跳到内容

认证备忘录

简介

认证AuthN)是通过确定一个或多个认证器(如密码、指纹或安全令牌)的有效性来验证个人、实体或网站是否如其所声称的身份的过程。

数字身份是在线交易中主体独一无二的表示。数字身份在数字服务的上下文中始终是唯一的,但不一定需要追溯到特定的真实主体。

身份验证是指确定主体确实是其所声称的身份。此概念与KYC(了解您的客户)概念相关,旨在将数字身份与真实人员绑定。

会话管理是服务器维护与其交互的实体状态的过程。这对于服务器记住在整个事务中如何响应后续请求是必需的。会话通过会话标识符在服务器上维护,该标识符可以在客户端和服务器之间传输和接收请求时来回传递。会话应针对每个用户独一无二,且在计算上极难预测。会话管理备忘录包含此领域最佳实践的进一步指南。

认证通用指南

用户ID

用户ID的主要功能是在系统中唯一标识用户。理想情况下,用户ID应随机生成,以防止创建可预测或顺序的ID,这可能会带来安全风险,尤其是在用户ID可能从外部来源暴露或推断出的系统中。

用户名

用户名是用户选择的易于记忆的标识符,用于在登录系统或服务时标识自己。如果用户选择的用户名也作为其在系统中的唯一标识符,则用户ID和用户名可以互换使用。

应允许用户使用其电子邮件地址作为用户名,前提是在注册时验证了该电子邮件。此外,他们应该可以选择电子邮件地址以外的用户名。有关验证电子邮件地址的信息,请访问输入验证备忘录电子邮件讨论

认证解决方案与敏感账户

  • 允许使用敏感账户(即可在解决方案内部使用的账户,例如后端/中间件/数据库)登录任何前端用户界面。
  • 将用于内部非安全访问(例如,公共访问/DMZ)的相同认证解决方案(例如,IDP/AD)用于前端。

实施适当的密码强度控制

使用密码进行认证时的一个关键问题是密码强度。“强”密码策略使得通过手动或自动化方式猜测密码变得困难甚至不可能。以下特征定义了一个强密码:

  • 密码长度
    • 应用程序应强制执行密码的最小长度。短于8个字符的密码被认为是弱密码(NIST SP800-63B)。
    • 密码的最大长度应至少为64个字符,以允许使用密码短语(NIST SP800-63B)。请注意,某些哈希算法的实现可能会导致长密码拒绝服务
  • 不要悄悄地截断密码。密码存储备忘录提供了如何处理超出最大长度密码的进一步指导。
  • 允许使用所有字符,包括Unicode和空格。不应有任何密码组成规则限制允许的字符类型。不应要求包含大小写字母、数字或特殊字符。
  • 当发生密码泄露时,在发现泄露或认证技术发生变化时,确保凭据轮换。避免要求定期更改密码;相反,鼓励用户选择强密码并启用多因素认证备忘录(MFA)。根据NIST指南,验证者不应强制任意的密码更改(例如,定期更改)。
  • 包含密码强度计,以帮助用户创建更复杂的密码
    • zxcvbn-ts库可用于此目的。
    • zxcvbn的其他语言实现此处列出;但是在使用前请检查每个示例的年限和成熟度。
  • 阻止常用和以前泄露的密码
    • Pwned Passwords是一项服务,可根据以前泄露的密码检查密码。API的详细信息在此处
    • 或者,您可以使用此机制下载Pwned Passwords数据库,以便自行托管。
    • 其他热门密码列表可用,但无法保证它们更新的程度
      • 由Daniel Miessler的SecLists托管的各种密码列表
      • NCSC托管的“Have I Been Pwned”中前10万个密码的静态副本,有文本JSON格式。

更多详细信息请查看

实施安全的密码恢复机制

应用程序通常会提供一种机制,允许用户在忘记密码时重新获得对其账户的访问权限。有关此功能的详细信息,请参阅忘记密码备忘录

安全地存储密码

