# 身份认证

  • 当服务器收到客户端的访问请求时,通常需要执行以下安全措施:
    • 身份认证 :识别客户端的身份。如果是一个已注册的用户,则让该客户端进入登录状态,否则视作未登录。
    • 用户授权 :当客户端登录成功之后,检查该用户的权限,判断允许访问哪些资源。
  • 本文介绍多种身份认证的方式。

# 密码登录

:用户访问网站,输入用户名、密码进行登录。

  • 为了避免密码被暴力破解,发现一个用户连续多次登录失败之后,通常禁止该用户登录一段时间。

# Basic Auth

:HTTP 协议定义的一种简单的身份认证方式。

  • 原理:HTTP 客户端将用户名、密码以明文方式发送给 HTTP 服务器,如果服务器认证通过则允许客户端访问,否则返回 HTTP 401 报文。
    • 例如,当用户使用 Web 浏览器访问该 HTTP 服务器时,通常会显示一个对话框,要求输入用户名、密码即可。
    • 实际上,HTTP 客户端会将 username:password 经过 Base64 编码之后,放在 HTTP Header 中发送给 HTTP 服务器。如下:
      curl 127.0.0.1 -H "Authorization: Basic YWRtaW46MTIzNA=="
      
    • 大部分 HTTP 客户端也支持按以下格式发送用户名、密码:
      curl http://username:[email protected]:80
      
    • Basic Auth 没有通过 Cookie 记录用户登录状态,因此浏览器重启之后,用户需要重新登录。
  • 优点:过程简单,容易实现。
  • 缺点:HTTP 协议以明文方式传输 Header ,容易泄露。因此使用 Basic Auth 时,应该采用 HTTPS 协议。
  • URL 中,username:password@host:port 三个字段的组合称为 authority 。

# 凭证登录

:服务器通过凭证验证用户的身份信息。

  • 常见的几种凭证:
    • cookie
    • session
    • JWT
    • SSL 证书
  • 虽然 HTTP 通信是无状态的,但可以通过 cookie 或 session 保存 HTTP 通信的某些信息。
  • 工作流程:
    1. Web 服务器将各个客户端的某些信息(比如用户名、凭证)保存在客户端的 cookie 文件中。
    2. 当客户端下一次发出 HTTP 请求时,可以在请求报文的 headers 中填入 cookie 数据,从而告知上一次 HTTP 通信的信息。
      • Web 浏览器访问某个网站时会自动使用、且仅使用该网站的 cookie ,将它填入请求报文的 headers 中。
  • cookie 保存在客户端上,可能被泄露、篡改、盗用,是不安全的。因此服务器应该采取以下措施:
    • 如果数据不重要,可以直接存放到 cookie 中。比如客户端上一次 HTTP 通信的状态。
    • 如果数据是需要保密的,则加密后再存放到 cookie 中。
    • 如果数据是客户端的某种凭证,则要防止篡改、伪造。还要设置过期时间,过期之后服务器就不认。

# session

  • 工作流程:
    1. Web 服务器将每个客户端的信息保存在服务器上,比如数据库、内存缓存中。只将 session id 发送给客户端,用于分辨客户端的身份。
    2. 客户端每次发出 HTTP 请求时,将 session id 放在 HTTP Header、body 或 URL 中,传给服务器。
    3. 服务器根据 session id 找到对应的 session ,载入该客户端的信息。
  • 优点:
    • session 存储在服务器上,因此不怕泄露,可以包含敏感信息。
    • session 应该设置过期时间,过期之后就删除。如果客户端再发送该 session id ,服务器不会认可。
  • 缺点:
    • 将 session id 存储在客户端的 cookie 中,依然可能被 CSRF 攻击。

# JWT

:JSON Web Token ,一个实现凭证登录的 API 规范,将 JSON 格式的消息编码成 token 。

  • JWT 的作用与 session 类似。相当于服务器将 session 的内容编码成 token ,发送给客户端。客户端每次发出 HTTP 请求时,可以带上该 token 。
  • 客户端可以将 token 存储在 cookie 中,也可以存储在内存或数据库中,这样还能防止 CSRF 攻击。

