首先贴一下看过的文章:
1.http://www.cnblogs.com/xiekel...
2.http://blog.leapoahead.com/20...
3.http://blog.leapoahead.com/20...
4.jwt demo :https://github.com/bigmeow/JWT
5.https://github.com/jwtk/jjwt 这里面有几篇比较好的算是官方推荐的
6.http://blog.csdn.net/koastal/... 基于timestamp和nonce的防止重放攻击方案html
公司目前的WEB设计都是基于HTTP Basic Auth,一直以为会有很大的安全问题,重放攻击就很简单实现。git
引用第一篇文章的一段话:HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码便可,但因为有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的愈来愈少。所以,在开发对外开放的RESTful API时,尽可能避免采用HTTP Basic Auth。github
以为采用TOKEN的方式实现WEB和API的认证。 JSON WEB TOKEN 算是比较成熟的解决方案,所以采用JSON WEB TOKEN。 JSON WEB TOKEN的基本介绍请看 文章开头的后面3个链接。 数据库
JWT解决了:
1.做为TOKEN验证使用时解决了用户直接输入帐号和密码的进行认证的问题。
2.部分数据安全传输的问题(例如第2个连接的文章,是添加关注,服务器生成的链接,能够安全的经过邮件发送给目标客户,而不暴露操做用户的相关信息)。 json
做为TOKEN使用,JWT的payload须要有关于用户信息的字段,否则怎么知道是哪一个用户在操做,通常不要填写敏感信息,如用户密码等,由于是经过base64编码,是能够破解的。用户登陆和获取TOKEN的接口是须要HTTPS加密的,不然用户帐号和密码是会暴露的,也就没有什么安全性可言了。缓存
请求时TOKEN的上传能够用如下方式:
1.经过cookie
2.经过HTTP Authorization Head中
3.GET/POST方法,直接经过参数形式。安全
安全性:
1.首先要保证登陆和得到TOKEN的接口须要HTTPS加密
2.防止重放攻击:目前想到的 客户端和服务器间有一个共享的秘钥,在调用API时须要将API的方法、参数、TOKEN作一次签名(可用jwt)。服务器首先验证方法、参数、TOKEN的签名是否正确,而后验证TOKEN的签名是否正确。第一次签名时保证即便请求被劫持,劫持者也没有办法假冒其它请求或者修改参数,在必定程度上保证了安全性。 第二次签名验证主要是验证TOKEN的有效性,验证用户身份。服务器
以上步骤须要服务器上保存两种秘钥,第一种是生产TOKEN的秘钥,这个只有服务器程序知道。第二种秘钥是针对每一个使用接口的开发者的共享秘钥,这个秘钥只须要服务器和开发者知道(开发者能够登陆网站,在申请使用接口时,自定义本身的共享秘钥)。cookie
3.共享秘钥的保存:共享秘钥须要安全的保存,不能被泄漏。koa
-----------------------如下拷贝自第6个连接------------------------------------------
之前老是经过timestamp来防止重放攻击,可是这样并不能保证每次请求都是一次性的。今天看到了一篇文章介绍的经过nonce(Number used once)来保证一次有效,感受二者结合一下,就能达到一个很是好的效果了。
重放攻击是计算机世界黑客经常使用的攻击方式之一,所谓重放攻击就是攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程。
首先要明确一个事情,重放攻击是二次请求,黑客经过抓包获取到了请求的HTTP报文,而后黑客本身编写了一个相似的HTTP请求,发送给服务器。也就是说服务器处理了两个请求,先处理了正常的HTTP请求,而后又处理了黑客发送的篡改过的HTTP请求。
基于timestamp的方案
每次HTTP请求,都须要加上timestamp参数,而后把timestamp和其余参数一块儿进行数字签名。由于一次正常的HTTP请求,从发出到达服务器通常都不会超过60s,因此服务器收到HTTP请求以后,首先判断时间戳参数与当前时间相比较,是否超过了60s,若是超过了则认为是非法的请求。
假如黑客经过抓包获得了咱们的请求url:
http://koastal.site/index/Inf...
其中
$sign=md5($uid.$token.$stime);
// 服务器经过uid从数据库中可读出token
通常状况下,黑客从抓包重放请求耗时远远超过了60s,因此此时请求中的stime参数已经失效了。
若是黑客修改stime参数为当前的时间戳,则sign参数对应的数字签名就会失效,由于黑客不知道token值,没有办法生成新的数字签名。
但这种方式的漏洞也是显而易见的,若是在60s以内进行重放攻击,那就没办法了,因此这种方式不能保证请求仅一次有效。
基于nonce的方案
nonce的意思是仅一次有效的随机字符串,要求每次请求时,该参数要保证不一样,因此该参数通常与时间戳有关,咱们这里为了方便起见,直接使用时间戳的16进制,实际使用时能够加上客户端的ip地址,mac地址等信息作个哈希以后,做为nonce参数。
咱们将每次请求的nonce参数存储到一个“集合”中,能够json格式存储到数据库或缓存中。
每次处理HTTP请求时,首先判断该请求的nonce参数是否在该“集合”中,若是存在则认为是非法请求。
假如黑客经过抓包获得了咱们的请求url:
http://koastal.site/index/Inf...
其中
$sign=md5($uid.$token.$nonce);
// 服务器经过uid从数据库中可读出token
nonce参数在首次请求时,已经被存储到了服务器上的“集合”中,再次发送请求会被识别并拒绝。
nonce参数做为数字签名的一部分,是没法篡改的,由于黑客不清楚token,因此不能生成新的sign。
这种方式也有很大的问题,那就是存储nonce参数的“集合”会愈来愈大,验证nonce是否存在“集合”中的耗时会愈来愈长。咱们不能让nonce“集合”无限大,因此须要按期清理该“集合”,可是一旦该“集合”被清理,咱们就没法验证被清理了的nonce参数了。也就是说,假设该“集合”平均1天清理一次的话,咱们抓取到的该url,虽然当时没法进行重放攻击,可是咱们仍是能够每隔一天进行一次重放攻击的。并且存储24小时内,全部请求的“nonce”参数,也是一笔不小的开销。
基于timestamp和nonce的方案
那咱们若是同时使用timestamp和nonce参数呢?
nonce的一次性能够解决timestamp参数60s的问题,timestamp能够解决nonce参数“集合”愈来愈大的问题。
咱们在timestamp方案的基础上,加上nonce参数,由于timstamp参数对于超过60s的请求,都认为非法请求,因此咱们只须要存储60s的nonce参数的“集合”便可。
假如黑客经过抓包获得了咱们的请求url:
http://koastal.site/index/Inf...
其中
$sign=md5($uid.$token.$stime.$nonce);
// 服务器经过uid从数据库中可读出token
若是在60s内,重放该HTTP请求,由于nonce参数已经在首次请求的时候被记录在服务器的nonce参数“集合”中,因此会被判断为非法请求。超过60s以后,stime参数就会失效,此时由于黑客不清楚token的值,因此没法从新生成签名。
综上,咱们认为一次正常的HTTP请求发送不会超过60s,在60s以内的重放攻击能够由nonce参数保证,超过60s的重放攻击能够由stime参数保证。
由于nonce参数只会在60s以内起做用,因此只须要保存60s以内的nonce参数便可。
咱们并不必定要每一个60s去清理该nonce参数的集合,只须要在新的nonce到来时,判断nonce集合最后一次修改时间,超过60s的话,就清空该集合,存放新的nonce参数集合。其实nonce参数集合能够存放的时间更久一些,可是最少是60s。
验证流程
//判断stime参数是否有效
if( $now - $stime > 60){
die("请求超时");
}
//判断nonce参数是否在“集合”已存在
if( in_array($nonce,$nonceArray) ){
die("请求仅一次有效");
}
//验证数字签名
if ( $sign != md5($uid.$token.$stime.$nonce) ){
die("数字签名验证失败");
}
//判断是否须要清理nonce集合
if( $now - $nonceArray->lastModifyTime > 60 ){
$nonceArray = null;
}
//记录本次请求的nonce参数
$nonceArray.push($nonce);
//开始处理合法的请求