Restful API 安全

原文链接:http://openwares.net/misc/restful_api_security.html

restful是一种轻量级的web service实现方式。restful并不是标准,也没有对应的软件实体,只是基于http协议的一种指导性的设计方法或原则。

当下流行的open api大部分采用restful的方式实现,但restful并不限于此。普通的web app,移动app,以及系统之间的web service集成都可以采用restful的方式。

restful和http一样是无状态的,也就是单次请求之间并无任何联系,每次请求必须携带全部的状态信息。

对于受保护的资源,restful同样面临认证(authentication)和授权(authorization)的问题。

restful在不同的使用情景下有其相适宜的认证和授权方式。

第三方授权

现在火热的开放平台就是典型的三方授权模式。OAuth(Open Authorization)就是用于三方授权的协议,当前版本为2.0。
OAuth协议重在授权,应用程序无需知道资源拥有者的身份凭证,只需用户授权一定的资源访问权限,获取相应的Access Token就可以在授权范围内访问用户的资源。这种授权是有期限的,而且用户可以随时撤销。

OAuth授权整个流程涉及到用户,资源服务器,认证服务器和第三方应用这四个角色。资源服务器和认证服务器只是概念上的区分,物理上可以存在于同一个服务器。

Access Token就是与一个与用户相关的一个随机数,认证服务器记录了此Access Token所拥有的访问权限。第三方应用访问用户资源时携带Access Token,经过权限检查可以访问被授权的资源。

web应用

前后分离的web应用程序,后端可以采用restful方式向前端提供api接口。这种模式,使用传统的session方式即可满足要求。也可以采用token的方式,用户使用身份凭证通过系统身份认证后,服务端颁发一个随机的token,以后每次访问api时,参数中携带此token即可。token可以设置有效期,过期以后重新认证颁发新的token。

其实传统的session使用的sessionid就是token。无论使用cookie,url重写还是隐藏表单域,无非都是将服务器颁发的sessionid再重新发送给服务器进行认证。sessionid就是会话令牌。

session用于认证,授权则由应用程序自行处理,比如基于角色的权限系统等。

传统的session方式最大的风险在于session劫持,https可以大大缓解这一风险,可以杜绝中间人攻击。

web接口

restful方式实现web service供其他应用使用。这种情形下通过颁发app id(access key/pulic key)和app secret(secret key/private key),并对请求进行签名的方式来保证api的安全,防止有人篡改请求和非授权访问。如果签名中添加timestamp可以进一步防范重放攻击(replay attack)。

此处的access key用户标示用户的身份,客户端必须妥善保存其secret key,这是服务端认证客户端唯一可靠保证。
access key类似传统的用户名,而secret key则是两端共享的私密秘钥,以随机数生成算法生成一个较长的随机字符串即可。

客户请求api时,将请求的动作类型(get,post,put或delete)、uri、请求参数(包括access key)、timestamp使用secret key进行签名,使用HMAC-SHA256等摘要算法。将计算好的摘要同其他请求参与一同发送给服务器。服务端根据access key查找其对应的secret key,然后使用相同的算法重新计算摘要。如果重新计算的摘要与请求传送过来的摘要一致,则可以信任此次请求。添加时间戳的主要目的是用于防范重放攻击。

签名算法

下面是一个签名算法的例子。

算法描述如下:

signature = HMAC-SHA256(secrey_key, string_to_sign);

string_to_sign = http_verb + "&" + uri + "&" + request_parameters_sorted;

request_parameters_sorted = "key1=value1&key2=value2&..keyn=valuen";

比如以post方式访问https://foo.com/bar/test接口,请求参数为:

{
  "first_name" : "kitty",
  "last_name" : "san",
  "age" : 8,
  "gender" : "female",
  "app_id" : "xdfe323423fsvdsefew",
  "timestamp" : "2015-10-21 12:06:06"
}

获取当前的UTC时间戳为: 2015-10-21 12:06:06

将请求参数的key以字典序排序得到:

{
  "age" : 8, 
  "app_id" : "xdfe323423fsvdsefew",
  "first_name" : "kitty",
  "gender" : "female",
  "last_name" : "san",
  "timestamp" : "2015-10-21 12:06:06"
}

将排序后的参数拼接得到request_parameters_sorted:

request_parameters_sorted = "age=8&app_id=xdfe323423fsvdsefew&first_name=kitty&gender=female&last_name=san&timestamp=2015-10-21 12:06:06";

然后得到将要签署的字符串string_to_sign

string_to_sign = "post&/bar/test&age=8&app_id=xdfe323423fsvdsefew&first_name=kitty&gender=female&last_name=san&timestamp=2015-10-21 12:06:06"

最后得到signature

signature = HMAC-SHA256('your_secret_key', "post&/bar/test&age=8&app_id=xdfe323423fsvdsefew&first_name=kitty&gender=female&last_name=san&timestamp=2015-10-21 12:06:06");

