OAuth 2.0 MAC Tokens
摘要
这个文档阐明了(specifies)HTTP MAC访问身份验证方案(scheme),一个HTTP认证方法使用一个MAC算法为部分HTTP请求提供了密码鉴定(cryptographic verification)。为了能和使用Access tokens方式一样,该文档定义了一个OAuth 2.0。
1. 简介
该文档阐明了(specifies)HTTP MAC访问身份验证方案(scheme),提供了发起已认证的HTTP请求(使用到了部分密码鉴定),涉及到了HTTP方法、请求URI和主机(host)。
与HTTP基本的访问认证方案(RFC2617)类似,MAC方案使用包含身份(identifier)和秘钥(key)在内的一组客户端证书(credentials)。然而,和基本的方案相比秘钥是不被包含在认证请求内的,只是将key用于计算请求MAC值而已,这个MAC会包含在认证请求中。
MAC方案需要在客户端和服务端之间建立起一个共享对称秘钥(shared symmetric key)。该规范提供了一个方法,该方法以MAC-type access token的形式使用OAuth 2.0给客户端分发一组MAC证书。
这种机制的主要设计目标是为服务简化、改善HTTP认证,比如不想使用或者不能为每一个请求使用TLS。特别的,该机制利用一个初始化TLS准备阶段来在服务端和客户端之间建立起一个共享secret。随后该共享secret就可以在不安全的通道中提供保护,免受网络攻击者攻击。
特别地,当一个服务使用该机制,网络攻击者将不能窃取用户的session token,其它的如cookies和bearer tokens可能会被窃取。此外,该机制还能保护泄漏掉的session token(当通过一个安全通道发送到错误的服务器)。例如,当一个客户端使用某种动派配置的方式来决定是否发送一个已认证的请求,或者当客户端验证服务端身份(作为TLS握手的一部分)失败的情况下。
不像HTTP摘要认证方案,该机制不需要与服务端进行互动来防止重放攻击(replay attacks)。取而代之的是,客户端提供一个nonce和一个timestamp,服务端可以使用一个有界的存储和nonce以及timestamp来防止重放攻击。此外,不像摘要(digest),该机制目的不是为了保护用户者本身的密码,因为客户端和服务端可以不受限制的获取关键的信息。服务端应该在TLS初始化准备阶段为该机制分发一个短期的证书衍生物。
1.1 例子
客户端尝试在没有认证的情况下访问一个受保护的资源,对资源服务发起如下HTTP请求:
GET /resource/1?b=1&a=2 HTTP/1.1
Host: example.com
资源服务器用以下信息响应,以质疑客户端身份的合法性:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: MAC
客户端为了在http://example.com/
服务端上访问资源预先湖区了一组MAC证书。颁发给客户端的MAC证书包括以下属性:
MAC key identifier: h480djs93hd8
MAC key: 489dks293j39
MAC algorithm: hmac-sha-1
客户端通过计算一个timestamp(距离1970年1月1号凌晨过去多少秒)和生成一个作为nonce的随机字符串方式构造认证头:
Timestamp: 1336363200
Nonce: dj83hs9s
客户端构造规范化的请求字符串(“\n”换行符目的仅为)
1336363200\n
dj83hs9s\n
GET\n
/resource/1?b=1&a=2\n
example.com\n
80\n
\n
请求的MAC值是使用标准的MAC算法hmac-sha-1
计算出的。结果是用base64-encoded来产生请求MAC的:
bhCQXTVyfj5cmA9uKkPFx1zeOXM=
客户端包含MAC key identifier,nonce,和request MAC。在请求头塞入Authorization
信息:
GET /resource/1?b=1&a=2 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
ts="1336363200",
nonce="dj83hs9s",
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
服务端基于接收到的信息通过再次计算请求MAC验证请求,判断其有效性。如果验证通过,则服务端返回客户端请求的资源。
1.2 符号约定
关键字MUST,MUST NOT,REQUIRED,SHALL,SHALL NOT,SHOULD,SHOULD NOT,RECOMMENDED,MAY,以及OPTIONAL。
2. 颁发MAC证书
该规范使用OAuth 2.0为颁发MAC 证书提供了一个方法。该规范不会授权给服务端,以便让服务端能提供颁发MAC 证书的其它特殊方法(其余方法可能被定义并被使用)。MAC证书无论在何时别颁发,证书必须包含以下属性:
MAC key identifier
一个MAC key identifier字符串被用来计算请求MAC。该字符串对客户端来说一般不透明(可以看见)。典型地,服务端一般会给每一组MAC证书赋予一个具体的范围和生命时长。identifier可能表示一个唯一的被用来检索认证信息的值(例如从数据库中检索),或者一个可进行验证的独立的认证信息(即一个字符串包含一个签名和其它一些信息).
MAK key
作为MAC算法秘钥的共享对称秘钥。服务端MUST NOT重新发型一个之前已经发行的MAC key或MAC key的结合物。
MAC 算法
一个MAC算法是用来计算请求MAC值的。值必须为hmac-sha-1
,hmac-sha-256
或者在Section 7.1登记过的算法。算法名称大小写敏感。如果客户端不识别MAC算法,客户端MUST NOT使用MAC证书,就好像MAC证书没有颁发过一样继续执行下去。
3. 发起请求
为了发起已认证的请求,客户端必须持有一个有效的MAC证书,并传给服务端。客户端通过接收一组入参属性,构造出request请求参数,并放到头部的Authorization内。
3.1 Authorization请求头
Authorization请求头的字段使用RFC2617定义的架构,如下所示:
credentials = "MAC" 1*SP #params
params = id / ts / nonce / ext / mac
id = "id" "=" string-value
ts = "ts" "=" ( <"> timestamp <"> ) / timestamp
nonce = "nonce" "=" string-value
ext = "ext" "=" string-value
mac = "mac" "=" string-value
timestamp = 1*DIGIT
string-value = ( <"> plain-string <"> ) / plain-string
plain-string = 1*( %x20-21 / %x23-5B / %x5D-7E )
- id。REQUIRED。是MAC key identifier。
- ts。REQUIRED。请求的时间戳。MUST正整数,MUST NOT以0起头,是1970-1-1 00:00:00距今的秒数。
- nonce。REQUIRED。由客户端产生唯一字符串。在所有具有相同时间戳和MAC密钥标识符组合的请求中,该值必须是唯一的。
- ext。OPTIONAL。是用来包含额外信息的字符串。该字符串所包含的内容和格式超出了本文所讨论的规范的范围。
- mac。REQUIRED。是HTTP请求MAC。属性MUST NOT出现两次或两次以上。属性的值只能为ASCII的子集。
3.2 请求MAC
客户端使用MAC算法,以及用MAC key来计算请求的MAC值。本文所讨论的规范定义了两个算法:hmac-sha-1
和hmac-sha-256
,以及其它注册过的算法。
3.2.1 规范化的请求字符串
规范化的请求字符串是一个始终如一的、可再生的、由资格HTTP请求元素拼接而成的单一字符串。通过将请求规范化成一个可再生的字符串,客户端和服务端都可以在同样的值上计算出请求MAC值。
该字符串是通过按顺序拼接被构造起来的,以下HTTP请求元素,每一行末尾都是换行符:
- 为请求而计算出来的timestamp。
- 为请求而产生的nonce。
- 大写的HTTP方法,如POST,HEAD等。
- 在RFC2616区域内定义的HTTP请求的URI。
- 在HTTP请求内的hostname。使用小写形式的请求头内的header字段。
- 在HTTP请求内的端口号,假如header字段不包含该值,则使用默认端口值,如HTTP是80端口,HTTPS是443端口。
- 如果请求中有值,则会放在请求头的
ext
,Authorization
字段对应的值处,如果请求中没有值,则为空串。
每一个元素的后面紧跟的是换行符,即使该元素是空串。
例如,HTTP请求为:
POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q HTTP/1.1
Host: example.com
Hello World!
使用timestamp:64095
,nonce:7d8f3e4a
和扩展字符串a,b,c
,规范化后成为:
264095\n --timestamp
7d8f3e4a\n --nonce
POST\n --HTTP METHOD NAME
/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q\n --HTTP URL
example.com\n --Hostname
80\n --port
a,b,c\n --ext
3.2.2 hmac-sha-1
hmac-sha-1
使用的是RFC2014内定义的HMAC-SHA1算法:
mac = HMAC-SHA1(key,text)
其中
text是3.2.1中秒速的规范化请求字符串;
key是服务端提供的MAC key。
mac是mac属性的值。
3.2.3 hmac-sha-256
hmac-sha-256
使用的是RFC2014内定义的HMAC-SHA1算法:
mac = HMAC-SHA256(key,text)
其中
text是3.2.1中秒速的规范化请求字符串;
key是服务端提供的MAC key。
mac是mac属性的值。
4. 验证请求
服务端接收到认证请求,通过执行以下必须的步骤验证其合法性:
- 和section3.2描述的一样,重新计算请求MAC值,并通过与从客户端中接收到的mac值进行对比。
- 确保从客户端中接收到的timestamp、nonce、mac key identifier的组合是唯一的,即不与之前接收到的组合一样。服务端如果接收到和4.1section描述一样的timestamp则会拒绝。
- 验证范围和MAC credentials的有效性。如果请求验证失败,服务端SHOULD用401(Unauthorized)HTTP status code响应。
4.1 timestamp有效性验证
timestamp,nonce,和key identifier的组合提供了一个唯一的可以让服务端防止重放攻击的标识(identifier)。如果没有重放攻击保护机制,一个attackers可以使用这个组合(有效的、合法的已经认证过的)请求多次,长期访问受保护的资源。
包含nonce的时间戳通过让服务端能够限制拒绝具有旧时间戳的请求的时间段的方式移除了保留无限数量的nonce值,以供将来检查的需要。如果执行这样的限制,服务器端MUST:
- 服务端第一次从客户端接收到请求(包含MAC key identifier),计算出服务端和客户端时间戳(单位秒)的差别(request time delta)。只要MAC密钥凭据有效,则MUST保留请求时间增量的差异。
- 对于客户端接下来的请求,根据请求时间差(request time delta)计算出要调整的请求时间—即由客户端产生请求MAC的时间。然后调整服务端的时钟(clock)。
- 验证调整后的请求时间是在服务端所定义的允许的范围之内。服务器应该允许有足够大的窗口来容纳网络延迟(在客户端发起请求的时间到服务端接收请求并处理的时间段)。
4.2 WWW-Authenticate
响应头字段
如果受保护的资源请求没有包含已经认证的凭证(credentials),即包含一个无效的MAC key identifier,服务端SHOULD包含 WWW-Authenticate
响应头字段。例如
HTTP/1.1 401 Unauthorized
WWW-Authenticate: MAC
WWW-Authenticate
请求响应头使用在RFC2617中定义的框架如下所示:
challenge = "MAC" [ 1*SP #param ]
param = error / auth-param
error = "error" "=" ( token / quoted-string)
每一种属性MUST NOT出现多于一次。
如果受保护的资源请求包含一个MAC Authorization请求头并且验证失败,服务端MAY包含error属性以提供一种可阅读的解释,解释为何访问遭到拒绝,这样也就间接帮助客户端编程人员定位到问题。例如:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: MAC error="The MAC credentials expired"
5. 使用OAuth 2.0
OAuth 2.0(RFC6749)定义了一个可扩展的基于token的认证框架。可以通过以发布MAC-type access token的方式来使用MAC认证方案以发起基于OAuth的请求。
该规范不会为了客户端定义一个从授权服务端中请求一个MAC-type的token的方法。此外,它不包括用于识别资源服务器支持哪些HMAC算法的任意侦探(discovery)设施,或客户端如何为受保护资源获取MAC access token 。
5.1 发布MAC-type access token
每当一个响应包含access tokens
参数,授权服务器颁发MAC-type access tokens 时MUST包含以下参数:
access_token
REQUIRED. The MAC key identifier.
mac_key
REQUIRED. The MAC key.
mac_algorithm
REQUIRED. 用于计算 request MAC的 MAC 算法.
值必须为 "hmac-sha-1", "hmac-sha-256", 或者在section7.1中登记着的扩展算法。
如:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token":"SlAV32hkKG",
"token_type":"mac",
"expires_in":3600,
"refresh_token":"8xLOxBtZp8",
"mac_key":"adijq39jdlaska9asud",
"mac_algorithm":"hmac-sha-256"
}
6. 安全考虑
和RFC2617中所陈述的那样,最大的风险来源不是来自于核心协议本身而是在其使用的政策和程序当中,强烈建议实施者评估该协议如何解决其安全需求。
6.1 MAC key的传输
该规范描述了两种获取或传输MAC keys的机制,当发送MAC keys到客户端时,两者都需要使用传送层安全(transport-layer security)机制。用户获取MAC凭证的方法必须通过使用传送层机制如TLS或SSL来保证传输是在保护之下的。
6.2 请求的机密性
虽然该协议为请求提供了完整性的验证机制,但是它并没有保证请求的机密性。除非进行更进一步的预防,否则窃听者将能完全访问请求内容。服务器应该谨慎地区分出将要发送的请求种类,并且应该为敏感性资源提供保护,比如说利用SLS。
6.3 伪造服务器的欺骗
该协议不会对服务器的真实性进行尝试性验证。敌对的第三方服务器可以充分利用这种便利,即通过拦截客户端的请求并返回误导性或者不恰当的信息。当使用这种协议进行开发时,服务提供者应当考虑这种攻击,并为任何请求(服务器不真实或者响应值正确)应用TLS。
6.4 明文存储凭证
MAC 关键功能在传统的身份认证上和密码一样。为了计算请求MAC值,服务端必须可以以明文方式读取MAC key。相反,例如现代操作系统仅存储用户凭据的单向散列。
如果一个攻击者可以取访问这些MAC keys-甚至更糟糕,存储这些MAC keys的服务器数据库-他或她将能在任意资源上执行任何操作。因此,服务器保护这些MAC密钥免受未经授权的访问至关重要。
6.5 MAC key的熵
除非使用TLS协议,否则窃听者将能完全访问经过身份验证的请求以及请求MAC值,因此窃听者也可以暴力破解以恢复所使用的MAC keys。
服务器应该谨慎地分配足够长、足够随机的MAC密钥,以抵抗这种攻击(至少在MAC凭证有效的时间段内)。
比如说,如果MAC凭证两周有效,服务器应当保证暴力破解所花费的时间少于两周。当然,服务器应该宁可谨慎地选择最长的MAC key。
用于产生这些MAC keys的伪随机数字生成器的质量同样重要。很多伪随机数据生成器看起来随机,实际上,进行密码分析或者暴力破解十分容易。实现者应当使用机密、安全的伪随机数据生成器以避免这些问题。
6.6 拒绝服务/资源耗尽攻击
该规范包括许多可能使服务器耗尽资源的功能。例如,该协议需要服务器追踪使用过的nonces。如果一个攻击者能够讯速地使用很多nonces,追踪它们所需的资源可能会耗尽可用的容量。再一次,该协议可以要求服务器执行高昂的计算以便验证请求MAC值。攻击者可能利用这点特性,通过发送一大堆无效请求的方式来进行拒绝服务攻击。
资源枯竭攻击绝对不属于本规范。 然而,实施者应该谨慎地考虑该协议所暴露的额外的攻击途径,并相应地设计其实现。例如,熵饥饿(entropy starvation )通常导致完全拒绝服务,同时系统等待新的熵,或者在弱(容易猜到的)MAC密钥中。当实现这一协议时,服务器应当考虑对于他们的程序而言哪一个更具风险并相应地设计其实现。
备注:熵指的是一池子的随机数。熵饥饿指的是消费随机数的能力>可供选用随机数。
6.7 时间攻击
该规范充分利用HMACs,其中签名验证涉及将接收到的MAC字符串与预期的字符串进行比较。如果字符串比较运算符是根据输入在可观察、不同的时间内运行,例如,字符串的比较是按字符比较的,如果两个字符串匹配失败则返回一个负数,则可以利用该定时信息来逐个确定期望的MAC。
鼓励服务实施者使用固定时间字符串比较器进行MAC验证。
Timing attacks(时间攻击)是一种通过用不同的查询,以统计分析发起请求到响应所花费的时间,以推断出某些信息。例如:
"hunter2" == "password123" # False. 51μs
F
"hunter2" == "obama" # False. 50μs
F
"hunter2" == "havana" # False. 73μs
TF
"hunter2" == "humana" # False. 90μs
TTF
...
"hunter2" == "hunter1" # False. 170μs
TTTTTTF
"hunter2" == "hunter2" # True. 190μs
TTTTTTT
字符串相似程度越高,所花费时间越久。这样就可以推断出目标字符串是什么。
解决办法:
1. 即使第一个字符不匹配,也比对所有的字符,然后才把结果返回。
2. 长度不匹配直接返回结果。
参考网址:https://thisdata.com/blog/timing-attacks-against-string-comparison/
6.8 CSRF攻击
当evil.com站点在受害者的浏览器中加载URL或提交表单到发生副作用的网站时跨站点请求伪造攻击(Cross-Site Request Forgery attack)便会出现,例如资金转移,状态消息变更等。为了防止这种攻击,网站可以使用各种技术来确定请求的发起者确实是站点本身,而不是第三方。经典的方法是在一组URL参数或表单内容中包含由服务器生成并绑定到用户session的nonce串,这表明只有服务器可能已经触发了该操作。
最近,Origin HTTP header被推荐,并在一些浏览器中部署了。该header表明了请求方的方案,主机和端口。 某些Web应用程序可能会使用此Origin HTTP header作为对CSRF的防御。
为了简化此规范,HTTP header不是MAC化字符串的一部分。因此,MAC认证无法抵御header欺骗,使用Host header来防御CSRF攻击的网站无法使用MAC认证来防范活动网络攻击者。 想要完全保护MAC认证的站点应该使用传统的,绑定cookie的CSRF防御
6.9 覆盖范围的局限性
规范化请求字符串被设计为支持在本规范中定义的认证方法。设计其他方法的用户应评估标准化请求字符串与其安全性要求的兼容性。由于规范化请求字符串不涵盖整个HTTP请求,所以服务器应该采用其他机制来保护这些元素。
请求MAC不覆盖整个entity-header field,通常会影响服务器解释执行request body。如果服务器的行为受到这种header fields的影响,攻击者可以在不被检测(侦测到)到的情况下操纵请求头。
名词解释
MAC: Message Authentication Code 消息认证码。
TLS: Transport Layer Security 传输层安全。