【问题标题】:Reference - Password Validation参考 - 密码验证
【发布时间】:2018-06-28 23:30:10
【问题描述】:

很多时候,问题(尤其是那些标记为 的问题)询问验证密码的方法。用户似乎通常会寻求密码验证方法,包括确保密码包含特定字符、匹配特定模式和/或遵守最小字符数。这篇文章旨在帮助用户找到合适的密码验证方法,而不会大大降低安全性。

所以问题是:应该如何正确验证密码?

【问题讨论】:

    标签: regex regex validation authentication passwords


    【解决方案1】:

    为什么密码验证规则不好?

    我们自己的 Jeff Atwood(Coding Horror 的博主和 Stack Overflow 和 Stack Exchange 的联合创始人)在 2017 年 3 月写了一篇关于密码规​​则的博客,标题为 Password Rules are Bullshit。如果你还没有读过这篇文章,我会敦促你这样做,因为它极大地反映了这篇文章的意图。

    如果您从未听说过NIST (National Institute of Standards and Technology),那么您可能没有为您的项目使用正确的网络安全方法。在这种情况下,请查看他们的Digital Identity Guidelines。您还应该及时了解网络安全最佳实践。 NIST Special Publication 800-63B (Revision 3) 提到密码规则如下:

    验证者不应强加其他组合规则(例如,要求 不同字符类型的混合或连续禁止 重复字符)用于记忆的秘密。

    就连 Mozilla 关于 Form data validation 的文档也拿密码规则开玩笑 (page archive here):

    “您的密码长度必须介于 8 到 30 个字符之间,并且包含一个大写字母、一个符号和一个数字”(真的吗?)

    如果您对密码强加组合规则会发生什么?您限制潜在密码的数量并删除不符合您的规则的密码排列。这使黑客可以确保他们的攻击也是如此! “是的,但有千万亿(1,000,000,000,000,000 或 1x1015)密码排列”25-GPU cluster cracks every standard Windows password in <6 hours (958 = 6,634,204,312,890,625 ~ 6.6x1015 个密码)。

    This StackExchange Security post 扩展了上面的 XKCD 漫画。

    如何验证密码?

    1。不要创建自己的身份验证

    完全不再需要密码,让人们使用 Google、Facebook、Twitter、Yahoo 或任何其他您喜欢的有效形式的Internet driver's license 登录。最好的密码 是one you don't have to store

    来源:Your Password is Too Damn Short Jeff Atwood。

    2。创建您自己的身份验证

    如果您真的必须创建自己的身份验证方法,至少要遵循经过验证的网络安全方法。以下两节(2.1 和 2.2)取自current NIST publication5.1.1.2 Memorized Secret Verifiers 部分。

    2.1。遵循经过验证的网络安全方法

    NIST 声明您应该

    • 要求订阅者选择的记忆密码长度至少为 8 个字符。
      • Jeff Atwood 建议,普通用户的密码至少应为 10 个字符,而具有更高权限的用户(即管理员和版主)的密码应至少为 15 个字符。
    • 允许订阅者选择的记忆密码长度不超过 64 个字符。
      • 理想情况下,您甚至不应该为此设置上限。
    • 允许所有打印ASCII(包括空格字符)和Unicode。
      • 出于长度要求,每个 Unicode 代码点应计为单个字符。
    • 将预期机密与包含已知常用、预期或泄露的值的列表进行比较。例如:
      • 从以前的违规语料库中获得的密码。
      • 字典单词。
      • 重复或连续字符(例如aaaaaa1234abcd
      • 特定于上下文的词,例如服务名称、用户名及其派生词。
    • 为订阅者提供指导,例如密码强度计。
    • 实施一种速率限制机制,有效限制对订阅者帐户进行的失败身份验证尝试次数(请参阅Rate Limiting (Throttling))。
    • 如果有证据表明身份验证器遭到破坏,则强制进行更改。
    • 允许声明人在输入记忆密码时使用粘贴功能(便于使用密码管理器,这通常会增加用户选择更强记忆密码的可能性)。

    2.2.不要使用本节中的任何方法!

    同一出版物还声明您不应该

    • 截断秘密。
    • 允许订阅者存储一个 hint 可供未经身份验证的声明者访问。
    • 在选择记忆的秘密时提示订阅者使用特定类型的信息(例如“你的第一只宠物的名字是什么?”)。
    • 对记忆的秘密实施其他组合规则(例如,要求混合使用不同的字符类型或禁止连续重复的字符)。
    • 要求任意更改记忆的秘密(例如定期)。

    有很多网站解释如何创建“正确”密码验证表单:其中大部分已经过时,不应使用。

    3。使用密码熵

    在继续阅读本节之前,请注意本节的目的不是为您提供部署自己的安全方案所需的工具,而是为您提供有关的信息如何 当前的安全方法验证 密码。如果您正在考虑创建自己的安全方案,您应该三思而后行,并阅读 StackExchange 安全社区中的 this article

    3.1。密码熵概述

    在最基本的层面上,密码熵可以使用以下公式计算:

    上式中:

    • 代表密码熵
    • 是唯一字符中的字符数
    • 是密码中的字符数

    这意味着代表可能的密码数量;或者,就熵而言,用尽所有可能性所需的尝试次数。

    不幸的是,这个公式没有考虑以下内容:

    • 通用密码:即Password1admin
    • 名称:即JohnMary
    • 常用词:即英文theI
    • 反转/反转单词:即drowssap(密码向后)
    • 字母替换(又名 leet):即P@$$w0rd

    为这些额外的考虑添加逻辑是一个很大的挑战。有关可以添加到项目中的现有包,请参见 3.2。

    3.2.现有的密码熵项目

    在撰写本文时,用于估计密码强度的最知名的现有库是 zxcvbn by Dropbox(GitHub 上的一个开源项目)。它被改编为支持


    做错了

    不过,我理解每个人都有不同的要求,并且有时人们想以错误的方式做事。对于那些符合这个标准的人(或者没有选择并且已经向您的经理提供了本节以上的所有内容以及更多内容,但他们拒绝更新他们的方法)至少允许使用 Unicode 字符。当您将密码字符限制为一组特定字符(即确保存在小写 ASCII 字符a-z 或指定用户可以或不能输入的字符!@#$%^&amp;*())时,您只是在自找麻烦!

    附注永远不要相信客户端验证,因为它很容易被禁用。这意味着对于那些尝试使用 STOP 验证密码的人。请参阅JavaScript: client-side vs. server-side validation 了解更多信息。

    以下正则表达式模式不适用于所有编程语言,但它适用于许多主要编程语言 ()。请注意,以下正则表达式可能不适用于您的语言(甚至语言版本),您可能需要使用替代方法(即:请参阅Python regex matching Unicode properties)。一些编程语言甚至有更好的方法来检查这类事情(即使用Password Validation Plugin 代替)而不是重新发明轮子。如果使用XRegExp addonJavascript + Unicode regexes 中讨论的其他一些Unicode 类转换工具,则使用 以下是有效的。

    如果您需要阻止输入控制字符,您可以使用模式[^\P{C}\s] 在出现正则表达式匹配时提示用户。这只会匹配不是空白字符的控制字符 - 即水平制表符、换行符、垂直制表符。

    以下正则表达式确保至少一个小写字母、大写字母、数字和符号存在于 8+ 个字符长度的密码中:

    ^(?=\P{Ll}*\p{Ll})(?=\P{Lu}*\p{Lu})(?=\P{N}*\p{N})(?=[\p{L}\p{N}]*[^\p{L}\p{N}])[\s\S]{8,}$
    
    • ^ 在行首声明位置。
    • (?=\P{Ll}*\p{Ll}) 确保至少存在一个小写字母(在任何脚本中)。
    • (?=\P{Lu}*\p{Lu}) 确保至少存在一个大写字母(在任何脚本中)。
    • (?=\P{N}*\p{N}) 确保至少存在一个数字字符(在任何脚本中)。
    • (?=[\p{L}\p{N}]*[^\p{L}\p{N}]) 确保至少有一个不是字母或数字的字符(在任何脚本中)存在。
    • [\s\S]{8,} 匹配任意字符 8 次或更多次。
    • $ 在行尾断言位置。

    请自行决定使用上述正则表达式。您已被警告!

    【讨论】:

    • 我可以使用正则表达式 ^(?=\P{Ll}*\p{Ll})(?=\P{Lu}*\p{Lu})(?=\P{N }*\p{N})(?=[\p{L}\p{N}]*[^\p{L}\p{N}])[\s\S]{8,}$ in快捷的语言?我想使用大写、小写、数字和特殊字符组合来检查密码
    • @ChandanJee NSRegularExpression 确实允许 unicode 属性 \p{}\P{} 并且还允许前瞻 (?=),如 documentation 中所述。所以是的,这将在 Swift 中工作。但是,我建议您在后端实现这一点,因为可以绕过任何前端代码(当然,除非数据只存在于用户的设备上)。
    猜你喜欢
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    相关资源
    最近更新 更多