应用程序使用正确的加密技术存储密码至关重要。有关此功能的详细信息,请参阅密码存储备忘录

使用安全函数比较密码哈希值

在可能的情况下,应使用语言或框架提供的安全密码比较函数(如PHP中的password_verify()函数)将用户提供的密码与存储的密码哈希值进行比较。如果无法做到这一点,请确保比较函数:

  • 具有最大输入长度,以防止极长输入导致的拒绝服务攻击。
  • 明确设置两个变量的类型,以防止类型混淆攻击,例如PHP中的魔术哈希(Magic Hashes)。
  • 在常数时间内返回,以防止定时攻击(timing attacks)。

修改密码功能

开发修改密码功能时,请确保:

  • 用户已通过活跃会话进行认证。
  • 验证当前密码。这是为了确保是合法的用户正在更改密码。滥用情况是:合法用户正在使用公共计算机登录。该用户忘记注销。然后另一个人使用这台公共计算机。如果我们不验证当前密码,这个人可能能够更改密码。

仅通过TLS或其他强传输方式传输密码

参见:传输层安全备忘录

登录页面和所有后续认证页面必须仅通过TLS或其他强传输方式访问。未能将TLS或其他强传输方式用于登录页面将允许攻击者修改登录表单操作,导致用户的凭据被发送到任意位置。未能将TLS或其他强传输方式用于登录后的认证页面将使攻击者能够查看未加密的会话ID并损害用户的认证会话。

敏感功能要求重新认证

为了缓解CSRF和会话劫持,在更新敏感账户信息(如用户的密码或电子邮件地址)或进行敏感交易(如将购买的商品运送到新地址)之前,要求提供账户的当前凭据非常重要。如果没有此对策,攻击者可能能够通过CSRF或XSS攻击执行敏感交易,而无需知道用户的当前凭据。此外,攻击者可能会暂时物理访问用户的浏览器或窃取其会话ID以劫持用户的会话。

考虑强大的交易认证

某些应用程序应使用第二个因素来检查用户是否可以执行敏感操作。更多信息请参阅交易授权备忘录

TLS客户端认证

TLS客户端认证,也称为双向TLS认证,包括浏览器和服务器在TLS握手过程中发送各自的TLS证书。正如您可以通过使用证书并询问可验证的有效证书颁发机构(CA)来验证服务器的真实性一样,服务器可以通过从客户端接收证书并对照第三方CA或其自己的CA进行验证来认证用户。为此,服务器必须向用户提供专门为其生成的证书,为主体赋值,以便这些值可用于确定证书应验证哪个用户。用户在浏览器上安装证书,现在将其用于网站。

这种方法适用于以下情况:

  • 用户只从一台计算机/浏览器访问网站是可接受的(甚至更受欢迎)。
  • 用户不会轻易被在浏览器上安装TLS证书的过程吓到,或者会有专人(可能是IT支持人员)为用户完成此操作。
  • 网站需要额外的安全步骤。
  • 当网站是公司或组织的内网时,使用此方法也是一个好主意。

对于面向大众且公开可用的网站,通常不建议使用此方法,因为它们会有普通用户。例如,在像Facebook这样的网站上实现此功能不是一个好主意。虽然此技术可以防止用户输入密码(从而保护其免受普通键盘记录器窃取),但仍然建议考虑将密码和TLS客户端认证结合使用。

此外,如果客户端位于执行SSL/TLS解密的企业代理之后,这将破坏证书认证,除非该站点被允许通过代理。

更多信息,请参见:客户端认证的TLS握手

认证与错误消息

在认证功能中错误地实现的错误消息可用于用户ID和密码枚举。应用程序应以通用方式响应(包括HTTP和HTML)。

认证响应

使用任何认证机制(登录、密码重置或密码恢复),应用程序必须返回通用错误消息,无论

  • 用户ID或密码不正确。
  • 账户不存在。
  • 账户被锁定或禁用。

还应考虑账户注册功能,并且对于用户已存在的情况,可以采用相同的通用错误消息方法。

