使用 MySQL 对用户进行身份验证的最佳方式(接受其他建议)?

Posted

技术标签:

【中文标题】使用 MySQL 对用户进行身份验证的最佳方式(接受其他建议)?【英文标题】:Best way to authenticate a user with MySQL (Open to other suggestions)? 【发布时间】:2011-11-02 13:12:48 【问题描述】:

我正在创建一个基于 Web 的登录系统,为此我使用 mysql 作为我的后端,并使用 JSPS 和 Servlet 来实现功能,还使用一个名为 jasypt 1.8 的库来加密密码,以便以后将它们存储在 MySQL 上。

我的问题是:以下代码有什么问题吗(安全相关、最佳实践等...):

 protected boolean verifyUser(String user, String pass) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException 

    StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();

    Connection conn = null;
    String userName = "****";
    String password = "****";
    String url = "jdbc:mysql://localhost:3306/DB";
    ResultSet rs = null;
    try 
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        conn = DriverManager.getConnection(url, userName, password);
        System.out.println("Database connection established");

        PreparedStatement stmt = null;

        stmt = conn.prepareStatement("SELECT * FROM DB.LOGINS WHERE USER = ?");
        stmt.setString(1, user);
        rs = stmt.executeQuery();
        if(!rs.next())
            return false;                
        

        if(passwordEncryptor.checkPassword(pass, rs.getString("Password")))
            return true;
        
        conn.close();
     catch (Exception e) 

    
    return false;

我不知道将用户从数据库中取出然后将其与提供的密码进行比较是否正确(即,我认为最好的方法是从数据库中取出信息)数据库使用用户名和密码,而不仅仅是前者)。不幸的是,我无法做到这一点,因为我无法生成密钥,因为库中没有能够做到这一点的方法(而且我无法在文档中找到生成密钥的算法)。

我这样做是因为我正在使用的库有一个内置的随机盐生成器,该生成器将自身存储在加密后创建的字符串中(如果重要,请使用 sha-256...)和方法checkPassword() 是唯一能够生成与存储在数据库中的密钥完全相同的密钥(已经通过加密过程)。

无论如何,如果您有任何创建登录系统的经验或知道很多安全最佳实践,如果您认为我的解决方案不合适,我希望您能告诉我您对此类问题的体验。

感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

Jasypt 正是让您可以轻松地进行这种密码检查,因此检查密码的代码是完全可以的。

我的主要评论是该方法中发生了两件事。

获取 sql 连接 在控制台上打印连接消息 获取用户 检查不为空 使用内部 StrongPasswordEncryptor 检查密码

这意味着在该方法中所有内容都几乎是硬编码的

为了做得更好,我会:

使用日志系统Log4j 在其他地方分离连接的配置(属性文件...) 最终使用连接池(这里是MySQL的一个例子 没有 enpty catch 块、抛出异常或至少记录它,这样你就知道发生了什么 另外,如果你想改变你的Jasypt options,你应该在这个方法之外做密码加密机制。

无论如何,只有几件事可以使它更加模块化。

现在在生产系统中,大多数人更喜欢使用像Apache Shiro 这样的框架,这样他们就可以轻松更改身份验证机制,也可以轻松配置角色和组。

瞧。希望这个答案能有所启发。

【讨论】:

很好的答案,在阅读本文之前我从没想过使用连接池,立即实施,而且我肯定会让这个更加模块化,这只是我为自己制作的概念证明,所以我可以得到一些需要重做的反馈,再问一个问题:当你说我需要将连接的配置分离到一个属性文件中时,你是指为此使用一个新类?或者使用某种文本文件来读取数据?再次感谢您的反馈。 除了上述很好的建议外,我建议您在查询中仅选择密码字段,因为它是您唯一使用的。然后,您可以避免传输未使用的数据并降低带宽使用率。 @user815922 是的,一个文本文件。 Jasypt 有几个externalizing configuration and reading it 的例子。【参考方案2】:

考虑到用户名在系统中是唯一的,您的读取用户信息和比较密码哈希的解决方案是可以的,并且是广泛使用的解决方案。只要整个处理在服务器端完成,不涉及安全风险。

但是,如果你想在实际应用中使用这样的代码,你不应该每次都创建连接,而是考虑使用连接池,例如 apache commons dbcp,这样可以额外简化开发;)

【讨论】:

【参考方案3】:

还使用名为 jasypt 1.8 的库来加密密码

不得加密密码。您应该单向散列它们,并比较散列。您不得提供任何可以合法解释为让其他人知道用户密码的方式。否则,您将失去交易的法律不可否认性,这严重到足以让您破产。你需要接受法律咨询,这真的很严重。

【讨论】:

对不起,我想我误解了加密的概念,Jasypt 的库实际上做的是每个密码的单向哈希(SHA-256 方法的大约 5000 次迭代),然后它是存储在 MySQL 数据库中,之后方法 checkPassword() (也来自 Jasypt 的库)检查存储在已经单向散列密码中的盐并生成密码并将其与数据库中的密码进行比较以检查它们是否平等,如果我做错了,请告诉我。

以上是关于使用 MySQL 对用户进行身份验证的最佳方式(接受其他建议)?的主要内容,如果未能解决你的问题,请参考以下文章

实施 SSO 的最佳方式是啥?

无需对移动应用进行用户身份验证即可保护私有 REST API 的最佳方法

Rails API:实现身份验证的最佳方式?

使用 JWT 进行身份验证的最佳实践

存储 oauth 和本地身份验证方法的最佳实践?

API测试最佳实践 - 身份验证