基于表单的网站authentication的权威性指南

基于表单的网站authentication

我们认为,堆栈溢出不应该只是一个非常具体的技术问题的资源,而且也是关于如何解决常见问题的一般指导。 “基于表单的网站authentication”应该是这样一个实验的一个很好的话题。

它应该包括以下主题:

  • 如何login
  • 如何保持login状态
  • pipe理Cookie(包括推荐设置)
  • SSL / HTTPSencryption
  • 如何存储密码
  • 使用秘密的问题
  • 忘记用户名/密码function
  • 使用随机数来防止跨站请求伪造(CSRF)
  • OpenID的
  • “记住我”checkbox
  • 浏览器自动完成用户名和密码
  • 秘密URL(被摘要保护的公共URL )
  • 检查密码强度
  • 电子邮件validation
  • 以及更多关于 基于表单的身份validation …

它不应该包括像这样的东西:

  • angular色和授权
  • HTTP基本authentication

请帮助我们:

  1. build议子主题
  2. 提交关于这个问题的好文章
  3. 编辑正式的答案

第一部分:如何login

我们假设您已经知道如何构build一个login名+密码HTML表单,该表单将值发布到服务器端的脚本进行身份validation。 下面的部分将讨论合理的实践authentication模式,以及如何避免最常见的安全缺陷。

要HTTPS或不HTTPS?

除非连接已经安全(即使用SSL / TLS通过HTTPS隧道传输),否则您的login表单值将以明文forms发送,从而允许任何在浏览器和Web服务器之间窃听的人窃听login信息。通过。 这种types的窃听是政府常规做的,但是一般来说,我们不会说“拥有”的线路,除非这样说:如果您保护任何重要的东西,请使用HTTPS。

实质上,在login期间防止窃听/数据包嗅探的唯一可行的方法是使用HTTPS或其他基于证书的encryptionscheme(例如TLS )或经过validation和testing的挑战 – 响应scheme(例如, Diffie-Hellman基于SRP)。 任何其他方法都可以被窃听攻击者轻易规避

当然,如果你愿意做一些不切实际的事情,你也可以采用某种forms的双因素身份validationscheme(例如,Google身份validation器应用程序,物理“冷战风格”码本或RSA密钥生成器encryption狗)。 如果正确应用,甚至可以使用不安全的连接,但是很难想象开发者会愿意实现双因素身份validation而不是SSL。

(不要)滚动你自己的JavaScriptencryption/哈希

考虑到在您的网站上设置SSL证书的非零成本和感知技术难度,一些开发人员试图推出自己的浏览器内哈希或encryptionscheme,以避免在不安全的线路上传递明文login。

虽然这是一个崇高的想法,但它本质上是无用的(并且可能是一个安全缺陷 ),除非它与上述之一结合在一起 – 也就是说,要么使用高度encryption来保护线路,要么使用经过validation的挑战 – 响应机制(如果你不知道这是什么,只要知道它是最难以certificate的,最难devise的,而且在数字安全中最难实现的概念)。

虽然哈希密码可以有效防止密码泄露 ,但它却容易受到重放攻击,中间人攻击/劫持(如果攻击者可以在到达您的网页之前向您的不安全的HTML页面中插入几个字节浏览器,他们可以简单地注释掉JavaScript中的散列),或暴力攻击(因为你正在向攻击者提供用户名,密码和散列密码)。

CAPTCHAS反对人性

CAPTCHA旨在阻止一种特定types的攻击:自动字典/暴力试验和错误,没有人类操作员。 毫无疑问,这是一个真正的威胁,然而,有些方法可以无缝处理,不需要validation码,特别是devise合理的服务器login限制scheme – 我们将在后面讨论。

知道validation码的实现不是相同的; 他们通常不是人类可以解决的,他们中的大多数对于机器人实际上是无效的,他们都对廉价的第三世界劳动力无效(根据OWASP ,目前的血汗工厂的费率是每500个testing12美元),有些实施可能是技术上在一些国家是非法的(见OWASP身份validation备忘单 )。 如果您必须使用CAPTCHA,请使用Google的reCAPTCHA ,因为它的定义是OCR-hard(因为它已经使用了OCR错误分类的书本扫描),并且非常难以用户友好。