目的是防止产生差异因素,从而使攻击者能够对应用程序发起用户枚举操作。

有趣的是,业务逻辑本身可能带来与处理时间相关的差异因素。事实上,根据实现的不同,处理时间根据情况(成功与失败)可能显著不同,从而允许攻击者发起基于时间的攻击(例如,几秒钟的差异)。

使用伪代码实现登录功能的示例

  • 第一次实现使用“快速退出”方法
IF USER_EXISTS(username) THEN
    password_hash=HASH(password)
    IS_VALID=LOOKUP_CREDENTIALS_IN_STORE(username, password_hash)
    IF NOT IS_VALID THEN
        RETURN Error("Invalid Username or Password!")
    ENDIF
ELSE
   RETURN Error("Invalid Username or Password!")
ENDIF

可以清楚地看到,如果用户不存在,应用程序将直接抛出错误。否则,当用户存在但密码不正确时,显然在应用程序出错之前会有更多的处理。反过来,相同错误的响应时间将不同,从而允许攻击者区分错误的用户名和错误的密码。

  • 第二次实现不依赖“快速退出”方法
password_hash=HASH(password)
IS_VALID=LOOKUP_CREDENTIALS_IN_STORE(username, password_hash)
IF NOT IS_VALID THEN
   RETURN Error("Invalid Username or Password!")
ENDIF

无论用户或密码是什么,这段代码都将经历相同的过程,从而使应用程序能够在近似相同的响应时间内返回。

向用户返回通用错误消息的问题是一个用户体验(UX)问题。合法用户可能会对通用消息感到困惑,从而使他们难以使用应用程序,并且在多次重试后,可能会因其复杂性而离开应用程序。返回“通用错误消息”的决定可以根据应用程序及其数据的关键性来确定。例如,对于关键应用程序,团队可以决定在失败情况下,用户将始终被重定向到支持页面,并返回“通用错误消息”。

关于用户枚举本身,针对暴力攻击的保护也是有效的,因为它阻止攻击者大规模应用枚举。对于不能返回“通用错误消息”的功能,可以使用CAPTCHA,因为必须保留“用户体验”。

不正确和正确的响应示例
登录

不正确的响应示例

  • “用户foo登录:密码无效。”
  • “登录失败,用户ID无效。”
  • “登录失败;账户已禁用。”
  • “登录失败;此用户未激活。”

正确的响应示例

  • “登录失败;用户ID或密码无效。”
密码恢复

不正确的响应示例

  • “我们已向您发送密码重置链接。”
  • “此电子邮件地址不在我们的数据库中。”

正确的响应示例

  • “如果该电子邮件地址在我们的数据库中,我们将向您发送一封电子邮件以重置您的密码。”
账户创建

不正确的响应示例

  • “此用户ID已被使用。”
  • “欢迎!您已成功注册。”

正确的响应示例

  • “激活您账户的链接已发送到提供的电子邮件地址。”
错误代码和URL

应用程序可能根据认证尝试响应返回不同的HTTP错误代码。对于正面结果,它可能响应200;对于负面结果,它可能响应403。即使向用户显示通用错误页面,HTTP响应代码也可能不同,这可能会泄露账户是否有效的信息。

错误披露也可以用作差异因素,请参阅错误处理备忘录关于应用程序中不同错误的全局处理。

防范自动化攻击

攻击者可以使用多种不同类型的自动化攻击来尝试入侵用户账户。最常见的类型如下:

攻击类型 描述
暴力破解 针对单个账户测试来自字典或其他来源的多个密码。
凭证填充 测试从其他网站泄露获得的用户名/密码对。
密码喷洒 针对大量不同账户测试单个弱密码。

可以实施不同的保护机制来防御这些攻击。在许多情况下,这些防御措施并不能提供完全的保护,但当以深度防御的方式实施其中一些措施时,可以达到合理的保护水平。

以下各节将主要关注防止暴力破解攻击,尽管这些控制措施对其他类型的攻击也可能有效。有关防御凭证填充和密码喷洒的进一步指导,请参阅凭证填充预防备忘录

