【问题标题】:How can I hash passwords in postgresql?如何在 postgresql 中散列密码?
【发布时间】:2011-02-08 11:35:14
【问题描述】:

我需要在 postgresql 上使用 salt 对一些密码进行哈希处理,但我无法找到任何有关如何完成此操作的相关文档。

那么如何在 postgresql 中散列密码(使用一些盐)?

【问题讨论】:

    标签: security postgresql hash cryptography salt


    【解决方案1】:

    应用程序应使用 bcrypt 或 pbkdf2 等密钥派生函数对其密码进行哈希处理。 Here is more information on secure password storage.

    ...但有时您仍然需要数据库中的加密函数。

    您可以使用pgcrypto 访问 sha256,它是 sha2 家族的成员。请记住 sha0、sha1 md4 和 md5 非常损坏,应该从不用于密码哈希。

    以下是哈希密码的好方法:

    digest("salt"||"password"||primary_key, "sha256")
    

    盐应该是一个随机生成的大值。这种盐应该受到保护,因为在恢复盐之前无法破坏散列。如果您将盐存储在数据库中,则可以使用 sql 注入将其与密码哈希一起获取。连接主键用于防止两个人拥有相同的密码哈希,即使他们拥有相同的密码。当然这个系统可以改进,但这比我见过的大多数系统要好得多。

    通常最好在应用程序访问数据库之前对其进行哈希处理。这是因为查询可以显示在日志中,如果数据库服务器是自己的,那么它们可以启用日志记录以获取明文密码。

    【讨论】:

    • 是的,我来晚了。删除了我的答案,因为你是第一个更详细的;)。
    • @T Duncan Smith 谢谢伙计,我给了你一些积分作为一个好的 SO 成员。
    • 嗯,日志记录问题是一个好点,我想,但出于实际原因,我希望能够运行 sql 语句来取消个性化密码(以及其他个人信息)发布清理后的数据库。
    • Err,你能澄清一下“盐应该是一个很大的随机生成值”的说法吗?我会通过传统的字符串连接方式添加随机值盐吗?是否:update account set pswhash = crypt('global salt' || 'new password' || 'user created date', gen_salt('sha256')) where account_id = 5 或类似的东西实际上对创建初始哈希有意义?还是我错过了 crypt() 函数的一些内容?
    • pgcrypto 页面上的文档非常好,并阐明了为什么这是一种非常愚蠢的哈希方法。事实上,灾难的秘诀。使用 crypt 函数,用 'bf' 哈希代替。查看更多信息,包括如何在 codahale.com/how-to-safely-store-a-password 上每秒使用数十亿个盐渍哈希进行自定义破解
    【解决方案2】:

    示例和文档:http://www.postgresql.org/docs/8.3/static/pgcrypto.html

    UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));
    
    SELECT pswhash = crypt('entered password', pswhash) FROM ... ;
    

    【讨论】:

    • 是的,pgcrypto 看起来像我正在寻找的东西,但我很难弄清楚它的用法,示例用法是说我不必将自己的盐硬编码到哈希? IE。我不再需要提供自己的盐数据,例如:update account set pswhash = crypt('global salt' || 'new password' || 'user created date', gen_salt('sha256')) where account_id = 5?还是加盐仍然是一个手动过程?
    • 使用 md5 算法,没有任何迭代计数(随着时间的推移适应散列速度的增加)是灾难的根源。相反,使用'bf':gen_salt('bf')。查看更多信息,包括如何在 codahale.com/how-to-safely-store-a-password 上每秒使用数十亿个盐渍哈希进行自定义破解
    • @Tchalvak 正确 - 您不再需要提供自己的盐数据。事实上,gen_salt 还对算法进行了编码,正如我上面提到的,它实际上应该是 'bf' - 请参阅参考资料了解更多信息。鉴于使用了“bf”,这个答案远远优于 rook 的答案。
    • 这是正确的答案。你不应该使用digest 函数来加密密码,它不够安全。只要确保您使用 Blowfish 算法而不是 MD5。
    【解决方案3】:

    我问这个问题已经有一段时间了,而且我现在对密码学理论更加熟悉,所以这里是更现代的方法:

    推理

    • 不要使用 md5。不要使用单个循环的 sha-family 快速哈希。快速哈希有助于攻击者,所以您不希望这样。
    • 改为使用资源密集型哈希,例如 bcrypt。 Bcrypt 已经过时间考验,并且可以扩展以适应未来。
    • 不要费心自己撒盐,您可能会搞砸自己的安全性或可移植性,请依靠 gen_salt() 自行生成令人敬畏的独特的每次使用的盐。
    • 一般来说,不要做白痴,不要尝试编写自己的本土加密货币,只需使用聪明人提供的内容即可。

    Debian/Ubuntu 安装包

    sudo apt-get install postgresql   // (of course)
    sudo apt-get install postgresql-contrib libpq-dev   // (gets bcrypt, crypt() and gen_salt())
    sudo apt-get install php5-pgsql   // (optional if you're using postgresql with php)
    

    在数据库中的 postgresql 中激活 crypt() 和 bcrypt

    // Create your database first, then:
    cd `pg_config --sharedir` // Move to the postgres directory that holds these scripts.
    echo "create extension pgcrypto" | psql -d yOuRdATaBaSeNaMe // enable the pgcrypo extension
    

    在查询中使用 crypt() 和 gen_salt()

    将 :pass 与现有哈希进行比较:

    select * from accounts where password_hash = crypt(:pass, password_hash);
    //(note how the existing hash is used as its own individualized salt)
    

    使用随机盐创建 :password 的哈希:

    insert into accounts (password) values crypt(:password, gen_salt('bf', 8));
    //(the 8 is the work factor)
    

    From-in-Php bcrypt 散列稍微可取

    在 php 5.5 及更高版本中有 password_* 函数允许使用 bcrypt 进行简单的密码散列(大约是时候了!),并且对于低于该版本的版本有一个向后兼容库。 通常散列会回退到包装 linux 系统调用以降低 CPU 使用率,尽管您可能希望确保它已安装在您的服务器上。请参阅:https://github.com/ircmaxell/password_compat(需要 php 5.3.7+)

    注意日志记录

    请注意,使用 pg_crypto,密码在从浏览器到 php 再到数据库的传输过程中都是纯文本的。这意味着如果您对数据库日志不小心,它们可以以纯文本形式从查询中记录下来。例如拥有 postgresql 慢查询日志可以从正在进行的登录查询中捕获并记录密码。

    总结

    如果可以,请使用 php bcrypt,它会减少密码保持未散列的时间。尝试确保您的 linux 系统在它的 crypt() 中安装了 bcrypt,这样它是高性能的。强烈建议至少升级到 php 5.3.7+,因为 php 的实现从 php 5.3.0 到 5.3.6.9 略有错误,并且在 php 5.2.9 及更低版本中不适当地回退到损坏的DES 而没有警告。

    如果您想要/需要 in-postgres 散列,安装 bcrypt 是可行的方法,因为默认安装的散列是旧的和损坏的(md5 等)。

    以下是有关该主题的更多阅读参考资料:

    【讨论】:

    • 那么,使用 pgcrypto 与在应用程序端进行散列比较好?一般来说,日常工作哈希、guid生成等应该由pg而不是app来完成吗?谢谢!
    • 我已经更详细地编辑了上面的答案。由于 pg_crypto 要求密码的明文命中数据库查询,当偶然的查询日志发生时可能会出现问题,如果可以的话,我建议这些天首先尝试使用 in-php password_hash()。 Bcrypt 是当前最先进的密码散列技术,因此它击败了其他选项,无论是在 postgresql 还是 php 中。 Bcrypt 散列在设计上是资源密集型的,因此如果您在 php 中使用它,请尝试从 crypt() 获取 bcrypt 以减少服务器的资源使用。
    • 不要使用 md5,它坏了,postgres 听到“使用 md5”,因为它是用来散列密码的......
    • 在阅读了这里的日志记录问题后,我有一个 GIANT 怪胎并重写了一堆代码。然后我意识到我正在使用参数化查询,这意味着我的数据库日志中没有明文内容。值得注意的是,当使用 pgp 加密时,我还需要将我的公钥/私钥字符串作为参数传递以避免记录
    • Postgres 11+ 具有scram-sha-256 密码方案(来自RFC 7677)。由于它使用了SCRAM,因此在某些情况下它可能是 PHP 的password_* 函数的替代品。
    猜你喜欢
    • 1970-01-01
    • 2020-07-18
    • 2016-11-01
    • 2011-05-10
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多