计算完签名后,将签名作为请求参数之一一起发送给服务端,参数的名称为signature。服务器端接收到请求后以相同算法重新计算签名进行核对即可。服务器端计算签名时要去掉signature参数。

所有的字符都使用UTF-8编码。直接对原始请求参数进行签名即可,无需进行url编码。服务器端接收到的也是原始请求参数,这样计算签名更简单。

防范重放攻击

因为请求中携带了请求发出时的时间戳,服务器可以设置一个合理的请求认证时间窗口,比如10分钟,在当前时间前后10分钟之内的请求都可以视为合法请求。这只是减少了被重放攻击的可能性,但并未完全杜绝重放攻击。如果请求在服务器时间窗内被截获重放,则只靠时间戳是无能为力的。

因此,需要附加另外的机制来防止重放攻击。服务端可以记录每次请求的时间戳和签名,每次请求到达是,先验证请求是否在时间窗口范围内,如果超出时间范围则直接拒绝。如果在时间窗口内,则查询请求记录,如果没有对应的请求记录,则满足此次请求,并将此次请求的时间戳和签名记录下来,并清理掉不在当前时间窗口内的所有请求。

时间戳加记录请求的方式可以完全杜绝重放攻击,而且可以保持一个很小的请求记录表。因为在当前时间窗口外的请求可以随时被清理掉。

请求速率限制

如有需要可以对api请求的速率或次数进行限制。

非对称秘钥加密签名

也可以使用RSA非对称秘钥进行数字签名。

服务端生成RSA公私密钥对和客户端的access key,将私钥和access key交付客户端应用。服务端保存access key和客户公钥。

请求签名时,客户端不再使用HMAC签名算法,而是使用普通的摘要算法,比如SHA256,但此时传送的摘要使用客户私钥进行加密后再随请求参数一起传递。因为谁都可以计算SHA256摘要,所以需要用私钥进行加密保护。

服务端接收到请求后,使用同样的算法计算SHA256摘要,然后使用客户的公钥解密随请求一起发的、客户端计算的、加密后的摘要,如果服务端重新计算的摘要与解密后的摘要相同,则认为请求是合法。

无论使用对称秘钥还是非对称秘钥进行签名,秘钥都要妥善保存,这是整个签名认证算法的基石。

无论何种情形,对于restful api的安全而言,https/ssl加密都是十分有必要的。

注意:使用access key与secret key并对api签名调用的方式,并不适合web前端或者移动app使用。因为web前端无法保密secret key,而将secret key保存在android或ios app中也是无法保证安全的,很容易将secret key从app中破解出来。只有将secret key保存在后端才能保证安全。并且secret key是针对客户端发放的,而不应该是针对每一个客户端的user发放的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介这是一门使用Java语言,SpringBoot框架,从0开发一个RESTful API应用,接近企业级的项目(我的云音乐),课程包含了基础内容,高级内容,项目封装,项目重构等知识,99%代码为手写;因为这是项目课程;所以不会深入到源码讲解某个知识点,以及原理,但会粗略的讲解下基础原理;主要是讲解如何使用系统功能,流行的第三方框架,第三方服务,完成接近企业级项目,目的是让大家,学到真正的企业级项目开发技术。适用人群刚刚毕业的学生想提高职场竞争力想学从零开发SpringBoot项目想提升SpringBoot项目开发技术想学习SpringBoot项目架构技术想学习企业级项目开发技术就是想学习SpringBoot开发能学到什么从0开发一个类似企业级项目学会能做出市面上90%通用API快速增加1到2年实际开发经验刚毕业学完后能找到满意的工作已经工作学完后最高涨薪30%课程信息全课程目前是82章,155小时,每节视频都经过精心剪辑。在线学习分辨率最高1080P课程知识点1~11章:学习方法,项目架构,编码规范,Postman使用方法,Git和Github版本控制12~16章:搭建开发环境,快速入门SpringBoot框架17~20章:快速入门MySQL数据库21~30章:MyBatis,登录注册,找回密码,发送短信,发送邮件,企业级接口配置31~41章:实现歌单,歌单标签,音乐,列表分页,视频,评论,好友功能42~48章:阿里云OSS,话题,MyBatis-plus,应用监控49~53章:Redis使用,集成Redis,SpringCache,HTTP缓存54~58章:Elasticsearch使用,集成Elasticsearch,使用ES搜索59~61章:商城,集成支付宝SDK,支付宝支付62~64章:常用哈希和加密算法,接口加密和签名65~67章:实时挤掉用户,企业级项目测试环境,企业级接口文档68~69章:SpringBoot全站HTTPS,自签证书,申请免费证书70~73章:云MySQL数据库,云Redis数据库使用,轻量级应用部署环境,域名解析74~80章:Docker使用,生产级Kubernetes集群,域名解析,集群全站HTTPS81~82章:增强和重构项目,课程总结,后续学习计划

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值