就我个人而言,我倾向于发现CAPTCHAS令人讨厌,并且当用户多次login失败并且限制延迟被最大化时,将它们仅用作最后的手段。 这种情况很less会被接受,从而加强了整个体系。

存储密码/validationlogin

在最近几年我们已经看到的所有高度公开的黑客和用户数据泄漏之后,这可能最终是常识,但是必须说:不要在数据库中以明文forms存储密码。 用户数据库通常是通过SQL注入攻击,泄露或收集的,如果您正在存储原始的明文密码,那么您的login安全性就是即时游戏。

所以,如果你不能存储密码,你如何检查从login表单发送的login名+密码组合是否正确? 答案是使用密钥派生函数进行散列。 无论何时创build新用户或更改密码,您都需要input密码并通过KDF(如bcrypt,scrypt或PBKDF2)运行,将明文密码(“correcthorsebatterystaple”)转换为长且随机的string,在你的数据库中存储更安全。 要validationlogin名,您对input的密码运行相同的哈希函数,这次传入salt并将生成的哈希string与存储在数据库中的值进行比较。 bcrypt和scrypt已经存储了哈希值。 请参阅sec.stackexchange上的这篇文章以获取更多详细信息。

使用盐的原因是因为哈希本身是不够的 – 你会想添加一个所谓的“盐”,以防止彩虹表的散列。 盐有效地防止两个完全匹配的密码被存储为相同的散列值,从而防止在攻击者正在执行密码猜测攻击时整个数据库被一次扫描。

密码散列不应该用于密码存储,因为用户select的密码不够强(即通常不包含足够的熵),并且攻击者可以在相对较短的时间内通过访问散列来完成密码猜测攻击。 这就是为什么使用KDF–这些有效的“延伸密钥”,这意味着攻击者所做的每个密码猜测都涉及多次迭代哈希algorithm,例如10,000次,这使得攻击者的密码猜测速度减慢了10,000倍。

会话数据 – “您以Spiderman69身份login”

一旦服务器validation了用户数据库的login名和密码并find匹配项,系统就需要记住浏览器已被authentication。 这个事实应该只存储在服务器端的会话数据中。

如果您对会话数据不熟悉,请按照以下步骤操作:将一个随机生成的string存储在即将到期的Cookie中,并用于引用存储在服务器上的数据集合(会话数据)。 如果你使用的是MVC框架,这无疑已经被处理了。

如果可能,请确保会话cookie在发送到浏览器时设置了安全和HTTP Only标志。 httponly标志为防止XSS攻击读取的cookie提供了一些保护。 安全标志确保cookie仅通过HTTPS发回,从而防止networking嗅探攻击。 cookie的价值不应该是可预测的。 在提交引用不存在的会话的cookie的情况下,应立即replace其值以防止会话固定 。

第二部分:如何保持login – 臭名昭着的“记住我”checkbox

持久loginCookies(“记住我”function)是危险区域; 一方面当用户理解如何处理时,它们与传统login完全一样安全; 另一方面,对于不小心的用户来说,这是一个巨大的安全风险,他们可能会在公用计算机上使用它们,忘记注销,谁不知道浏览器cookie是什么或者如何删除它们。

就我个人而言,我喜欢定期访问我访问的网站的持续login,但我知道如何安全地处理这些网站。 如果您肯定您的用户知道相同的内容,则可以使用持久的login信息来干净的良心。 如果没有 – 那么你可以订阅这样一种理念,那些粗心的用户如果被黑客入侵,就会将自己的login凭据带到自己的身上。 这不像我们去用户的房子,并撕下所有那些带有密码的贴纸引起的便签纸,这些密码也是在他们的显示器边缘排列的。

当然,有些系统不能有任何账户被黑客入侵; 对于这样的系统,你无法certificate持久login是正确的。

