从resfful API设计到加密算法
众所周知,SOAP 是基于XML的webservice协议,传的数据都是xml格式的,而当下resftul设计比较火,因为快效率高,但是安全性就不及SOAP,
SOAP定义了xml-security的一些规范,除了传数据,还要传额外的安全认证信息。而restful设计没有对安全性规范做什么定义。
那么如何确保Restful设计的安全性呢?
其实不管什么SOA协议,都要面临着安全性问题,也就是客户端和服务器端之间的认证问题,这里顺便扯一下SOA,SOA就是对外提供服务接口的一种思想,可以很多技术实现,什么XML-RPC,RMI,SOAP,Restful等等,(当然前面两种用得很少了)
通常认证有几种情形,
1:常用的用户名密码+认证码登录(登录验证)
2:Cookie + Session
原理即当客户端登录完毕之后,给客户端返回一个 cookie ,服务器端控制该 session 的有效期, 每次请求都带上该值,然后服务器端做验证,退出之后,客户端通知服务端端销毁 session ,自身销毁 cookie 。但是如果抓包获取到 cookie ,就能任意伪造请求了。
危险性高,实际开发估计使用得还不少。
3:基于2的问题,对于CSRF攻击,我们通常会额外生成一个token,放在HttpSession里,每次get/post请求都必须带上这个token,前端JSP通过session.getAttribute("token")就能获取到。如果前后端完全分离的话,那先要握一次手,由客户端保存住token。
4: 太小看黑客了,包都能抓到,token也能抓到,所以方法3也然并卵。
于是想一种办法,让黑客即使抓到包也看不懂,yes,就必须对关键信息进行加密。而且加密还得越复杂越好,让黑客逆向不出来。
加密的问题后面再说,参考(http://www.tuicool.com/articles/Zb6j6rR)的一种认证方法很好,
Api Key + Security Key + Sign
这里的认证逻辑即:
用户登录返回一个
api_key
和security_key
;然后客户端将
security_key
存在客户端;当要发送请求之前,通过
function2
加密方法,把如图所示的五个值一起加密,得到一个sign
;发送请求的时候,则将除去
security_key
之外的值,以及sign
一起发送给服务器端;服务器端首先验证时间戳是否有效,比如是服务器时间戳5分钟之前的请求视为无效;
然后根据
api_key
验证sercurity_key
;最后验证
sign
。
是否需要加上时间戳验证?
上面的认证逻辑中加密得到签名的时候,把时间戳加进去是为了在一定程度上屏蔽了一些无效的请求,可以略去,也可以设计的更加严格。 如果想防止恶意的 api ddos 攻击,这一步验证肯定是不行的。需要做更多的验证,比如用户验证,ip 验证等。 可以参考 github 的 api 的设计 。它会在返回的 http 头信息里带上
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4999
表示这个接口在某一时间段内,该授权用户调用该接口的最大次数为5000次,该时间段内还剩余4999次。当然,这样的验证加上之后,在代码的执行效率上肯定会有所影响。
是否需要将 request_parameters
也加入到 sign
生成的算法之中?
也不是必须的,仅仅是为了请求的真实性,减少请求的伪造,比如 有人抓包拿到 http 请求之后,如果没有验证 sign
这步,那么别人就可以非常简单的修改请求的参数,而请求都会生效。
血的教训,自己经历的一个实际案例:
一个取消用户喜欢的标签的接口,该接口会向服务器端发送类似于 ids=1,2,3,4
这样的 request_parameters
,然后服务器端拿到这些 id 之后切割,然后将该用户和这些标签的关系从 user_tag
表中删除。某个周末,数据库服务器报警,而依照我们用户习惯,那个时间不存在流量高峰,这个报警很不正常,正准备处理,报警结束了,但是过了一段时间就有用户反应他们喜欢的标签都被删了。
通过查询数据库的慢日志,发现有很多注入的 sql。
DELETE FROM `user_tag` WHERE uid=4385328 AND tid=1 OR 14=14;
DELETE FROM `user_tag` WHERE uid=4385328 AND tid=1 OR 91=91;
原来 没有对切割之后的 id 没有做数字验证,估计黑客就是传的 ids=1 OR 14=14,2,3
,而一个 delete 操作可能超时,他丫的就搞了很多次请求,真是够狠的。
幸运,数据库还有定时的打包备份,大部分用户的数据还是恢复了,同时修复了这一漏洞。
所以如果这里将 request_parameters
也加入到签名之中,就减少了伪造请求的可能性,但是无法杜绝,破坏者可能就非要黑你,又对逆向工程非常熟悉,找到我们加密算法的实现,依然可以未知出合法的签名,所以我们常说,服务器端永远不能相信客户端的请求都是安全的、合法的,需要做验证的都还是不能省略。
同时这( sign
算法)也造成了 api 接口调试的成本,api 测试工具必须也得实现那一套算法,或者是设置在开发环境下不做验证。我们在配置开发环境的时候则是 vpn 连测试服务器所在内网,然后进行测试,否则开发环境也存在被人利用的风险。
分割线--------------------------------------------------------------------------
好了,说实话,上面那位老兄的第六步没看太明白,根据APIkey check securitykey ,我理解securitykey 应该就是第一次握手生成的通常意义的token,
而这个APIkey则是类似于百度开发者那种key,是和用户绑定的,表示这个用户可以用我的api,每次请求都必须要有,
这个securitykey 是根据某种规则(加了时间戳作为salt),并且是基于APIkey生成的,这样才说的通。
那服务器端验证,先根据传过来的APIkey,生成securitykey,再和其他传过来的timestamp和request_parameters 和endpoint和前端采用同样的加密方法生成
一个sign,再和前端传过来的sign比较,一致就算pass,接下来就那securitykey 愉快地和服务器端(对称加密)消息通信啦。
黑客面临两个难点,一是要知道由APIkey生成securitykey的方法,二是要知道图中function2的加密算法,
然鹅,黑客如果在服务器端第一次给客户端APIkey和securitykey的时候就获取到它们两,而客户端的functions恰好又是js写的,那么这种方法也是然并卵的。
5:这个时候要讨论一下加密算法了。
对称加密(Symmetric Cryptography)
对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。
对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,不行的话就再用1解;但如果你的密钥有1 MB大,黑客们可能永远也无法破解,但加密和解密的过程要花费很长的时间。密钥的大小既要照顾到安全性,也要照顾到效率,是一个trade-off(权衡)。
非对称加密(Asymmetric Cryptography)
非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。
目前最常用的非对称加密算法是RSA算法,是Rivest, Shamir, 和Adleman于1978年发明,他们那时都是在MIT
虽然非对称加密很安全,但是和对称加密比起来,它非常的慢,所以我们还是要用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。 所以,结合方法4和方法5,正常的握手流程应该是这样的。
(1) 用户登录返回一个 公钥(publickey),一个APIkey作为用户识别key。
(2) 浏览器生成了一个随机数作为对称密钥(securitykey ), 并用公钥对自己的对称密钥加密,浏览器将加密后的对称密钥发送给服务器。
(3) 服务器使用私钥解密得到浏览器的对称密钥。
(4) 两边可以使用对称密钥来对沟通的内容进行加密与解密了。
这招应该能让黑客傻眼了吧。但前提是用户名和密码可别泄漏了。
最后再说一下soap和rest的适用场景,
其实SOA本质就是一种网络函数调用,如果我们的需求都可以抽象成资源,就可以用rest,而且抽象得越精确越好,
个人感觉,如今大多数项目都是对某些数据(对象)CRUD,即使对与工作流等偏数据处理类的应用,也是一种活动或处理的调用而已,
验证,log,异常处理都可以交给spring,那么我想选择rest的根本原因还是在于它的高效率上吧。
从resfful API设计到加密算法的更多相关文章
- javascript的api设计原则
前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来.很难做到 ...
- (转载) RESTful API 设计指南
作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...
- RESTful API 设计指南
转自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机. ...
- GOTO Berlin: Web API设计原则
在邮件列表和讨论区中有很多与REST和Web API相关的讨论,下面仅是我个人对这些问题的一些见解,并没有绝对的真理,InnoQ的首席顾问Oliver Wolf在GOTO Berlin大会上开始自己的 ...
- RESTful API 设计最佳实践
背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个"万能"的设计标准:如何鉴权?API ...
- 我所理解的RESTful Web API [设计篇]
<我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...
- 从英文变形规则计算到Restful Api设计
➠更多技术干货请戳:听云博客 一天在研究Restful API设计,命名的时候我总是很纠结,我相信大多数人也有这种感觉,不是说想不出来某个单词怎么写的问题,像我这种没事背单词背到13000词量的人也要 ...
- RESTful API 设计指南 (转)
RESTful API 设计指南 2016-02-23 ImportNew (点击上方公号,可快速关注) 作者:阮一峰 链接:http://www.ruanyifeng.com/blog/2014/0 ...
- 基于资源的权限系统-API设计
概述 权限系统需要和别的系统集成,因此,良好的API是易用性的保证. 这里只设计一些权限相关的核心 API,关于用户,组织,导入导出之类的后续再逐步补充 API 设计 围绕权限有以下 4 类 API: ...
随机推荐
- Excel应该这么玩——6、链接:瞬间转移
上一篇中提到通过命名表格来管理基础数据,这样会让数据更规范.如果有很多个基础数据表,需要查找或者修改其中的一个,可以通过名称框中下拉来定位. 但是当表格较多的时候,通过下拉选择的方式就不是很好定位了. ...
- lucene中FSDirectory、RAMDirectory的用法
package com.ljq.one; import java.io.BufferedReader;import java.io.File;import java.io.FileInputStrea ...
- font-family:“微软雅黑” OR font-family:Microsoft Yahei
sublime对中文编码支持的不好,可以考虑用后者.
- IOS响应式编程框架ReactiveCocoa(RAC)使用示例
ReactiveCocoa是响应式编程(FRP)在iOS中的一个实现框架,它的开源地址为:https://github.com/ReactiveCocoa/ReactiveCocoa# :在网上看了几 ...
- Codefroces 750C:New Year and Rating(思维)
http://codeforces.com/contest/750/problem/C 题意:有n场比赛,每场比赛有一个c,代表比赛结束后分数的增长情况,有一个d,代表这场比赛在div1或者div2打 ...
- javascript实现九九乘法表
CSS代码部分: <style type="text/css"> table { width: 800px; height: 300px; border-collaps ...
- python 学习笔记十五 web框架
python Web程序 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. Python的WEB框架分为两类: 自己写socket,自 ...
- sql-ASCII函数运用
declare @a int = ASCII('A') declare @b int = ASCII('F') declare @c int = 1 while(@a <= @b) begin ...
- Extjs MVC学习随笔01
Extjs Mvc模式下的整个MVC框架体系即下图: 包含了Controller(实现方法层),Store(数据来源管理层),View(页面布局层).之所以用MVC我想是因为减轻针对某一页面的单一的J ...
- R语言拆分字符串
R语言拆分字符串 aaa<-"aa;bb;cc"ccc<-strsplit(aaa,split=";") bbb<- unlist(strsp ...