多因素认证

多因素认证(MFA)无疑是防御大多数与密码相关攻击(包括暴力破解攻击)的最佳防御措施,微软的分析表明它将阻止99.9%的账户入侵。因此,应尽可能实施MFA;但是,根据应用程序受众的不同,强制使用MFA可能不切实际或不可行。

多因素认证备忘录包含实施MFA的进一步指导。

登录限流

登录限流是一种协议,用于防止攻击者通过正常交互方式尝试猜测密码次数过多,它包括以下控制措施:

  • 最大尝试次数。
账户锁定

防止这些攻击最常见的保护措施是实施账户锁定,即在一定数量的登录失败后,阻止在一段时间内进行任何更多的登录尝试。

失败登录的计数器应与账户本身相关联,而不是与源IP地址相关联,以防止攻击者从大量不同的IP地址进行登录尝试。在实施账户锁定策略时,应考虑许多不同的因素,以在安全性和可用性之间取得平衡:

  • 账户被锁定前的失败尝试次数(锁定阈值)。
  • 这些尝试必须发生的时间段(观察窗口)。
  • 账户被锁定的时长(锁定持续时间)。

有些应用程序不使用固定的锁定持续时间(例如,十分钟),而是使用指数锁定,其中锁定持续时间最初很短(例如,一秒),但在每次登录失败后翻倍。

  • 每次账户锁定后延迟的时间(最多2-3次,之后永久锁定账户)。

在设计账户锁定系统时,必须小心防止其被用于通过锁定其他用户账户而导致拒绝服务。一种可能的方法是,即使账户被锁定,也允许使用忘记密码功能登录。

验证码(CAPTCHA)

使用有效的验证码(CAPTCHA)有助于防止针对账户的自动化登录尝试。然而,许多验证码实现存在弱点,允许使用自动化技术或外包服务来解决它们。因此,应将验证码的使用视为一种深度防御控制,以使暴力破解攻击更耗时且成本更高,而不是作为一种预防措施。

在少量登录失败尝试后才要求解决验证码,而不是从第一次登录就要求,可能更具用户友好性。

安全问题和助记词

添加安全问题或助记词也有助于防止自动化攻击,特别是当要求用户输入单词中随机选择的几个字符时。需要注意的是,这构成多因素认证,因为两个因素都是相同的(您知道的东西)。此外,安全问题通常很弱且答案可预测,因此必须仔细选择。选择和使用安全问题备忘录包含此方面的进一步指导。

日志记录和监控

启用认证功能的日志记录和监控,以便实时检测攻击/故障。

  • 确保所有故障都被记录和审查。
  • 确保所有密码失败都被记录和审查。
  • 确保所有账户锁定都被记录和审查。

使用无需密码的认证协议

虽然通过用户名、密码和多因素认证的组合进行认证通常被认为是安全的,但在某些使用场景下,这并不是最佳选择,甚至不安全。例如,第三方应用程序希望连接到Web应用程序,无论是来自移动设备、另一个网站、桌面还是其他情况。在这种情况下,允许第三方应用程序存储用户/密码组合被认为是不安全的,因为它将攻击面扩展到他们手中,超出了您的控制范围。为了解决这个问题以及其他用例,有几种认证协议可以保护您免受用户数据暴露给攻击者。

OAuth

开放授权(OAuth)是一种协议,允许应用程序以用户身份向服务器进行认证,而无需密码或充当身份提供者的任何第三方服务器。它使用服务器生成的令牌并规定了授权流必须如何发生,以便客户端(例如移动应用程序)可以告诉服务器哪个用户正在使用该服务。

建议使用和实施OAuth 2.0,因为第一个版本(OAuth 1.0)已被发现容易受到会话固定攻击。

