基于Base64编码的HTTP Basic Authentication由于安全问题,已经不再广泛使用了。在云存储中,数据的安全性一直被广泛关注。亚马逊的AWS S3和Openstack Swift分别采取了不同的算法来对每一个HTTP请求进行鉴权。以下是二者的鉴权过程:
一、AWS S3的HTTP请求鉴权流程
AWS采取的鉴权算法类似于HTTP基本认证。我们知道Base64只是对字符串进行了一个转换存储,是可以反向解析出源字符串的,因此基本认证中使用Base64编码处理过的用户名和密码可以被截获,一旦用户名和密码泄漏,黑客可以构造任何需要的请求进行数据窃取和改写。AWS采用的是签名认证的思想来解决这一问题。
基本原理:
1.客户端将请求中的通用信息(如:Bucket、Object、请求时间戳和请求方法名等)和Secret ID进行SHA256哈希计算得到一个字符串;
2.最终在HTTP请求中传输的是该HASH值。其中Access Key在请求中以明文传输;
3.服务端拿到该请求后,首先提取出Access Key,然后根据Access Key到服务端数据库中查询创建租户时分配给该租户的Secret ID;
4.服务端从请求中提取通用信息,配合查询得到的Secret ID,使用同样签名计算过程计算一个签名,然后与请求中携带的签名进行比对,二者一致则认为该请求是合法请求,鉴权通过。否则返回403鉴权失败。
如果整个HTTP请求被截获,黑客虽然能得到该鉴权值,但是无法反解析出用户的Secret ID,因为SHA是不可逆。因此最坏的情况:可以重复发送该请求(不修改请求中任一参数)到服务端,攻击范围非常有限。
假设,黑客想使用该鉴权值伪造新的请求,那么修改请求中的通用信息,而签名值没有改变,最终鉴权也无法通过。
那么是不是黑客可以一直使用该鉴权发送该请求呢?也不是的,AWS S3拿到请求后会比对服务端的时间与请求中的时间的差值,如果该请求的发出时间比服务端的时间早15分钟,则认为该请求为非法请求。客户端必须以新的时间戳来重新生成新的HASH值,再发送请求。
从上面的过程来看,AWS的鉴权算法非常好的解决了密钥泄漏和每一个请求都能得到鉴权的问题。
二、再来看基于Keystone的Openstack Swift的HTTP请求鉴权流程
Keystone的原理比较简单,整个系统提供全局唯一的Keystone服务,客户端在发送HTTP请求之前,首先需要向Keystone申请一个Token(定长的字符串),该Token的有效期由Keystone服务端来指定。申请Token时,需要向Keystone提供用户名和密码,这里可以理解成AWS中的Access Key和Secret ID,Keystone认证通过该用户之后,发放Token给客户端。之后客户端每次发送HTTP请求时都必须携带该Token,Swift拿到该Token和用户名信息后,也会像Keystone查询该Token是否有效。Token有效,则继续处理该业务,Token无效,则返回鉴权失败。具体的流程可以从如下序列图看出:
这样的鉴权过程存在一些问题:
1.相比于AWS的鉴权,这里如果Token泄漏,会造成比较严重的后果,虽然Token有有效期,但是每次都需用用户名和密码去申请,频繁申请也有可能会造成密钥的泄漏;
2.每一次请求都需要Swift与Keystone之间作一次交互,性能可能存在问题。
事实上,Openstack就发生过多次Token永久有效的bug,导致数据被破坏。当然这样的架构也有其优点,Keystone可以在多个服务间共享,将鉴权逻辑集中管理,做到了服务级的重用,而AWS必须在每一个服务中解析和生成签名,只能做到模块或者代码级别的重用。