5

我正在开发一个使用 Tomcat 7.0 作为应用程序服务器的基于 Java 的 Web 应用程序。在对先前问题的有用回复之后,我决定使用 bcrypt 将密码安全地存储在我的 HSQLDB 中。但是 Tomcat 的默认 Realm 实现不能处理 bcrypt,所以我需要自己编写;这是我编写自定义领域的唯一原因,尽管在所有其他方式中普通的 JDBCRealm 都可以工作。我一直在谷歌搜索并查看示例,但我对几点感到困惑。

首先,我应该扩展 RealmBase 还是 JDBCRealm?我发现的大多数示例都使用 RealmBase,但到目前为止,我已经成功地将 JDBCRealm 用于应用程序(因为它仍在开发中,我开始以明文形式存储密码并仅使用 JDBCRealm 来处理身份验证),以及一个答案Code Ranch 上的一个问题建议只是扩展它。不过,我不确定在这种情况下我需要重写哪些方法。只是身份验证方法,还是更多?如果这样做,JDBCRealm 是否仍然能够处理和管理用户角色、getPrincipal 等等?

其次,在上面链接的 CodeRanch 示例中,除非我遗漏了什么,否则 getPassword 方法似乎正在返回未加密的密码。因为我将使用 bcrypt,这是不可能的,而且无论如何这似乎是不可取的,我想。在此博客文章中的其他示例中,getPassword 似乎只是直接从数据库返回密码。那么哪种方式是正确的呢?我找不到 getPassword 的确切用途;文档没有说。是否可以为此返回存储在数据库中的加密值?

如果有人能告诉我应该扩展什么类,应该重写什么方法,以及 getPassword 应该返回什么,我将不胜感激。

4

1 回答 1

4

好吧,经过反复试验,我想出了如何做到这一点。我扩展了 JDBCRealm 并且只覆盖了 authenticate 方法,它工作得很好。我将BCrypt.java放在与我的自定义领域相同的目录中,这段代码有效:

import java.security.Principal;
import org.apache.catalina.realm.JDBCRealm;
public class BCryptRealm extends JDBCRealm
{
  @Override
  public Principal authenticate(String username, String credentials)
  {
    String hashedPassword = getPassword(username);
    // Added this check after discovering checkpw generates a null pointer
    // error if the hashedPassword is null, which happens when the user doesn't
    // exist. I'm assuming returning null immediately would be bad practice as
    // it would let an attacker know which users do and don't exist, so I added
    // a call to hashpw. No idea if that completely solves the problem, so if
    // your application has more stringent security needs this should be
    // investigated further.
    if (hashedPassword == null)
    {
      BCrypt.hashpw("fakePassword", BCrypt.gensalt());
      return null;
    }
    if (BCrypt.checkpw(credentials, hashedPassword))
    {
      return getPrincipal(username);
    }
    return null;
  }
}

于 2012-09-10T01:37:19.320 回答