# 示例

  1. 生成 header :

    {
      "typ": "JWT",
      "alg": "HS256"
    }
    
  2. 生成 payload :

    {
        "username": "leo",
        "exp": 1577853296
    }
    
  3. 生成 signature :

    var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
    var signature = HMACSHA256(encodedString, 'secret');  // secret 用于加盐,需要保密
    
  4. 将上述 header、payload、signature 三部分依次拼接,用点号 . 分隔,就生成了 token :

    var token = base64UrlEncode(header) + '.' + base64UrlEncode(payload) + '.' + signature
    
  5. 将 token 放到 HTTP Header 中使用:

    'Authorization': 'Bearer ' + token
    

# 单点登录

:SSO(Single Sign On),指多个网站共用一个身份认证系统,使得用户只需登录一次,然后通过同一个身份凭证访问不同网站。

  • 优点:
    • 节约了用户登录多个网站的时间。
  • 缺点:
    • 增加了单点故障的风险。SSO 系统故障时,多个网站的用户登录都会失败。
  • 实现 SSO 的常见协议:
    • CAS(Central Authentication Service ,中央验证服务)
    • Kerberos
    • LDAP
    • OAuth
    • OpenID
    • SAML(安全断言标记语言):一个认证协议,通信内容采用 XML 格式。
    • SASL

# OIDC

:OpenID Connect ,一个实现 SSO 的协议。

  • 它基于 OAuth2 ,在授权的基础上,增加了对用户的身份认证。
  • 角色划分:
    • End User(EU):终端用户,用 OpenID 证明自己的身份。
    • OpenID Provider(OP):OpenID 提供方。
    • Relying Part(RP):OpenID 支持方,允许用户用 OpenID 登录自己的网站。
  • 工作流程:
    1. 用户访问 RP 网站,以 OAuth 登录方式跳转到 OP 网站。
    2. OP 发送 OAuth 授权码给 RP 。
    3. RP 根据授权码,向 OP 请求该用户的 access_token、id_token 。
      • id_token 一般有效期较短,需要根据 refresh_token 刷新。
    4. RP 根据 id_token ,向 OP 请求该用户的身份信息(UserInfo)。

# SASL

:简单认证和安全层(Simple Authentication and Security Layer),是一个进行身份认证的框架。

  • 1997 年发布,2006 年制定了 RFC 4422 (opens new window) 标准。
  • SASL 是一个抽象的认证层,介于应用程序与具体的认证机制之间。
    • 应用程序使用 SASL 时,可以切换到不同的认证机制,通用性更强。
  • SASL 支持多种认证机制,例如:
    • ANONYMOUS :表示未登录用户。
    • PLAIN :基于用户名 + 明文密码进行认证。
    • DIGEST-MD5 :基于用户名 + 密码哈希值进行认证。
    • EXTERNAL :使用外部信息来验证身份,比如通过 TLS 获取的验证信息。
    • GSSAPI :通常采用 Kerberos 协议来实现。
    • NTLM :Windows NT LAN Manager
    • OAUTHBEARER
    • SCRAM

# Kerberos

:一个实现 SSO 的协议。

  • 1980 年代由麻省理工学院发布。

  • Kerberos 服务器称为 KDC(Key Distribution Center ,密钥发放中心),分为两部分:

    • 身份认证服务器(Authentication Server ,AS):存储所有用户的密码,负责身份认证。
    • 票据授予服务器(Ticket Granting Service ,TGS):负责用户授权。
  • 业务应用的 client 访问 server 时,通过 Kerberos 进行身份认证的流程:

    1. client 向 KDC 请求身份认证。
    2. KDC 通过 client 的身份认证之后,回复一个证明身份的 Ticket(称为 Ticket Granting Ticket ,TGT),并用用户密码加密。
    3. client 解密 Ticket ,然后发送到 TGS ,请求访问某个 server 。
    4. TGS 回复一个允许访问该 client 访问 server 的 Ticket(称为 Server Ticket ,ST)。
    5. client 拿着授权 Ticket 去访问 server 。
  • 优点:

    • 属于第三方认证机制,避免了密码被业务服务器泄露。
    • 基于对称加密进行身份认证,避免了密码在网络传输时泄露。
    • Kerberos 服务器的 API 可以封装为 SASL 的 GSSAPI 再调用。

# 多因素身份认证

:MFA(Multi-Factor Authentication)。指同时使用多种方式来验证用户的身份。

  • 例如:
    • 当用户通过账号密码验证之后,再验证手机验证码,或硬件令牌、指纹。
    • 当用户使用 ATM 时,需要同时验证银行卡、密码。