OAuth 2.0 依靠 HTTPS 进行安全保障,目前被 Facebook、Google、Twitter 和 Microsoft 等公司的 API 使用和实施。OAuth 1.0a 使用起来更困难,因为它需要使用加密库进行数字签名。但是,由于 OAuth 1.0a 不依赖 HTTPS 进行安全保障,它可能更适合风险较高的交易。

OpenId

OpenId 是一种基于 HTTP 的协议,它使用身份提供者来验证用户是否是其所声称的身份。它是一个非常简单的协议,提供了一种由服务提供商发起的单点登录(SSO)方式。这允许用户重复使用分配给可信 OpenId 身份提供者的单一身份,并在多个网站上保持相同的用户身份,而无需向任何网站提供密码,除了 OpenId 身份提供者。

由于其简单性和对密码的保护,OpenId 得到了很好的采纳。一些知名的 OpenId 身份提供者包括 Stack Exchange、Google、Facebook 和 Yahoo!。

对于非企业环境,只要身份提供者值得信赖,OpenId 被认为是安全且通常更好的选择。

SAML

安全断言标记语言(SAML)通常被认为与OpenId竞争。最推荐的版本是2.0,因为它功能非常完善并提供强大的安全性。与OpenId一样,SAML使用身份提供者,但与OpenId不同的是,它是基于XML的,并提供更大的灵活性。SAML基于浏览器重定向发送XML数据。此外,SAML不仅由服务提供者发起;它也可以由身份提供者发起。这允许用户在不同门户之间导航,同时仍保持认证状态而无需进行任何操作,从而使过程透明化。

虽然OpenId占据了大部分消费市场,但SAML通常是企业应用程序的选择,因为很少有OpenId身份提供者被认为是企业级的(这意味着它们验证用户身份的方式不符合企业身份所需的高标准)。SAML更常用于企业内网网站,有时甚至使用内网服务器作为身份提供者。

在过去的几年中,SAP ERP和SharePoint(SharePoint通过Active Directory Federation Services 2.0)等应用程序已决定使用SAML 2.0认证作为Web服务和Web应用程序需要企业联合时首选的单点登录实现方法。

另请参见:SAML安全备忘录

FIDO

快速身份在线(FIDO)联盟创建了两种协议来促进在线认证:通用认证框架(UAF)协议和通用第二因素(U2F)协议。UAF侧重于无密码认证,而U2F允许向现有基于密码的认证添加第二个因素。这两种协议都基于公钥加密挑战-响应模型。

UAF 利用设备上现有的安全技术进行认证,包括指纹传感器、摄像头(面部生物识别)、麦克风(语音生物识别)、可信执行环境(TEE)、安全元件(SE)等。该协议旨在将这些设备功能接入一个通用的认证框架。UAF 适用于原生应用程序和 Web 应用程序。

U2F 通过使用硬件令牌(通常是USB)增强基于密码的认证,该令牌存储加密认证密钥并将其用于签名。用户可以将相同的令牌作为多个应用程序的第二因素。U2F 适用于 Web 应用程序。它通过使用网站的URL查找存储的认证密钥来提供防钓鱼保护

密码管理器

密码管理器是自动化管理大量不同凭据的程序、浏览器插件或网络服务。大多数密码管理器都具有允许用户轻松在网站上使用它们的功能,方法是:(a)将密码粘贴到登录表单中,或者(b)模拟用户键入密码。

Web应用程序不应通过遵循以下建议来使密码管理器的工作变得不必要地困难:

  • 使用标准HTML表单进行用户名和密码输入,并使用适当的type属性。
  • 避免使用基于插件的登录页面(如Flash或Silverlight)。
  • 实施合理的密码最大长度,至少64个字符,如实施适当的密码强度控制部分所述。
  • 允许密码中使用任何可打印字符。
  • 允许用户粘贴到用户名、密码和MFA字段中。
  • 允许用户通过单次按下Tab键在用户名和密码字段之间导航。

更改用户的注册邮箱地址

用户电子邮件地址经常发生变化。以下是处理系统此类情况的推荐流程:

