# 身份验证备忘单
> 原文:[Authentication Cheat Sheet](https://www.owasp.org/index.php/Authentication_Cheat_Sheet)
> 来源:[身份验证备忘单](http://cheatsheets.hackdig.com/?3.htm)
## 介绍
身份验证是一种验证一个人或实体声明的身份是否正确的过程。身份验证通常是由用户提交用户名或者ID、一个或多个只有给定用户才知道的私人信息来完成。
会话管理是一个服务器维护与某个实体的交互状态的过程。服务器需要记住如何在一个事务中响应后续请求。会话由服务器维护,服务器使用一个可以在客户端与服务端传递的会话标示符来做这个工作。每个用户都应该有一个独一无二的会话,并且这个会话非常难以预测(以防被攻击者猜解)。
## 身份认证主要指导方案
### 用户ID
确保你的用户名/用户ID是不区分大小写的。许多网站使用email地址作为用户名,email地址正好就是不区分大小写的。如果你不注意这个问题,可能会导致严重的混乱:smith和Smith竟然是不同的用户。
### 适当的密码强度控制
使用密码认证时,密码的强度是一个重要的关注点。一个健壮的密码策略使通过手动/自动猜测密码变得非常难。以下特征定义了一个健壮的密码:
#### 密码长度
更长的密码能让字符有更多组合,从而使得攻击者更难猜到。
应用程序应该强制检测最小密码长度。
密码少于10个字符的被视为弱密码 ([1]).
限制最小密码长度可能导致一些用户难以记住自己的密码,应用程序应该引导用户使用口令句(句子或单词的组合)密码,口令句密码比典型的密码要长,但是更便于记忆。
最大密码长度不应设置的过低,因为它会妨碍用户创建口令句密码。典型口令句密码的最大长度是128个字符。
口令句密码如果只包含小写拉丁字符,少于20个字符就是弱密码
每个字符都应计算在内!!!
确保用户输入的所有字符都包含在密码内。我们发现有些系统会把用户的密码截断。(例如:用户输入了20位密码,系统截断为15个字符)
这通常是因为设置所有密码输入框的长度为相同的最大长度导致的。这是特别重要的,尤其是你的最大密码长度是20~30个字符的时候。
#### 密码复杂度
应用程序应该包含密码复杂性检查规则,防止(用户)使用容易被猜到的密码。密码机制应该允许用户使用所有可输入的字符作为其密码的一部分,甚至空格也包括在内。密码应该区分大小写来增加密码的复杂度。我们偶尔会在一些旧系统(例如大型机)上发现不区分大小写的密码。
密码修改机制应该根据应用程序和它的用户群至少引入一个最低标准的复杂度。例如:
密码应该满足下面列出规则的3~4条
* 至少一个大写字符(A-Z)
* 至少一个小写字符(a-z)
* 至少一个数字(0-9)
* 至少一个特殊字符(标点符号)——别忘了把空格也当成特殊字符
* 至少10个字符
* 最多128个字符
* 相同字符不要连续重复超过两次(如:111)
应用程序需要更复杂的密码策略,开发者需要清楚的了解这些策略是什么。
* 密码策略需要明确的在修改密码页面显示。
* 一定要列出你允许的所有的特殊字符。
推荐:
* 理想情况下,应用程序应将用户输入的密码的复杂度(满足了几条密码复杂度要求)显示给用户。
* 在实际应用中,如果用户的密码不满足密码复杂度要求或者确认密码与密码不同,提交按钮应该是灰色的。这会让用户更容易理解并遵守你的密码复杂度要求。
不管UI的表现是怎样的,当一个用户提交他们的修改密码请求时:
* 如果新密码不符合密码复杂度要求,错误提示应描述其每条不符合的复杂度规则,而不是仅仅提示第一条不符合的规则。
修改密码应该简单,不要把它搞的像在黑暗中打猎一样。
### 实现安全的密码恢复机制
应用程序通常都有一个找回密码的机制,帮助忘记密码的人重新获得账号的控制权限。请查看《忘记密码备忘单 获取更多这方面的信息。
### 使用安全的方式存储密码
使用正确的加密技术是应用程序存储密码的关键。请查看密码存储备忘单查看更多这方面的信息。
### 密码只应使用TLS传输
详情请看: 传输层保护备忘单
登陆页面及之后的身份认证页面数据都必须完全(包括页面上的所有元素)通过TLS传输。最初的登陆页面(通常被称为login landing page)必须配以TLS。如果登陆页面没有使用TLS,攻击者就可以修改登陆表单,将用户的身份凭证发送到任意一个网络区域。如果登陆页面之后的身份认证页面没有使用TLS,攻击者就可以查看未加密的会话ID,威胁用户的会话安全。
### 敏感操作需要重新认证
为了降低CSRF和会话劫持攻击的危害,在用户做修改密码或邮箱修改敏感信息操作,修改货品寄送地址等敏感交易操作时,需要用户重新验证身份。没有这个对策,一个攻击者可以通过CSRF或XSS攻击,在无需知道用户当前身份凭证的情况下,来执行敏感交易。另外,攻击者可能通过临时物理接触用户的浏览器或者窃取他们的会话ID来劫持用户的会话。
### 多因素认证(MFA)
多因素认证(MFA)是指使用多个身份认证因素来登入系统或执行流程:
* 一些是你知道的(账号信息或密码)
* 一些是你拥有的(令牌或手机)
* 一些是你的特性(如生物特性)
类似OTP等使用硬件令牌实现的认证方案也是防范CSRF和客户端恶意软件攻击的好办法。市面上有很多MFA硬件可以集成到你的应用程序中。获取更多信息请查看: [2]。
### SSL客户端身份认证
SSL客户端身份认证又称双向SSL身份认证。浏览器和服务器在TLS握手过程中,发送各自的SSL证书来表明身份。正如你可以通过询问CA这个证书是否有效来验证服务器的真实性,服务器同样可以通过接受客户端发送的证书来验证用户(询问第三方CA或者自己的CA)。服务器为用户提供一个独有的签名证书,特定用户安装证书后,可以用它来用访问网站,没有这个证书的用户则无法访问。
建议在下面的情况下使用此技术:
* 当用户只从一台电脑或浏览器访问者这个网站时,这是可以接受的(甚至是首选)方案。
* 当用户不会被“在浏览器上安装SSL证书的繁琐步骤”吓到或者有专门的IT支持人员帮助他做这个事情的时候。
* 网站需要更加的安全的认证步骤的时候。
* 当网站是一个公司或组织的内网站点时,这也是一个很好的选择。
对一个大量用户和公共网站来说,这通常不是一个好主意。例如:对于Fackbook,这个方案是不适用的。同时,这个技术可以让用户不用输入密码来访问网站(从而防止键盘记录器窃取密码信息)。不过使用密码和SSL客户端身份认证结合的认证方式依旧是个保护用户安全的好主意。
查看更多信息,请访问: [3] 或 [4]
### 身份认证和错误信息
在身份认证功能的开发中,不正确的错误信息提示可能会让攻击者能够使用用户ID和密码进行枚举。一个应用程序应该尽可能的以通用的方式返回HTTP或HTML响应。
#### 身份认证响应
无论用户的用户ID还是密码输入错误,应用程序都应该返回一个通用的错误提示信息。对于一个存在的账号,应用程序不应该给予任何能够标示账号存在状态的提示(如提示:当前账号存在,但密码错误)。
#### 不正确的响应示例
"用户foo登陆:密码错误
"登陆失败:用户ID错误"
"登陆失败:账号被禁用"
"登陆失败:用户未激活"
#### 正确的响应示例
"登陆失败,用户ID或密码错误"
正确的响应不会标示出用户ID或者密码是否准确,从而保证攻击者不能猜到有效的用户ID。
#### 错误码与URL
应用程序可能会根据尝试进行身份认证的不同行为,返回不同的HTTP错误码。当有匹配的认证结果时,返回200状态码;当没有匹配的结果时,返回403错误码。尽管给用户显示了一个通用的错误页面,HTTP状态码的不同导致攻击者可以用来判断账号有效还是无效。
### 防止暴力破解攻击
如果攻击者能够猜测密码,并且账号不会因为多次失败的身份认证尝试而被禁用,那么攻击者就有机会使用暴力破解技术盗取用户的账户。自动暴力破解/密码尝试攻击只是WEB应用常见的安全挑战之一。当一个账号的失败登陆尝试次数超过阈值,密码锁定机制应该生效。密码锁定机制也是有逻辑弱点的,攻击者会在已知的账号上进行大量的身份认证尝试,进而锁定所有的用户账号。鉴于密码锁定系统的目的是防止受到暴力破解攻击,一个明智的策略是锁定账号一段时间(如20分钟),这能显著降低攻击者的破解速度同时让合法用户能够自动解锁(防止被恶意锁定)。
同时,多因素身份认证是一个防止暴力破解攻击的非常强大的工具,因为认证凭证是一个动态变量。当使用多因素身份认证时,账号锁定机制可能就不必要了。
## 使用无需密码的身份认证协议
虽然通过用户名/密码组合和使用多因素身份认证通常比较安全,但是仍然有些不适用的案例。一个例子是第三方应用程序想通过手机设备、另外一个站点、桌面或其他方式连接到web应用程序。这种情况下,让第三方应用程序存储用户名/密码是极不安全的。这会使易受攻击的面扩大,超出你的控制。在这种情况下(或类似的案例),有一些身份认证协议可以保护你,避免你的用户数据暴露在攻击者面前。
### OAuth
开放授权(OAuth)是一种允许应用程序在不需要密码或第三方身份认证提供商的情况下,验证用户的身份。它使用服务器生成的token,提供授权流程,从而让客户端(如手机应用程序)能够告知服务器,当前是哪个用户在使用这个服务。
建议使用和实现OAuth 2.0,因为第一个版本(OAuth1.0)容易遭到会话固定攻击(session fixation)。
OAuth 2.0目前已经被Facebook, Google, Twitter和Microsoft等公司实现和使用。
### OpenId
OpenId是一个基于HTTP协议的使用身份提供者来识别用户的工具。这是一个非常简单的协议,允许服务提供者发起单点登录(SSO)。这个协议允许用户在多个网站重用一个OpenId身份提供者给予的身份。只需要提供给OpenId身份提供者密码,而不需要提供其他任何网站的密码。
因为这种方式非常简单并能有效的保护密码,OpenId得到广泛的应用。一些知名的身份认证提供者Stack Exchange, Google, Facebook和Yahoo!都支持OpenId。
对于非企业环境,只要身份认证提供者可信,OpenId就是安全的而正确的选择。
### SAML
安全断言标记语言(SAML)通常被看做OpenId的竞争对手。推荐使用SAML2.0版本,因为这个版本功能全面并提供了很强的安全性。就像OpenId一样,SAML也使用身份认证提供者角色,与之不同的是,SAML是基于XML并提供了更多的灵活性。SAML是依赖浏览器跳转来发送XML数据的。不同于OpenId(译者觉得此处原文可能错误,原文是Unlike SAML),SAML不仅能从服务提供者那里开始,而且能从身份认证提供者那里开始。用户不用做任何事情,就能在不同的站点切换,并保证身份认证依旧有效,这让身份认证过程变得简单而透明。
OpenId占据大多数消费级市场,SAML通常是企业应用的首选。这是因为几乎没有被认可的企业级OpenId身份认证提供者(意味着他们检查用户身份的标准达不到企业身份认证的高标准)。SAML常常被用在内网环境,有时候甚至使用一个内网服务器作为身份认证提供者。
在过去的几年里,应用程序如SAP ERP和SharePoint(使用ADFS2.0的SharePoint)决定使用SAML2.0来做身份认证。当web服务和web应用程序需要企业间联合时,将其作为SSO实现的首选方案。
## 会话管理通用指南
会话管理与身份验证直接相关。目前会话管理通用指南已经移到会话管理备忘单。
## 密码管理工具
密码管理工具可以是应用程序、浏览器插件或网络服务,他们自动化的管理大量不同的凭证,包含记住密码、自动填充、在不同的网站生成随机的密码等功能。web应用程序在这些情况下能帮助密码管理工具更好的工作:
* 用户名和密码使用标准的HTML输入框。
* 不在HTML表单区域禁用复制和粘贴。
* 允许非常长的密码。
* 不使用多级登陆方案(用户名在第一页,密码在第二页)。
* 不使用严重依赖脚本(javascript等)进行身份验证的方案。
## 作者与主编
Eoin Keary eoinkeary[at]owasp.org