$ ls ~yifei/notes/

HTTP 认证介绍

Posted on:

Last modified:

周末给一个库添加 http 代理的支持,发现对 http basic auth 不甚了解,阅读了一下相关的文档, 写篇备忘。

http 中的认证主要是 basic auth 和 digest auth 两种,其中 digest auth 比较复杂,而且也没有 提升安全性,已经不建议使用了。

RFC 7235 [1] 描述了客户端(通常是浏览器)和服务器如何通过 http 进行身份认证的一些机制。 客户端和 http 代理之间也可以使用 http auth 来做验证。  

验证流程

  1. 当客户端访问一个页面时,如果只有验证后才能访问,或者验证后有更多内容,服务器应该发送 401 Unauthorized,提出一个 challenge,设定 WWW-Authenticate header,并指定验证的 type 和 realm,具体定义下文有讲。
  2. 客户端这时通常应该提示用户输入密钥,一般是浏览器弹出用户名密码对话框供用户填写,然后 使用Authorization header 发送验证的密钥。如果验证通过的话,应该正常访问(200 OK), 验证通过但是没有权限的话应该返回 403 Forbidden。
  3. 如果验证不通过,应该服务器返回 401,客户端可以重试。

注意,如果客户端已经知道需要密钥访问,那么可以在第一个请求直接发送对应的密钥,这样就避免了 401 Unauthorized。

MDN 上的流程图  

代理验证的不同

如果代理服务器需要验证的话,流程是类似的,有两点细节不同:

  1. 代理服务器应该发送 407 Proxy Authentication Required 而不是 401。使用的 headers 也变成 了 Proxy-Authenticate 和 Proxy-Authorization 。
  2. 服务器的头部 WWW-Authenticate 是 end-to-end 的,也就是代理服务器不应该篡改,应该原样 传递。而代理服务器的 Proxy-头部是 hop-by-hop 的,也就是不能向下传递。

实现细节

服务器或者代理服务器随着 4XX 发送的头部为

WWW-Authenticate: <type> realm=<realm>
or
Proxy-Authenticate: <type> realm=<realm>

其中 type 指定了使用的验证的类型,也就是用户名和密码加密方式的不同,IANA 钦定了一批方法 [2]。然鹅,一般来说常用的只有两个 Basic 和 Digest。而其中 Digest 的实现可能会要求服务器 明文存储密码,于是大家又 angry 了 [3],这里也不推荐使用。所以这里只介绍 Basic 类型。

realm 指定了验证的领域,也就是说相同 realm 下的用户名和密码是一样的,如果你访问的两个页面 在同一个 realm,那么浏览器在第二次访问就不会问你密码了。

客户端发送对应的头部和密钥来获得访问权限

Authorization: <type> <credentials>
or
Proxy-Authorization: <type> <credentials>

其中,type 就是刚刚的那个 Basic 或者 Digest。credentials 按照对应的方法计算。对于 Basic 类型 credentials = base64(username + ':' + password)

一个例子,假设用户名和密码分别是:aladdin 和 opensesame。那么客户端应该发送的 header 是: Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

需要注意的地方

  1. 因为 http 协议本身是无状态的,所以 Auth 应该是无状态的,每次请求都应该携带。

  2. 如果是 http 协议的话,对于 Basic Auth,那么密码都是明文发送的,可以使用 https 来避免 这个问题。

  3. 可以使用:https://username:password@www.example.com/ 这种形式来预先输入账号密码,但是 这种形式已经不鼓励了。不过在设定一些环境变量时,比如 http_proxy,也只能用这种方法来制定 用户名和密码

参考

  1. 对应的 RFC https://tools.ietf.org/html/rfc7235
  2. IANA 注册的 auth 类型 http://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
  3. 为什么不要使用 digest 验证  https://stackoverflow.com/questions/2384230/what-is-digest-authentication
  4. MDN 的文章还提供了如何让 apache 和 nginx 使用 basic auth https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
WeChat Qr Code

© 2016-2022 Yifei Kong. Powered by ynotes

All contents are under the CC-BY-NC-SA license, if not otherwise specified.

Opinions expressed here are solely my own and do not express the views or opinions of my employer.

友情链接: MySQL 教程站