提问人: 提问时间:8/3/2008 最后编辑:37 revs, 21 users 25%Michiel de Mare 更新时间:4/27/2022 访问量:679067
基于表单的网站身份验证权威指南 [已关闭]
The definitive guide to form-based website authentication [closed]
问:
主持人注:
这个问题不适合我们的问答格式,目前适用于 Stack Overflow 的话题性规则。对于内容仍然有价值的问题,我们通常使用“历史锁”。但是,此问题的答案是积极维护的,并且历史锁不允许编辑答案。因此,应用了“wiki 答案”锁以允许编辑答案。您应该假设通常由历史锁处理的话题性问题存在(即,这个问题不是 Stack Overflow 的主题问题的一个很好的例子)。
网站的基于表单的身份验证
我们认为,Stack Overflow 不仅应该成为非常具体的技术问题的资源,还应该提供有关如何解决常见问题变体的一般指南。“基于表单的网站身份验证”应该是此类实验的一个很好的主题。
它应该包括以下主题:
- 如何登录
- 如何注销
- 如何保持登录状态
- 管理Cookie(包括推荐的设置)
- SSL/HTTPS加密
- 如何存储密码
- 使用秘密问题
- 忘记用户名/密码功能
- 使用随机数防止跨站点请求伪造 (CSRF)
- OpenID
- “记住我”复选框
- 浏览器自动完成用户名和密码
- 机密 URL(受摘要保护的公共 URL)
- 检查密码强度
- 电子邮件验证
- 还有更多关于基于表单的身份验证的信息...
它不应包括以下内容:
- 角色和授权
- HTTP 基本身份验证
请通过以下方式帮助我们:
- 建议副主题
- 提交关于这个主题的好文章
- 编辑官方答案
答:
权威文章
发送凭据
100% 安全地发送凭据的唯一实用方法是使用 SSL。使用 JavaScript 对密码进行哈希处理是不安全的。客户端密码哈希的常见陷阱:
- 如果客户端和服务器之间的连接未加密,则您所做的一切都容易受到中间人攻击。攻击者可以替换传入的 javascript 以破坏哈希或将所有凭据发送到他们的服务器,他们可以监听客户端响应并完美地模拟用户等。 具有受信任证书颁发机构的 SSL 旨在防止 MitM 攻击。
- 如果不在服务器上执行额外的冗余工作,则服务器接收的哈希密码的安全性较低。
还有另一种称为 SRP 的安全方法,但它已获得专利(尽管它是免费许可的),并且很少有好的实现可用。
存储密码
切勿将密码以明文形式存储在数据库中。即使您不关心自己网站的安全性,也不会。假设您的某些用户将重复使用其网上银行帐户的密码。因此,请存储经过哈希处理的密码,并丢弃原始密码。并确保密码不会显示在访问日志或应用程序日志中。OWASP建议使用Argon2作为新应用的首选。如果不可用,则应改用 PBKDF2 或 scrypt。最后,如果以上都不可用,请使用 bcrypt。
哈希值本身也是不安全的。例如,相同的密码意味着相同的哈希值 - 这使得哈希查找表成为一次破解大量密码的有效方法。相反,请存储加盐的哈希。盐是在哈希之前附加到密码的字符串 - 每个用户使用不同的(随机)盐。盐是一个公共值,因此您可以将它们与哈希一起存储在数据库中。有关更多信息,请参阅此处。
这意味着您无法向用户发送他们忘记的密码(因为您只有哈希值)。除非您已对用户进行身份验证,否则不要重置用户的密码(用户必须证明他们能够阅读发送到存储(和验证)电子邮件地址的电子邮件。
安全问题
安全问题是不安全的 - 避免使用它们。为什么?安全问题所做的任何事情,密码都做得更好。阅读第三部分:在本 wiki 中@Jens Roland 中使用秘密问题答案。
会话 Cookie
用户登录后,服务器会向用户发送会话 cookie。服务器可以从 cookie 中检索用户名或 id,但其他任何人都无法生成此类 cookie(TODO 解释机制)。
Cookie 可以被劫持:它们的安全性取决于客户端机器的其余部分和其他通信。它们可以从磁盘读取,在网络流量中嗅探,通过跨站点脚本攻击解除,从中毒的DNS中钓鱼,因此客户端将其cookie发送到错误的服务器。不要发送持久性 Cookie。Cookie 应在客户端会话结束时过期(浏览器关闭或离开您的域)。
如果要自动登录用户,可以设置持久性 Cookie,但它应与完整会话 Cookie 区分开来。您可以设置一个附加标志,表示用户已自动登录,并且需要真实登录才能进行敏感操作。这在希望为您提供无缝、个性化购物体验但仍能保护您的财务详细信息的购物网站中很受欢迎。例如,当您返回访问亚马逊时,他们会向您显示一个看起来像您已登录的页面,但是当您下订单(或更改您的送货地址、信用卡等)时,他们会要求您确认密码。
另一方面,银行和信用卡等金融网站只有敏感数据,不应允许自动登录或低安全模式。
外部资源列表
- Web 上客户端身份验证的注意事项 (PDF)
21 页的学术文章,其中包含许多重要提示。 - 询问 YC:用户身份验证
论坛关于该主题的最佳实践讨论 - 您可能错误地
存储了密码 关于存储密码的介绍性文章 - 讨论:编码恐怖:您可能不正确地存储密码
关于编码恐怖文章的论坛讨论。 - 永远不要将密码存储在数据库中!
另一个关于在数据库中存储密码的警告。 - 密码破解
维基百科上关于几种密码哈希方案弱点的文章。 - Enough with The Rainbow Tables: What You Need To Know About Secure Password Schemes
讨论彩虹表以及如何防御彩虹表和其他线程。包括广泛的讨论。
评论
第一部分:如何登录
我们假设您已经知道如何构建登录名+密码 HTML 表单,该表单将值 POST 到服务器端的脚本进行身份验证。以下各节将讨论健全实用身份验证的模式,以及如何避免最常见的安全陷阱。
到HTTPS还是不到HTTPS?
除非连接已经是安全的(即,使用 SSL/TLS 通过 HTTPS 建立隧道),否则您的登录表单值将以明文形式发送,这允许任何窃听浏览器和 Web 服务器之间线路的人能够在登录信息通过时读取登录信息。这种类型的窃听通常由政府完成,但一般来说,我们不会解决“拥有”的电线,只是说:只需使用 HTTPS。
从本质上讲,在登录期间防止窃听/数据包嗅探的唯一实用方法是使用HTTPS或其他基于证书的加密方案(例如,TLS)或经过验证和测试的质询-响应方案(例如,基于Diffie-Hellman的SRP)。任何其他方法都可以很容易地被窃听攻击者规避。
当然,如果你愿意有点不切实际,你也可以采用某种形式的双因素身份验证方案(例如谷歌身份验证器应用程序、物理“冷战风格”密码本或RSA密钥生成器加密狗)。如果应用得当,即使使用不安全的连接,也可以使用,但很难想象开发人员愿意实现双因素身份验证而不是 SSL。
(不要)滚动您自己的 JavaScript 加密/哈希
鉴于在您的网站上设置SSL证书的成本和技术难度(尽管现在是可以避免的),一些开发人员倾向于推出自己的浏览器内哈希或加密方案,以避免通过不安全的网络传递明文登录。
虽然这是一个崇高的想法,但它基本上是无用的(并且可能是一个安全漏洞),除非它与上述之一相结合——也就是说,要么使用强大的加密来保护线路,要么使用久经考验的挑战-响应机制(如果你不知道那是什么,只要知道它是最难证明的机制之一, 在数字安全中,最难设计,也最难实现的概念)。
虽然对密码进行哈希处理确实可以有效防止密码泄露,但它容易受到重放攻击、中间人攻击/劫持(如果攻击者可以在不安全的 HTML 页面到达您的浏览器之前将其注入几个字节,他们可以简单地注释掉 JavaScript 中的哈希)或暴力攻击(因为您同时向攻击者提供用户名, 盐和散列密码)。
反人类验证码
CAPTCHA 旨在阻止一种特定类别的攻击:无需人工操作员的自动字典/暴力试错。毫无疑问,这是一个真正的威胁,但是,有一些方法可以无缝地处理它,不需要验证码,专门设计的服务器端登录限制方案 - 我们将在后面讨论这些。
要知道,CAPTCHA 实现的创建方式并不相同;它们通常不是人类可以解决的,它们中的大多数实际上对机器人无效,所有这些都对廉价的第三世界劳动力无效(根据 OWASP,目前的血汗工厂费率为每 500 次测试 12 美元),并且某些实现在某些国家/地区可能在技术上是非法的(参见 OWASP 身份验证备忘单)。如果您必须使用验证码,请使用 Google 的 reCAPTCHA,因为它根据定义是 OCR 硬的(因为它使用已经 OCR 错误分类的书籍扫描),并且非常努力地做到用户友好。
就我个人而言,我倾向于觉得验证码很烦人,并且只有在用户多次登录失败并且限制延迟达到最大时才将它们用作最后的手段。这种情况很少发生,以至于无法接受,它加强了整个系统。
存储密码/验证登录
在我们近年来看到的所有广为人知的黑客攻击和用户数据泄露之后,这可能最终成为常识,但不得不说:不要将密码以明文形式存储在数据库中。用户数据库经常被黑客入侵、泄露或通过SQL注入收集,如果您存储的是原始的纯文本密码,那么对于您的登录安全性来说,这将立即结束游戏。
那么,如果您无法存储密码,如何检查登录表单中的登录名+密码组合 POST 是否正确?答案是使用密钥派生函数进行哈希处理。每当创建新用户或更改密码时,您都会获取密码并通过 KDF(例如 Argon2、bcrypt、scrypt 或 PBKDF2)运行它,将明文密码(“correcthorsebatterystaple”)转换为一个长而随机的字符串,存储在数据库中要安全得多。要验证登录,请对输入的密码运行相同的哈希函数,这次传入盐并将生成的哈希字符串与数据库中存储的值进行比较。Argon2、bcrypt 和 scrypt 已经存储了带有哈希值的盐。查看sec.stackexchange上的这篇文章,了解更多详细信息。
使用盐的原因是哈希本身是不够的 - 您需要添加所谓的“盐”来保护哈希免受彩虹表的影响。盐可以有效地防止将完全匹配的两个密码存储为相同的哈希值,从而防止在攻击者执行密码猜测攻击时在一次运行中扫描整个数据库。
不应将加密哈希用于密码存储,因为用户选择的密码不够强(即通常不包含足够的熵),并且有权访问哈希的攻击者可能会在相对较短的时间内完成密码猜测攻击。这就是使用 KDF 的原因 - 这些有效地“拉伸密钥”,这意味着攻击者所做的每个密码猜测都会导致哈希算法多次重复,例如 10,000 次,这会导致攻击者猜测密码的速度慢 10,000 倍。
会话数据 - “您以 Spiderman69 身份登录”
一旦服务器根据您的用户数据库验证了登录名和密码并找到匹配项,系统就需要一种方法来记住浏览器已经过身份验证。这一事实应仅存储在服务器端的会话数据中。
如果您不熟悉会话数据,以下是它的工作原理:单个随机生成的字符串存储在即将过期的 cookie 中,用于引用存储在服务器上的数据集合(会话数据)。如果您使用的是 MVC 框架,这无疑已经处理好了。
如果可能,请确保会话 cookie 在发送到浏览器时设置了 secure 和 HTTP Only 标志。HttpOnly 标志提供一些保护,防止通过 XSS 攻击读取 cookie。安全标志确保 cookie 仅通过 HTTPS 发回,从而防止网络嗅探攻击。Cookie 的值不应是可预测的。如果出现引用不存在的会话的 cookie,则应立即替换其值以防止会话固定。
会话状态也可以在客户端维护。这是通过使用 JWT(JSON Web 令牌)等技术实现的。
第二部分:如何保持登录状态 - 臭名昭著的“记住我”复选框
持久性登录 Cookie(“记住我”功能)是一个危险区域;一方面,当用户了解如何处理它们时,它们与传统登录一样安全;另一方面,粗心的用户可能会遇到巨大的安全风险,他们可能会在公共计算机上使用它们而忘记注销,并且可能不知道什么是浏览器cookie或如何删除它们。
就我个人而言,我喜欢定期访问的网站的持续登录,但我知道如何安全地处理它们。如果您确信您的用户也知道这一点,则可以问心无愧地使用持久登录。如果不是 - 好吧,那么您可能会认同这样一种理念,即如果用户被黑客入侵,那么对登录凭据粗心大意的用户就会自己带来这种想法。这也不是说我们去用户家里撕掉所有那些带有密码的便利贴,这些便利贴是他们在显示器边缘排成一排的密码。
当然,有些系统无法承受任何帐户被黑客入侵的后果;对于此类系统,您无法证明持久登录的合理性。
如果您决定实施持久性登录 Cookie,请按以下步骤操作:
首先,花一些时间阅读 Paragon Initiative 关于该主题的文章。你需要把一堆元素弄对,这篇文章很好地解释了每个元素。
重申一个最常见的陷阱,不要将持久登录 COOKIE(令牌)存储在您的数据库中,而只是它的哈希值!登录令牌是等效的密码,因此,如果攻击者掌握了您的数据库,他们可以使用令牌登录任何帐户,就像它们是明文登录密码组合一样。因此,在存储持久性登录令牌时,请使用哈希(根据 https://security.stackexchange.com/a/63438/5002 弱哈希可以很好地实现此目的)。
第三部分:使用秘密问题
不要实施“秘密问题”。“秘密问题”功能是一种安全反模式。阅读必读列表中的第 4 个链接中的论文。你可以问莎拉·佩林(Sarah Palin),在她的雅虎电子邮件帐户在之前的总统竞选期间被黑客入侵后,因为她的安全问题的答案是......“瓦西拉高中”!
即使有用户指定的问题,大多数用户也很可能会选择:
一个“标准”的秘密问题,比如母亲的婚前姓氏或最喜欢的宠物
任何人都可以从他们的博客、LinkedIn 个人资料或类似内容中提取的简单琐事
任何比猜测密码更容易回答的问题。对于任何像样的密码,这是您能想象到的每一个问题
总之,安全问题在几乎所有形式和变体中本质上都是不安全的,无论出于何种原因,都不应在身份验证方案中使用。
安全问题甚至存在于野外的真正原因是,它们可以方便地节省一些无法访问其电子邮件以获取重新激活代码的用户拨打支持电话的成本。这是以牺牲安全和莎拉·佩林的声誉为代价的。值得吗?可能不是。
第四部分:忘记密码功能
我已经提到过为什么您永远不应该使用安全问题来处理忘记/丢失的用户密码;不言而喻,您永远不应该通过电子邮件向用户发送他们的实际密码。在这个领域,至少还有两个非常常见的陷阱需要避免:
不要将忘记的密码重置为自动生成的强密码 - 众所周知,此类密码很难记住,这意味着用户必须更改或写下来 - 例如,在显示器边缘的亮黄色便利贴上。与其设置新密码,不如让用户立即选择一个新密码 - 无论如何,这就是他们想要做的。(一个例外情况可能是,如果用户普遍使用密码管理器来存储/管理密码,如果不写下密码,通常无法记住这些密码)。
始终对数据库中丢失的密码代码/令牌进行哈希处理。同样,此代码是密码等效的另一个示例,因此必须对其进行哈希处理,以防攻击者获得您的数据库。当请求丢失密码代码时,将明文代码发送到用户的电子邮件地址,然后对其进行哈希处理,将哈希保存在数据库中,然后丢弃原始代码。就像密码或永久登录令牌一样。
最后一点:始终确保输入“丢失密码”的界面至少与登录表单本身一样安全,否则攻击者只会使用它来获取访问权限。确保生成很长的“丢失密码代码”(例如,16 个区分大小写的字母数字字符)是一个好的开始,但请考虑添加与登录表单本身相同的限制方案。
第五部分:检查密码强度
首先,您需要阅读这篇小文章以进行现实检查: 500 个最常见的密码
好的,所以也许这个列表不是任何地方任何系统上最常见的密码的规范列表,但它很好地表明,当没有强制执行的策略时,人们会选择密码。此外,当您将其与最近被盗密码的公开分析进行比较时,该列表看起来非常接近家庭。
因此:由于没有最低密码强度要求,2% 的用户使用前 20 个最常见的密码之一。这意味着:如果攻击者只有 20 次尝试,那么您网站上每 50 个帐户中就有 1 个是可破解的。
要阻止这种情况,需要计算密码的熵,然后应用阈值。美国国家标准与技术研究院 (NIST) 特别出版物 800-63 提出了一系列非常好的建议。当与字典和键盘布局分析相结合时(例如,“qwertyuiop”是一个错误的密码),可以在 18 位熵的水平上拒绝 99% 的所有选择不当的密码。简单地计算密码强度并向用户显示视觉强度计是好的,但还不够。除非强制执行,否则很多用户很可能会忽略它。
为了对高熵密码的用户友好性进行令人耳目一新的理解,强烈推荐 Randall Munroe 的密码强度 xkcd。
利用 Troy Hunt 的 Have I Been Pwned API 检查用户密码与在公共数据泄露中泄露的密码。
第六部分:更多 - 或者:防止快速登录尝试
首先,看一下数字: 密码恢复速度 - 您的密码将保留多长时间
如果您没有时间浏览该链接中的表格,以下是它们的列表:
破解弱密码几乎不需要时间,即使您用算盘破解它
如果字母数字 9 个字符的密码不区分大小写,则几乎不需要任何时间即可破解
如果长度少于 8 个字符,则几乎不需要任何时间即可破解复杂的符号、字母和数字、大小写密码(台式 PC 可以在几天甚至几小时内搜索多达 7 个字符的整个密钥空间)
但是,如果您被限制为每秒一次尝试,那么即使是 6 个字符的密码也需要花费过多的时间!
那么我们可以从这些数字中学到什么呢?嗯,很多,但我们可以专注于最重要的部分:事实上,防止大量快速连续登录尝试(即暴力攻击)真的不是那么困难。但正确预防它并不像看起来那么容易。
一般来说,您有三种选择,它们都对暴力攻击(和字典攻击)有效,但由于您已经采用了强密码策略,因此它们应该不是问题):
在 N 次尝试失败后出示验证码(这很烦人,而且经常无效——但我在这里重复一遍)
在 N 次尝试失败后锁定帐户并要求电子邮件验证(这是等待发生的 DoS 攻击)
最后,登录限制:即在 N 次尝试失败后设置尝试之间的时间延迟(是的,DoS 攻击仍然是可能的,但至少它们的可能性要小得多,而且实施起来要复杂得多)。
最佳实践 #1:随着尝试失败次数的增加而增加的短时间延迟,例如:
- 1 次尝试失败 = 无延迟
- 2 次失败尝试 = 2 秒延迟
- 3 次失败尝试 = 4 秒延迟
- 4 次失败尝试 = 8 秒延迟
- 5 次失败尝试 = 16 秒延迟
- 等。
DoS 攻击此方案将非常不切实际,因为生成的锁定时间略大于先前锁定时间的总和。
澄清一下:延迟不是将响应返回给浏览器之前的延迟。它更像是一个超时或不应期,在此期间,根本不会接受或评估对特定帐户或特定 IP 地址的登录尝试。也就是说,正确的凭据不会在成功登录时返回,不正确的凭据不会触发延迟增加。
最佳实践 #2:在 N 次尝试失败后生效的中等长度时间延迟,例如:
- 1-4 次失败的尝试 = 无延迟
- 5 次失败尝试 = 15-30 分钟延迟
DoS 攻击这个方案是相当不切实际的,但肯定是可行的。此外,需要注意的是,对于合法用户来说,如此长的延迟可能非常烦人。健忘的用户会不喜欢你。
最佳实践 #3:结合这两种方法 - 要么是固定的、短时间的延迟,在 N 次尝试失败后生效,例如:
- 1-4 次失败的尝试 = 无延迟
- 5+ 次失败尝试 = 20 秒延迟
或者,具有固定上限的递增延迟,例如:
- 1 次失败尝试 = 5 秒延迟
- 2 次失败尝试 = 15 秒延迟
- 3+ 次失败尝试 = 45 秒延迟
这个最终方案取自OWASP最佳实践建议(必读列表中的链接1),应该被视为最佳实践,即使它被公认为是限制性的。
然而,根据经验,我会说:你的密码策略越强大,你就越少用延迟来打扰用户。如果需要强(区分大小写的字母数字 + 所需的数字和符号)9+ 字符密码,则可以在激活限制之前为用户提供 2-4 次非延迟密码尝试。
DoS 攻击这种最终的登录限制方案是非常不切实际的。最后,始终允许持久性(cookie)登录(和/或经过验证码验证的登录表单)通过,因此合法用户在攻击过程中甚至不会被延迟。这样一来,非常不切实际的 DoS 攻击就变成了非常不切实际的攻击。
此外,对管理员帐户进行更积极的限制是有意义的,因为这些帐户是最有吸引力的入口点
第七部分:分布式暴力攻击
顺便说一句,更高级的攻击者会试图通过“传播他们的活动”来规避登录限制:
在僵尸网络上分发尝试以防止 IP 地址标记
他们不会选择一个用户并尝试 50.000 个最常见的密码(由于我们的限制,他们不能),而是选择最常见的密码并针对 50.000 个用户进行尝试。这样一来,他们不仅可以绕过验证码和登录限制等最大尝试次数,而且成功的机会也会增加,因为最常见的密码 1 比数字 49.995 的可能性要大得多
将每个用户帐户的登录请求间隔开来,例如,间隔 30 秒,以潜入雷达
在这里,最佳做法是记录系统范围内的失败登录次数,并使用站点错误登录频率的运行平均值作为上限的基础,然后对所有用户施加上限。
太抽象了?让我改写一下:
假设您的网站在过去 3 个月内平均每天有 120 次错误登录。使用该值(运行平均值),您的系统可能会将全局限制设置为该限制的 3 倍,即。24 小时内有 360 次尝试失败。然后,如果所有帐户的失败尝试总数在一天内超过该数字(或者更好的是,监控加速率并在计算出的阈值上触发),它将激活系统范围的登录限制 - 这意味着所有用户的短暂延迟(仍然,cookie登录和/或备份验证码登录除外)。
我还发布了一个问题,其中包含更多详细信息,并很好地讨论了如何在抵御分布式暴力攻击时避免棘手的陷阱
第八部分:双因素身份验证和身份验证提供程序
无论是漏洞利用、密码被写下并丢失、带有密钥的笔记本电脑被盗,还是用户登录网络钓鱼网站,凭据都可能被泄露。可以使用双因素身份验证进一步保护登录,该身份验证使用带外因素,例如从电话呼叫、短信、应用程序或加密狗收到的一次性代码。一些提供商提供双因素身份验证服务。
身份验证可以完全委托给单点登录服务,由另一个提供程序处理凭据收集。这会将问题推给受信任的第三方。Google 和 Twitter 都提供基于标准的 SSO 服务,而 Facebook 则提供类似的专有解决方案。
必读链接 关于 Web 身份验证
- OWASP 身份验证指南 / OWASP 身份验证备忘单
- Web 上客户端身份验证的注意事项(非常可读的麻省理工学院研究论文)
- 维基百科: HTTP cookie
- 后备身份验证的个人知识问题:Facebook时代的安全问题(非常可读的伯克利研究论文)
评论
SELECT * FROM LoginTokens WHERE UserID=[userid from cookie] AND HashedToken=[hash(token from cookie)]
首先,需要特别注意的是,这个答案并不适合这个确切的问题。这绝对不应该是最高答案!
我将继续提到Mozilla提出的BrowserID(或者更准确地说,是验证电子邮件协议),以寻找未来更好的身份验证方法的升级路径。
我是这样总结的:
- Mozilla是一个非营利性组织,其价值观与寻找解决这个问题的良好解决方案非常吻合。
- 今天的现实情况是,大多数网站都使用基于表单的身份验证
- 基于表单的身份验证有一个很大的缺点,即增加了网络钓鱼的风险。用户被要求将敏感信息输入到由远程实体控制的区域,而不是由其用户代理(浏览器)控制的区域。
- 由于浏览器是隐式信任的(用户代理的整个想法是代表用户行事),它们可以帮助改善这种情况。
- 阻碍进展的主要力量是部署僵局。解决方案必须分解为步骤,这些步骤本身可以提供一些增量收益。
- 表达互联网基础设施中内置身份的最简单的去中心化方法是域名。
- 作为表达身份的第二级,每个域管理自己的一组帐户。
- “accountdomain”形式简明扼要,并受到各种协议和 URI 方案的支持。当然,这种标识符最普遍地被认可为电子邮件地址。
@
- 电子邮件提供商已经是事实上的在线主要身份提供商。当前的密码重置流程通常允许您控制某个帐户,前提是您可以证明您控制了该帐户的关联电子邮件地址。
- 验证电子邮件协议旨在提供一种基于公钥加密的安全方法,以简化向域 B 证明您在域 A 上拥有帐户的过程。
- 对于不支持验证电子邮件协议的浏览器(目前所有浏览器),Mozilla提供了一个填充程序,用于在客户端JavaScript代码中实现该协议。
- 对于不支持“已验证电子邮件协议”的电子邮件服务,该协议允许第三方充当受信任的中介,声称他们已验证用户对帐户的所有权。拥有大量此类第三方是不可取的;此功能仅用于允许升级路径,并且最好电子邮件服务本身提供这些断言。
- Mozilla提供自己的服务,就像这样一个受信任的第三方一样。实施验证电子邮件协议的服务提供商(即依赖方)可以选择是否信任 Mozilla 的断言。Mozilla的服务使用发送带有确认链接的电子邮件的传统方式来验证用户的帐户所有权。
- 当然,服务提供商除了他们可能希望提供的任何其他身份验证方法外,还可以将此协议作为一种选项。
- 这里寻求的一大用户界面优势是“身份选择器”。当用户访问网站并选择进行身份验证时,他们的浏览器会向他们显示一系列电子邮件地址(“个人”、“工作”、“政治活动”等),这些电子邮件地址可用于向网站表明自己的身份。
- 作为这项工作的一部分,正在寻求的另一个重要的用户界面优势是帮助浏览器更多地了解用户的会话 - 他们当前主要以谁的身份登录 - 因此它可以在浏览器镶边中显示它。
- 由于该系统的分布式性质,它避免了对 Facebook、Twitter、Google 等主要网站的锁定。任何个人都可以拥有自己的域,因此可以充当自己的身份提供商。
这并不是严格意义上的“基于表单的网站身份验证”。但是,这是从当前基于表单的身份验证规范过渡到更安全的规范的努力:浏览器支持的身份验证。
评论
我不认为上面的答案是“错误的”,但有很大一部分身份验证领域没有被触及(或者更确切地说,重点是“如何实现cookie会话”,而不是“哪些选项可用以及权衡什么”。
我建议的编辑/答案是
- 问题更多地在于帐户设置,而不是密码检查。
- 使用双因素身份验证比更聪明的密码加密方法安全得多
不要尝试实现自己的登录表单或密码数据库存储,除非 存储的数据在创建帐户和自行生成时毫无价值(即 Web 2.0 风格,如 Facebook、Flickr 等)
- 摘要式身份验证是所有主要浏览器和服务器都支持的基于标准的方法,即使通过安全通道也不会发送密码。
这避免了任何需要“会话”或 cookie,因为浏览器本身每次都会重新加密通信。这是最“轻量级”的开发方法。
但是,我不建议这样做,除了公共的低价值服务。这是上面其他一些答案的问题 - 不要尝试重新实现服务器端身份验证机制 - 这个问题已经解决,并且大多数主流浏览器都支持。不要使用cookies。不要在自己的手动数据库中存储任何内容。只需询问每个请求是否通过身份验证即可。其他所有内容都应由配置和第三方受信任的软件支持。
所以。。。
首先,我们将初始创建帐户(使用密码)与随后重新检查密码混淆了。如果我是 Flickr 并且是第一次创建您的网站,则新用户可以访问零值(空白网络空间)。我真的不在乎创建帐户的人是否在谎报他们的名字。如果我正在创建医院内联网/外联网的帐户,则价值在于所有医疗记录,因此我确实关心帐户创建者的身份 (*)。
这是非常非常困难的部分。唯一体面的解决方案是信任网络。例如,您以医生的身份加入医院。你用你的照片、护照号码和公钥在某个地方创建一个网页,然后用私钥对它们进行哈希处理。然后,您访问医院,系统管理员查看您的护照,查看照片是否与您匹配,然后使用医院私钥对网页/照片哈希进行哈希处理。从现在开始,我们可以安全地交换密钥和令牌。任何信任医院的人都可以(顺便说一句,有秘诀)。系统管理员还可以为您提供 RSA 加密狗或其他双因素身份验证。
但这很麻烦,而且不是很 web 2.0。但是,这是创建新帐户的唯一安全方法,这些帐户可以访问非自行创建的有价值信息。
Kerberos 和 SPNEGO - 与受信任的第三方的单点登录机制 - 基本上用户根据受信任的第三方进行验证。(注意,这绝不是不可信的 OAuth)
SRP - 一种没有受信任的第三方的智能密码身份验证。但在这里,我们进入了“使用双因素身份验证更安全,即使成本更高”的领域
SSL 客户端 - 为客户端提供公钥证书(在所有主要浏览器中都支持,但会引发对客户端计算机安全性的问题)。
归根结底,这是一个权衡 - 安全漏洞的成本与实施更安全方法的成本是多少。有一天,我们可能会看到一个适当的PKI被广泛接受,因此不再拥有滚动的身份验证表单和数据库。有一天。。。
评论
哈希时,不要使用 MD5 等快速哈希算法(存在许多硬件实现)。使用类似 SHA-512 的东西。对于密码,哈希越慢越好。
创建哈希的速度越快,任何暴力检查器的工作速度就越快。因此,较慢的哈希值会减慢暴力破解的速度。缓慢的哈希算法将使暴力破解对于较长的密码(8 位 +)不切实际
评论
我只是想分享这个我发现工作得很好的解决方案。
我称它为假人场(虽然我没有发明这个,所以不要相信我)。其他人则将其称为蜜罐。
简而言之:您只需要将其插入到您的中,并在验证时检查它是否为空:<form>
<input type="text" name="email" style="display:none" />
诀窍是欺骗机器人,让它认为它必须将数据插入到必填字段中,这就是我将输入命名为“电子邮件”的原因。如果您已经使用了一个名为“电子邮件”的字段,则应尝试将虚拟字段命名为其他名称,例如“公司”、“电话”或“电子邮件地址”。只需选择一些您知道您不需要的东西,以及人们通常会认为合乎逻辑的东西来填写到 Web 表单中。现在使用 CSS 或 JavaScript/jQuery 隐藏字段 - 任何最适合你的 - 只是不要将输入设置为,否则机器人不会上当。input
type
hidden
当您验证表单(客户端或服务器端)时,请检查您的虚拟字段是否已填写,以确定它是由人类还是机器人发送的。
例:
如果是人类:用户不会看到虚拟字段(在我的情况下名为“电子邮件”),也不会尝试填充它。因此,发送表单时,虚拟字段的值仍应为空。
如果是机器人:机器人将看到一个字段,其类型为和名称(或您称之为的任何字段),并将在逻辑上尝试使用适当的数据填充它。它不在乎你是否用一些花哨的CSS来设置输入表单的样式,Web开发人员一直在这样做。无论虚拟字段中的值是什么,只要它大于字符,我们就不在乎。text
email
0
我在留言簿上将这种方法与 CAPTCHA 结合使用,从那以后我再也没有看到任何垃圾邮件帖子。我以前使用过仅验证码的解决方案,但最终,它导致每小时大约有五个垃圾邮件帖子。在表单中添加虚拟字段已阻止(至少到目前为止)所有垃圾邮件的出现。
我相信这也可以很好地用于登录/身份验证表单。
警告:当然,这种方法不是 100% 万无一失的。可以对机器人进行编程,以忽略应用了样式的输入字段。您还必须考虑使用某种形式的自动完成(例如大多数浏览器都内置了!)为他们自动填写所有表单字段的人。他们还不如捡起一个虚拟的领域。display:none
您也可以通过让虚拟字段可见但在屏幕边界之外来稍微改变一下,但这完全取决于您。
要有创意!
评论
visibility:hidden
position:absolute;top:-9000px
text-indent
z-index
<input type="text" name="email" class="cucaracha">
.cucaracha { display:none; }
关于身份验证系统,我最喜欢的规则是:使用密码,而不是密码。容易记住,很难破解。 详细信息:编码恐怖:密码与密码短语
评论
我想补充一个非常重要的评论:-
- “在公司内部网环境中”,上述大多数(如果不是全部)可能不适用!
许多公司部署了“仅供内部使用”的网站,这些网站实际上是“企业应用程序”,恰好是通过URL实现的。这些 URL 只能在“公司的内部网络”内解析。(哪个网络神奇地包括所有连接VPN的“公路战士”。
当用户尽职尽责地连接到上述网络时,他们的身份(“身份验证”)是 [已经...]“确凿地知道”,就像他们做某些事情的许可(“授权”)一样......如。。。“访问本网站。”
这种“身份验证+授权”服务可以通过几种不同的技术提供,例如LDAP(Microsoft OpenDirectory)或Kerberos。
从你的角度来看,你只是知道这一点:任何合法地进入你的网站的人都必须伴随着[一个神奇地包含......]一个“令牌”的环境变量。(即,缺少此类令牌必须是 的直接理由。404 Not Found
令牌的价值对你来说毫无意义,但是,如果需要,“存在适当的手段”,你的网站可以通过它“[权威地]询问知道的人(LDAP......等等)“关于您可能遇到的任何和每一个(!)问题。换句话说,你没有利用任何“本土逻辑”。相反,你询问管理局并含蓄地相信它的判决。
呃呵呵......这与“狂野的互联网”相比,是一种心理上的转变。
评论
我想补充一个我使用过的建议,基于深度防御。您不需要为管理员提供与普通用户相同的身份验证和身份验证系统。您可以在单独的 URL 上使用单独的登录表单,为将授予高权限的请求执行单独的代码。这个人可以做出对普通用户来说完全痛苦的选择。我使用的一种方法是实际扰乱管理员访问的登录 URL,并通过电子邮件将新 URL 发送给管理员。立即阻止任何暴力攻击,因为您的新 URL 可能非常困难(非常长的随机字符串),但您的管理员用户唯一的不便是点击他们电子邮件中的链接。攻击者甚至不再知道该开机到底到哪里。
评论
我不知道最好是作为答案还是作为评论来回答这个问题。我选择了第一个选项。
关于第一个答案中的第四部分:忘记密码功能,我想说的是定时攻击。
在“记住您的密码”表单中,攻击者可能会检查电子邮件的完整列表,并检测哪些电子邮件已注册到系统(请参阅下面的链接)。
关于忘记密码表单,我想补充一点,使用一些延迟功能将成功和不成功的查询之间的时间相等是一个好主意。
https://crypto.stanford.edu/~dabo/papers/webtiming.pdf
使用 OpenID Connect 或用户管理的访问。
因为没有什么比根本不做更有效率的了。
评论
HttpOnly