一、概述
对外网暴露的RESTful API,由于是无状态的,如果不做认证,那就相当于裸奔的,任何人都可以调用,随意调用,这样是极不安全的。下面就RESTful API的安全性方案进行了一些研究。
(但是首先建议,核心系统的API不对外网暴露,只允许内网调用,而且不建议做成HTTP RESTful形式。如果非要使用RESTful API对外网暴露接口,那么请看下面)。
RESTful API的安全性,包括了如下三个方面:
a) 对客户端做身份认证
b) 各种安全防护措施
c) 身份认证之后的授权
1、对客户端做身份认证
面向最终用户的API,采用HTTPS + OAUTH 2的方式来认证比较好。
面向服务器的API,则比较简单,方式比较多。
2、各种安全防护措施
包括:防止敏感数据泄露,防篡改,防重放攻击,防DDoS攻击。应对方案包括:
采用HTTPS;DDoS流量清洗;对敏感数据部分加盐再加密传输;在请求中增加一次性的Token。
3、身份认证之后的授权,由应用服务器端根据业务需求自己实现,比如安全框架Shiro、SpringSecurity等。
参考资料
http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
http://open.weibo.com/wiki/index.php/Weibo-JS_V2
https://developer.github.com/v3/
考虑两种黑客攻击情况
1、针对HTTP的网络劫持;
2、针对HTTPS的中间人攻击+SSLstrip
防御措施,要点如下:
1、全站采用HTTPS
2、客户端、WEB端的数据单向加密传输
采用全站HTTPS后,能避免绝大多数的攻击。而针对HTTPS的攻击,难度很大(目前市面上对HTTPS成功的攻击还是比较少见),如果不是非常非常核心的数据,是可以不考虑特殊保护的。
针对HTTPS的进一步保护手段,是采用数据加密,对客户端和WEB端用户发送的数据,进行加密再传输,即使被黑客获取了,也无法篡改和利用。
二、客户端身份认证方案
1、客户端会话认证
两种大的方案:
a)基于服务器端(分布式)Session技术
b)基于JWT(Json Web Token)技术
通常来说,针对Web 浏览器端的应用,基本用(a)方案,而手机APP端的应用,一般用(b)方案。
分布式Session技术
基本上都是用Redis来存储Session信息。Session的方案比较常规,不做过多说明。
JWT技术(基于token的鉴权机制)
参见《JWT技术-基于token的鉴权机制》一文。
2、OAUTH 2.0认证
。。。。。。。。。。。。
三、关于HTTPS的安全性问题
首先来说,从目前全世界的报道来看,HTTPS数据加密应该是足够安全的,黑客很难破解。
但是,对HTTPS的应用,仍然可以变相的攻击:重放攻击。
首先,模拟一个重放攻击的例子,如下:
常规登录流程:
1、前端web页面用户输入账号、密码,点击登录。
2、请求提交之前,web端首先通过客户端脚本如javascript对密码原文进行md5加密。
3、提交账号、md5之后的密码
4、请求提交至后端,验证账号与密码是否与数据库中的一致,一致则认为登录成功,反之失败。
但是,如果监听者截取到了登录信息:
http://****/login.do?method=login&password=md5&userid=登录账号
把它重放一下,即可冒充你的身份登录系统。
解决思路如下:
1、把这个url请求做成一次性使用的,第二次(重放)请求就无效了。
2、每次请求传输一个token值,第二次如果还是一样的token,就无效。这个token的生成算法或者密码数据是保密的,监听者无法得知算法或者密码,从而无法仿制token。
方案一
1、如果是客户端APP,可以采用某种算法和密匙,将密码数据、时间截、随机数等加在一起生成token,然后再发送给服务器端验证,服务器验证通过后会记录下这个token,保存一段时间(比如24小时)。如果网络监听者再次发送一样的请求和token,则服务器端直接拒绝。由于网络监听者是不知道token生成算法或密匙的,如果他随意修改了token,服务器端根据密码数据、时间截、随机数等计算出来的token,就和接收到的token不一致,就拒绝这次访问。
举个实际例子:
假设第一次请求数据:
DATA: {password:"ds8fds7", score: 10}
RS-TOKEN: AAAAAAAAAA (timestamp + nonce)
如果黑客原封不动将这个请求再发一遍,显然这个token是会被拒绝的。所以要重新生成token,但是黑客不知道
方案二
2、也可以在调用这个API之前,先向服务器获取一个随机码(称之为盐值),在客户端和服务器端各保存一份,并且设置一个有效时间,客户端提交请求时,将md5之后的密码数据与该随机码拼接后,再次执行md5,然后提交(提交的token=md5(md5(密码数据)+随机码)),后端也会计算token,然后对比,对比成功则删除从服务器端这个随机码,监听者无法再次使用它进行登录。网络监听者即使再次提交这个请求,但是后端已经删除了随机码,所以无法通过。(这个方案的劣势在于,每次请求之前,都要先获取一个随机码,第二次请求时要携带上这个随机码)
3、针对方案一,如果不是客户端APP,而是WEB浏览器,算法和密匙是写在JavaScript里面的,怎么保证算法和密匙不被泄露?js是可以被拿到的,js函数可以被黑客执行,他可以调用js函数向服务器端发起请求。为避免这种情况,应该让网络监听者无法拿到可用的js,即使拿到了,也要限制js的执行,具体方案还有待研究,我考虑到两点,1是JavaScript混淆压缩,让js很难被反编译识别(目前来说是可以做到的),2是只允许js在指定环境下才能执行,例如有指定cookie或浏览器内存数据时才能执行,而cookie数据或内存数据需要从后端获取,js动态生成,且当该js生成的时候就携带一个标识,当js初始化时,就执行一次后端验证,验证通过该js可以执行,否则这个js不能执行。