注意:对于启用了多因素认证的情况,流程的严格性较低,因为身份证明比仅依赖密码更强。

  1. 确认用户认证cookie/令牌的有效性。如果无效,则显示登录屏幕。
  2. 向用户描述更改注册电子邮件地址的流程。
  3. 要求用户提交新的建议电子邮件地址,确保其符合系统规则。
  4. 请求使用多因素认证进行身份验证。
  5. 将建议的新电子邮件地址存储为待定更改。
  6. 创建并存储两个有时限的nonce,分别用于(a)系统管理员通知和(b)用户确认。
  7. 发送两封包含这些nonce的链接的电子邮件

    • 一封仅通知的电子邮件发送到当前地址,提醒用户即将发生的更改,并提供一个链接以报告意外活动。

    • 一封需要确认的电子邮件发送到建议的新地址,指示用户确认更改,并提供一个链接以处理意外情况。

  8. 相应地处理来自链接的响应。

  1. 确认用户认证cookie/令牌的有效性。如果无效,则显示登录屏幕。
  2. 向用户描述更改注册电子邮件地址的流程。
  3. 要求用户提交新的建议电子邮件地址,确保其符合系统规则。
  4. 要求用户提供当前密码进行身份验证。
  5. 将建议的新电子邮件地址存储为待定更改。
  6. 创建并存储三个有时限的nonce,分别用于系统管理员通知、用户确认和密码依赖的额外步骤。
  7. 发送两封包含这些nonce的链接的电子邮件

    • 一封需要确认的电子邮件发送到当前地址,指示用户确认更改,并提供一个链接以处理意外情况。

    • 一封单独的需要确认的电子邮件发送到建议的新地址,指示用户确认更改,并提供一个链接以处理意外情况。

  8. 相应地处理来自链接的响应。

关于上述流程的注意事项

自适应或基于风险的认证

更高级的应用程序的一个特点是能够根据各种环境和上下文属性(包括但不限于所请求访问的数据的敏感性、一天中的时间、用户位置、IP地址或设备指纹)要求不同的认证阶段。

例如,应用程序可能要求从特定设备首次登录时进行MFA,但后续从该设备登录时则不需要。或者,单点登录解决方案可能会认证用户并允许他们保持登录一天,但如果他们尝试访问个人资料页面,则需要重新认证。

另一种选择是相反的方法,应用程序允许低风险访问,只需识别设备(例如,特定的移动设备指纹,来自先前IP地址的持久cookie和浏览器指纹等),然后逐渐要求对更敏感的操作进行更强的身份验证。一个例子可能是允许某人触发查看他们当前的银行余额,但不允许查看账户号码或其他任何信息。如果他们需要查看交易,应用程序会让他们通过一些基本级别的身份验证,如果他们想进行任何资金转移,则需要MFA。

实施此类机制时应考虑的问题包括:

  • 所制定的策略是否符合任何公司政策,特别是任何监管政策。
  • 我们将在会话开始时监控哪些用户或设备属性(IP、地理位置、设备指纹、时间、行为生物识别等)?
  • 哪些信号需要在活跃会话期间刷新,以及刷新频率如何?
  • 我们将如何确保每个信号的准确性并处理缺失或低置信度的数据?
  • 什么评分模型(权重、阈值、机器学习、基于规则、混合)将把原始信号转换为风险等级?
  • 模型将在何处运行(边缘、API 网关、中央服务),以及我们的延迟预算是多少?
  • 每个风险等级对应什么操作(允许、验证码、MFA升级、阻止、撤销会话)?
  • 每项操作将附带哪些面向用户的消息和错误代码?
  • 我们将在哪个确切的代码或平台层调用风险引擎(登录控制器、中间件、API 网关、服务网格)?
  • 我们如何跨 Web、移动和 API 客户端一致地传播决策?
  • 当中途会话风险检查升级时,我们如何修改、扩展或撤销令牌/cookie?
  • 我们如何跨多个并发设备或浏览器标签同步状态?
  • 将有哪些监控和警报机制用于潜在可疑活动,包括如何通知用户。