Restful HMAC认证

咱们在设计REST(Representational State Transfer)风格的Web service API,有一个问题常常要考虑,就是如何设计用户认证的体系(Authentication). 缓存

比较传统的作法是首先有一个登录的API,而后服务器返回一个session ID,后续的操做客户端都必须带上这个session ID,可是这样的,服务就变成了有状态了,不符合REST风格的原则。另外,因为负载均衡的存在,必须有公共存储来保存用户的Session,这也增长了系统的复杂度。 安全

因此比较好的作法是每次都传递认证信息,这样系统就是无状态的,固然因为每次都须要认证,必然下降了一些效率,必要的时候要考虑缓存用户信息在服务器端。 服务器

有几点要注意: session

1.密码不能传播 负载均衡

一个比较低级的错误是通信时,由客户端传递用户名和密码到服务器端认证,这样很容易被黑客攻击形成密码泄露。 设计

标准的作法是使用HMAC(Hash-based Message Authentication Code),想法就是不传播password,而传播content和password的混合hash值。咱们来看看Amazon S3怎么作认证的。 code

Amazon对每个用户有一个AWSAccessKeyId和一个AWSSecretAccessKey,每次HTTP请求须要一个Id和一个Autherticantion信息。 好比: 同步

GET /photos/puppy.jpg HTTP/1.1 
Host: johnsmith.s3.amazonaws.com 
Date: Tue, 27 Mar 2007 19:36:42 +0000 Authorization: AWS 0PN5J17HBGZHT7JJ3X82: xXjDGYUmKxnwqr5KXNPGldn5LbA= 
这个Authorization的头是这样产生的: 其中YourSecretAccessKeyID用的就是AWSSecretAccessKey。 
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; 
Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( YourSecretAccessKeyID, StringToSign ) ) ); 

StringToSign = HTTP-Verb + "\n" + 
Content-MD5 + "\n" + 
Content-Type + "\n" + 
Date + "\n" + 
CanonicalizedAmzHeaders + 
CanonicalizedResource; 

CanonicalizedResource = [ "/" + Bucket ] + 
<HTTP-Request-URI, from the protocol name up to the query string> + 
[ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; 
CanonicalizedAmzHeaders = <described below> 

这样服务端就很容易根据用户信息来验证信息的正确与否。 string

  1. 验证信息的位置 hash

验证信息能够放在HTTP HEADER里面也能够放在HTTP URL里面,象这样: 

GET /photos/puppy.jpg?AWSAccessKeyId=0PN5J17HBGZHT7JJ3X82&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D HTTP/1.1 
Host: johnsmith.s3.amazonaws.com 
Date: Mon, 26 Mar 2007 19:37:58 +0000 

放在HTTP HEADER里面的好处是URL比较干净整洁,适合放在internet与人分享,而放在URL里面则有利于发布私有的访问权限给第三方。 

  1. 如何防范重放攻击(Replay attack)? 

理论上,黑客能够窃取你的通信报文,而后从新发送来经过认证。有几种可能的solution. 

  1. 客户端因此向服务器申请一个随机数,而后这个随机数做为下次通信的key,一旦使用事后就当即失效,也就是所谓的”一次一密”。这种方法的好处是很安全,可是增长通信量,并且因为负载均衡的存在,必须有公共存贮保存这个key。 

b.服务器端保存使用过的authertication信息,只要是使用过的就拒绝再次使用。这种方法不须要客户端支持,可是须要公共空间来保持历史记录。 

c.使用时间戳。作法就是认证信息中含有时间信息,这样服务器端就能够拒绝时间相隔太长的请求,认为其已通过期。这种作法须要服务器端和客户端有某种形式的时间同步。 

4.要不要使用HTTPS? 

若是安全度要求很高或者是针对internet的API,无疑应该使用HTTPS,来避免内容被窃取的可能。 

若是只是在局域网范围或者可信赖的计算环境,则使用HTTP来提升一点效率。 

相关文章
相关标签/搜索