如果您决定实施持久性loginCookie,那么您可以这样做:

  1. 首先,花一些时间阅读Paragon Initiative关于这个主题的文章 。 你需要得到一些正确的元素,文章做了很好的解释。

  2. 只是为了重申其中一个最常见的陷阱, 不要在您的数据库中存储持久性login帐户(代币),只有它的哈希! login令牌是密码等效的,所以如果攻击者拿到你的数据库,他们可以使用令牌login到任何帐户,就像他们是明文login密码组合。 因此,在存储持久login标记时,使用散列(根据https://security.stackexchange.com/a/63438/5002弱散列可以很好地实现此目的)。;

第三部分:使用秘密问题

不要执行“秘密问题” 。 “秘密问题”function是一种安全反模式。 从MUST-READ列表中阅读链接编号4的文章。 你可以问萨拉·佩林关于那个,她的雅虎! 电子邮件帐户在之前的总统竞选中被黑了,因为她的安全问题的答案是……“瓦西拉高中”!

即使用户指定的问题,大多数用户很可能会select:

  • 一个“标准”的秘密问题,如母亲的娘家姓或宠物

  • 一个简单的琐事,任何人都可以从他们的博客,LinkedIn的个人资料,或类似的提升

  • 任何比猜测他们的密码更容易回答的问题。 对于任何体面的密码,哪一个是你可以想象的问题

总而言之,安全问题实质上在所有forms和变化中都是不安全的,不应该出于任何原因在authenticationscheme中使用。

安全问题甚至存在的真正原因是他们方便地节省了一些无法访问他们的电子邮件的用户的支持电话的成本,以获得重新激活代码。 这以牺牲安全性和佩林的声誉为代价。 值得? 可能不会。

第四部分:忘记密码function

我已经提到了为什么你不应该使用安全问题来处理被遗忘/丢失的用户密码; 不言而喻,您不应该通过电子邮件向用户发送实际的密码。 在这个领域至less还有两个常见的陷阱:

  1. 不要一个被遗忘的密码重置为自动生成的强密码 – 这样的密码是非常难以记住的,这意味着用户必须改变它或者把它写下来 – 比如在显示器边缘的明亮的黄色Post-It上。 而不是设置一个新的密码,只需让用户立即select一个新的密码 – 这正是他们想要做的。

  2. 总是将丢失的密码代码/令牌散列在数据库中。 再次 ,这个代码是密码等效的另一个例子,所以它必须被散列,以防攻击者拿到你的数据库。 当请求丢失密码时,将明文代码发送到用户的电子邮件地址,然后对其进行散列,将散列保存在数据库中,然后丢弃原始文件 。 就像密码或持久login令牌一样。

最后一点:确保你input“丢失的密码”的界面至less和你的login表单本身一样安全,否则攻击者会简单地使用它来获得访问权限。 确保生成非常长的“丢失的密码”(例如,16个区分大小写的字母数字字符)是一个好的开始,但考虑添加与login表单本身相同的限制scheme。

第五部分:检查密码强度

首先,您需要阅读这篇小文章,了解真实情况: 500个最常见的密码

好吧,也许这个列表并不是任何系统上任何系统上最常用密码的规范列表,但是这是很好的指示,当没有强制执行的策略时,人们将select密码的程度如何。 此外,当您将其与最近被盗密码的公开可用分析进行比较时,该列表看上去离家很近。

因此:没有最低密码强度要求,2%的用户使用前20个最常用的密码之一。 意思是:如果攻击者只有20次尝试,你网站上的50个帐户中有1个将被破解。

阻止这个需要计算密码的熵然后应用一个阈值。 国家标准与技术研究院(NIST) 特刊800-63有一套非常好的build议。 当与字典和键盘布局分析(例如,“qwertyuiop”是一个错误的密码)结合使用时,可以在18位熵的级别拒绝99%的所有select不当的密码 。 简单地计算密码强度并向用户显示视觉强度计是好的,但是不足。 除非强制执行,否则很多用户很可能会忽略它。

为了让用户更方便地使用高熵密码,强烈build议使用Randall Munroe的密码强度xkcd 。

第六部分:更多 – 或者:防止快速login尝试

首先,看看数字: 密码恢复速度 – 你的密码将站起来多久

如果你没有时间查看这个链接中的表格,下面是它们的列表:

  1. 即使你用算盘来破解它,也几乎没有时间来破解弱密码

  2. 如果不区分大小写几乎不需要破解字母数字的9个字符的密码

  3. 如果长度小于8个字符 ,则几乎不需要时间来破解复杂的符号和字母及数字,大小写密码(一台台式机可以search整个密钥空间,最多7个字符几天甚至几小时)

  4. 但是, 如果您每秒限制一次尝试那么将会花费过多的时间来破解6个字符的密码

那么我们可以从这些数字中学到什么? 好吧,但是我们可以把重点放在最重要的部分上:防止大量的快速连续login尝试(即暴力攻击)实际上并不困难。 但是阻止它的正确性并不像看起来那么容易。

一般来说,你有三个select对于暴力攻击(和字典攻击都是有效的,但是由于你已经在使用强密码策略,所以不应该成为问题)

  • N次尝试失败后出示一个CAPTCHA (烦人的地狱,经常无效 – 但我在这里重复)

  • locking帐户并在N次尝试失败后需要电子邮件validation(这是等待发生的DoS攻击)

  • 最后, login限制 :也就是说,在N次尝试失败之后设置一次尝试之间的时间延迟(是的,DoS攻击仍然是可能的,但至less它们不太可能,而且更难复原)。

最佳做法#1:短暂的时间延迟随着尝试失败的次数而增加,如:

  • 1次失败尝试=没有延迟
  • 2次失败尝试= 2秒延迟
  • 3次失败尝试= 4秒延迟
  • 4次失败尝试= 8秒延迟
  • 5次失败尝试= 16秒延迟
  • 等等

DoS攻击这个scheme将是非常不切实际的,因为所产生的locking时间比之前的locking时间的总和稍大。

澄清:在将响应返回给浏览器之前,延迟不是延迟。 这更像是一个超时或不应期,在此期间,login尝试到特定的帐户或从一个特定的IP地址将不会被接受或评估。 也就是说,正确的凭证不会以成功的login返回,而不正确的凭证不会延迟增加。

最佳做法#2: N次失败尝试后生效的中等时间延迟,如:

  • 1-4次失败尝试=没有延迟
  • 5次失败尝试= 15-30分钟延迟

DoS攻击这个scheme将是非常不切实际的,但肯定是可行的。 另外,注意到这样一个长时间的延迟对于一个合法用户来说是非常烦人的。 健忘的用户会不喜欢你。

最佳实践#3:将两种方法结合起来 – 要么是在N次失败尝试后生效的固定的短时间延迟,如:

  • 1-4次失败尝试=没有延迟
  • 5次失败尝试= 20秒延迟

或者,一个固定的上限越来越延迟,如:

  • 1失败尝试= 5秒延迟
  • 2次失败尝试= 15秒延迟
  • 3次失败尝试= 45秒延迟

这个最后的计划是从OWASP的最佳实践build议(MUST-READ列表中的链接1)中提取出来的,并且应该被认为是最佳实践,即使它是公认的限制性的一面。

作为一个经验法则,我会说:密码策略越强,用户拖延的时间就越less。 如果您需要强大(区分大小写的字母数字+所需的数字和符号)9个字符的密码,您可以在激活限制之前为用户提供2-4个非延迟密码尝试。

DoS攻击这个最终的login节streamscheme将是非常不切实际的。 作为最后一步,始终允许持久(cookie)login(和/或validation码validation的login表单)通过,因此合法用户在攻击进行甚至不会被延迟。 这样,非常不切实际的DoS攻击变得非常不切实际的攻击。

此外,对pipe理员帐户进行更积极的限制是有意义的,因为这是最有吸引力的入口点

第七部分:分布式蛮力攻击

就像旁白一样,更高级的攻击者会试图通过“传播活动”来规避login限制:

  • 分发僵尸networking上的企图,以防止IP地址标记

  • 而不是挑选一个用户,并尝试50,000个最常用的密码(他们不能,因为我们的限制),他们会select最常用的密码,而不是对50,000个用户进行尝试。 这样一来,他们不仅可以避免像CAPTCHA和login节stream这样的最大尝试措施,而且他们的成功机会也会增加,因为最常见的密码比数字49.995

  • 将每个用户帐户的login请求隔开一段时间,例如间隔30秒,以躲避雷达

在这里,最好的做法是logging系统范围内login失败的次数 ,并使用站点不良login频率的运行平均值作为您对所有用户施加的上限的基础。

太抽象了? 让我换句话来说:

假设您的网站在过去3个月内平均每天有120次login失败。 使用(运行平均),您的系统可能会设置全球限制3倍 – 即。 在24小时内360次失败。 然后,如果所有帐户中失败尝试的总次数在一天内(甚至更好,监控加速率和在计算的阈值上触发)超过该数量,则会激活系统范围的login限制 – 这意味着所有用户的短暂延迟(仍然是cookielogin和/或备份validation码login除外)。

我还发布了一个更详细的问题和一个非常好的讨论如何避免棘手的贱金者抵御分布式蛮力攻击

第八部分:双因素authentication和authentication提供者

证书可能会受到威胁,无论是通过漏洞利用,密码被写下来和丢失,钥匙被盗用的笔记本电脑,还是用户login到钓鱼网站。 使用双因素身份validation可以进一步保护login,这些身份validation使用带外因素,例如通过电话,SMS消息,应用程序或encryption狗收到的一次性代码。 多家提供商提供双因素authentication服务。

身份validation可以完全委托给单点login服务,在这种服务中,另一个提供程序处理收集凭证。 这将问题推给了一个值得信赖的第三方。 Google和Twitter都提供基于标准的SSO服务,而Facebook则提供了类似的专有解决scheme。

必须阅读链接关于Webauthentication

  1. OWASP身份validation指南 / OWASP身份validation备忘单
  2. 在网上进行客户端authentication的注意事项(非常可读的麻省理工学院研究论文)
  3. Wikipedia:HTTP cookie
  4. 后备authentication的个人知识问题:Facebook时代的安全问题(非常易读的伯克利研究论文)

权威性文章

发送凭证

发送凭据100%安全的唯一可行的方法是使用SSL 。 使用JavaScript来散列密码是不安全的。 客户端密码哈希的常见缺陷:

  • 如果客户端和服务器之间的连接是未encryption的,那么所做的一切都容易受到中间人攻击 。 攻击者可以取代传入的JavaScript来打破哈希或发送所有凭据到他们的服务器,他们可以听取客户端的反应和完美地模拟用户等等。SSL与可信证书颁发机构旨在防止MitM攻击。
  • 如果您不在服务器上执行额外的冗余工作,则服务器接收的散列密码的安全性会降低 。

还有另一种称为SRP的安全方法,但是它已经获得专利(虽然它是免费许可的 ),并且很less有好的实现可用。

存储密码

千万不要将密码作为明文存储在数据库中。 即使你不关心你自己的网站的安全。 假设您的部分用户将重复使用其在线银行帐户的密码。 所以,存储哈希密码,并扔掉原来的。 并确保密码不会显示在访问日志或应用程序日志中。 最好的哈希函数似乎是bcrypt

哈希本身也是不安全的。 例如,相同的密码意味着相同的哈希值 – 这使得哈希查找表是一次破解大量密码的有效方法。 相反,存储盐渍散列。 salt是在散列之前附加到密码的string – 每个用户使用不同的(随机)盐。 salt是一个公共值,所以你可以把它们存储在数据库中。 请参阅这里了解更多。

这意味着你不能发送用户忘记密码(因为你只有散列)。 除非您已经对用户进行了身份validation,否则不要重置用户的密码(用户必须certificate他们能够读取发送到存储(和validation的)电子邮件地址的电子邮件。)

安全问题

安全问题是不安全的 – 避免使用它们。 为什么? 任何安全问题,密码都会更好。 阅读第三部分:在@Jens Roland 使用秘密问题在这个维基上的答案 。

会话cookie

用户login后,服务器向用户发送会话cookie。 服务器可以从cookie中获取用户名或者id,但是没有人能够生成这样的cookie(TODO解释机制)。

Cookies可能被劫持 :它们只与客户的其他机器和其他通信一样安全。 它们可以从磁盘读取,在networkingstream量中嗅探,由跨站点脚本攻击提取,从中毒的DNS中捕获,以便客户端将其cookie发送到错误的服务器。 不要发送持久性cookies。 Cookie应在客户端会话结束时过期(浏览器closures或离开您的域)。

如果你想自动login你的用户,你可以设置一个永久性的cookie,但它应该与完整的会话cookie不同。 您可以设置用户自动login的附加标志,并且需要login才能进行敏感操作。 这是受欢迎的购物网站,希望为您提供一个无缝的,个性化的购物体验,但仍然保护您的财务细节。 例如,当您返回访问亚马逊时,会向您显示一个看起来像您已login的页面,但当您下订单(或更改您的送货地址,信用卡等)时,它们会要求您确认你的密码。

另一方面,诸如银行和信用卡的金融网站仅具有敏感数据,不应允许自动login或低安全性模式。

外部资源列表

  • 网上客户端authentication的注意事项(PDF)
    21页的学术文章与许多伟大的提示。
  • 询问YC:用户authentication的最佳实践
    论坛讨论这个问题
  • 你很可能会错误地存储密码
    有关存储密码的介绍性文章
  • 讨论:编码恐怖:你可能存储密码不正确
    关于编码恐怖文章的论坛讨论。
  • 切勿将密码存储在数据库中!
    关于在数据库中存储密码的另一个警告。
  • 密码破解
    维基百科关于几个密码哈希scheme的弱点的文章。
  • 足够的彩虹表:你需要知道的安全密码scheme
    讨论关于彩虹桌的问题,以及如何防御彩虹桌以及其他线索。 包括广泛的讨论。

首先,强烈的警告,这个答案是不是最适合这个确切的问题。 它绝对不应该是最好的答案!

我将继续提到Mozilla提出的BrowserID (或者更准确地说, validation电子邮件协议 ),以find升级途径,以便在将来更好地进行身份validation。

我将这样总结一下:

  1. Mozilla是一个非常有价值的非营利组织,可以很好地解决这个问题。
  2. 现在的现实是,大多数网站使用基于表单的身份validation
  3. 基于表单的身份validation有一个很大的缺点,那就是增加了networking钓鱼的风险。 要求用户将敏感信息input由远程实体控制的区域,而不是由其用户代理(浏览器)控制的区域。
  4. 由于浏览器是隐式信任的(用户代理的整体思想是代表用户行事),他们可以帮助改善这种情况。
  5. 阻碍进展的主要力量是部署僵局 。 必须将解决scheme分解成可以自行提供一些增量利益的步骤。
  6. 内置于互联网基础设施中的表示身份的最简单的分散方法是域名。
  7. 作为expression身份的第二层,每个域pipe理自己的一套帐户。
  8. “account @ domain”forms简洁,支持多种协议和URIscheme。 当然,这样的标识符通常被认为是电子邮件地址。
  9. 电子邮件提供商已经是在线的事实上的主要身份提供商。 目前的密码重置stream程通常可以让您控制一个帐户,如果你能certificate你控制该帐户的相关电子邮件地址。
  10. validation电子邮件协议是为了提供一种基于公钥encryption技术的安全方法,用于简化向B域certificate你在域A上拥有帐户的过程。
  11. 对于不支持“validation电子邮件协议”的浏览器(目前全部是),Mozilla提供了一个在客户端JavaScript代码中实现协议的Shim。
  12. 对于不支持“validation电子邮件协议”的电子邮件服务,该协议允许第三方充当可信中介,声称他们已validation用户对帐户的所有权。 拥有大量这样的第三方是不可取的; 这个function只是为了允许升级path,并且电子邮件服务本身提供这些断言是非常优选的。
  13. Mozilla提供他们自己的服务来充当这样一个可信任的第三方。 实施validation邮件协议的服务提供商(即依赖方)可能会select信任Mozilla的断言。 Mozilla's service verifies users' account ownership using the conventional means of sending an email with a confirmation link.
  14. Service Providers may, of course, offer this protocol as an option in addition to any other method(s) of authentication they might wish to offer.
  15. A big user interface benefit being sought here is the “identity selector”. When a user visits a site and chooses to authenticate, their browser shows them a selection of email addresses (“personal”, “work”, “political activism”, etc.) they may use to identify themselves to the site.
  16. Another big user interface benefit being sought as part of this effort is helping the browser know more about the user's session – who they're signed in as currently, primarily – so it may display that in the browser chrome.
  17. Because of the distributed nature of this system, it avoids lock-in to major sites like Facebook, Twitter, Google, etc. Any individual can own their own domain and therefore act as their own identity provider.

This is not strictly “form-based authentication for websites”. But it is an effort to transition from the current norm of form-based authentication to something more secure: browser-supported authentication.

I just thought I'd share this solution that I found to be working just fine.

I call it the Dummy Field (though I haven't invented this so don't credit me).

In short: you just have to insert this into your <form> and check for it to be empty at when validating:

 <input type="text" name="email" style="display:none" /> 

The trick is to fool a bot into thinking it has to insert data into a required field, that's why I named the input "email". If you already have a field called email that you're using you should try naming the dummy field something else like "company", "phone" or "emailaddress". Just pick something you know you don't need and what sounds like something people would normally find logical to fill in into a web form. Now hide the input field using CSS or JavaScript/jQuery – whatever fits you best – just don't set the input type to hidden or else the bot won't fall for it.

When you are validating the form (either client or server side) check if your dummy field has been filled to determine if it was send by a human or a bot.

例:

In case of a human: The user will not see the dummy field (in my case named "email") and will not attempt to fill it. So the value of the dummy field should still be empty when the form has been send.

In case of a bot: The bot will see a field whose type is text and a name email (or whatever it is you called it) and will logically attempt to fill it with appropriate data. It doesn't care if you styled the input form with some fancy CSS, web-developers do it all the time. Whatever the value in the dummy field is, we don't care as long as it's larger than 0 characters.

I used this method on a guestbook in combination with CAPTCHA , and I haven't seen a single spam post since. I had used a CAPTCHA-only solution before, but eventually it resulted in about five spam posts every hour. Adding the dummy field in the form has stopped (at least till now) all the spam from appearing.

I believe this can also be used just fine with a login/authentication form.

Warning : Of course this method is not 100% fool proof. Bots can be programmed to ignore input fields with the style display:none applied to it. You also have to think about people who use some form of auto-completion (like most browsers have built-in!) to auto-fill all form fields for them. They might just as well pick up a dummy field.

You can also vary this up a little by leaving the dummy field visible but outside the boundaries of screen, but this is totally up to you.

有创意!

I do not think the above answer is "wrong" but there are large areas of authentication that are not touched upon (or rather the emphasis is on "how to implement cookie sessions", not on "what options are available and what are the trade offs".

My suggested edits / answers are

  • The problem lies more in account setup than in password checking.
  • The use of two factor authenitication is much more secure than more clever means of password encryption
  • Do NOT try to implement your own login form or database storage of passwords, unless the data being stored is valueless at account creation and self-generated (that is, web 2.0 style like Facebook, Flickr , etc.)

    1. Digest Authentication is a standards based approach supported in all major browsers and servers, that will not send a password even over a secure channel.

This avoids any need to have "sessions" or cookies as the browser itself will re-encrypt the communication each time. It is the most "lightweight" development approach.

However, I do not recommend this, except for public, low value services. This is an issue with some of the other answers above – do not try an re-implement server-side authetication mechanisms – this problem has been solved and is supported by most major browsers. Do not use cookies. Do not store anything in your own hand-rolled database. Just ask, per request, if the request is autheticated. Everything else should be supported by configuration and third-party trusted software.

所以…

First, we are confusing the initial creation of an account (with a password) with the re-checking of the password subsequently. If I am Flickr and creating your site for the first time, the new user has access to zero value (blank web space). I truly do not care if the person creating the account is lying about their name. If I am creating an account of the hospital intranet / extranet, the value lies in all the medical records, and so I do care about the identity (*) of the account creator.

This is the very very hard part. The only decent solution is a web of trust. For example, you join the hospital as a doctor. You create a web page hosted somewhere with your photo, your passport number and a public key, and hash them all with the private key. You then visit the hospital and the system administrator looks at your passport, sees if the photo matches you, and then hashes the web page / photo hash with the hospital private key. From now on we can securely exchange keys and tokens. As can anyone who trusts the hospital (there is the secret sauce BTW). The system administrator can also give you an RSA dongle or other two-factor authentication.

But this is a lot of hassle, and not very web 2.0. However, it is the only secure way to create new accounts that have access to valuable information that is not self-created.

  1. Kerberos and SPNEGO – single sign on mechanisms with a trusted third party – basically the user verifies against a trusted third party. (NB this is not in any way the not to be trusted OAuth )

  2. SRP – sort of clever password authentication without a trusted third party. But here we are getting into the realms of "it's safer to use two factor authentication, even if that's costlier"

  3. SSL client side – give the clients a public key certificate (support in all major browsers – but raises questions over client machine security).

In the end it's a tradeoff – what is the cost of a security breach vs the cost of implementing more secure approaches. One day, we may see a proper PKI widely accepted and so no more own rolled authentication forms and databases. One day…

When hashing, don't use fast hash algorithms such as MD5 (many hardware implementations exist). Use something like SHA-512. For passwords, slower hashes are better.

The faster you can create hashes, the faster any brute force checker can work. Slower hashes will therefore slow down brute forcing. A slow hash algorithm will make brute forcing impractical for longer passwords (8 digits +)

A good article about realistic password strength estimation is:

Dropbox Tech Blog » Blog Archive » zxcvbn: realistic password strength estimation

My favourite rule in regards to authentication systems: use passphrases, not passwords. Easy to remember, hard to crack. More info: Coding Horror: Passwords vs. Pass Phrases

I'd like to add one suggestion I've used, based on defense in depth. You don't need to have the same auth&auth system for admins as regular users. You can have a separate login form on a separate url executing separate code for requests that will grant high privileges. This one can make choices that would be a total pain to regular users. One such that I've used is to actually scramble the login URL for admin access and email the admin the new URL. Stops any brute force attack right away as your new URL can be arbitrarily difficult (very long random string) but your admin user's only inconvenience is following a link in their email. The attacker no longer knows where to even POST to.

I dont't know whether it was best to answer this as an answer or as a comment. I opted for the first option.

Regarding the poing PART IV: Forgotten Password Functionality in the first answer, I would make a point about Timing Attacks.

In the Remember your password forms, an attacker could potentially check a full list of emails and detect which are registered to the system (see link below).

Regarding the Forgotten Password Form, I would add that it is a good idea to equal times between successful and unsucessful queries with some delay function.

~dabo/papers/webtiming.pdf

I would like to add one very-important comment:

  • "In a corporate, intra- net setting," most if not all of the foregoing might not apply!

Many corporations deploy "internal use only" websites which are, effectively, "corporate applications" that happen to have been implemented through URLs. These URLs can (supposedly …) only be resolved within "the company's internal network." (Which network magically includes all VPN-connected 'road warriors.')

When a user is dutifully-connected to the aforesaid network, their identity ("authentication") is [already …] "conclusively known," as is their permission ("authorization") to do certain things … such as … "to access this website."

This "authentication + authorization" service can be provided by several different technologies, such as LDAP (Microsoft OpenDirectory) , or Kerberos.

From your point-of-view, you simply know this: that anyone who legitimately winds-up at your website must be accompanied by [an environment-variable magically containing …] a "token." ( ie The absence of such a token must be immediate grounds for 404 Not Found .)

The token's value makes no sense to you, but, should the need arise, "appropriate means exist" by which your web-site can "[authoritatively] ask someone who knows (LDAP… etc.)" about any and every(!) question that you may have. In other words, you do not avail yourself of any "home-grown logic." Instead, you inquire of The Authority and implicitly trust its verdict.

Uh huh … it's quite a mental-switch from the "wild-and-wooly Internet."

Use OpenID Connect or User-Managed Access .

As nothing is more efficient than not doing it at all.