目标
移动端(App、小程序、H5)调用服务端接口办理业务,增强接口的安全性,防止随意调用盗取数据,防止篡改数据。
现状
接口分为匿名接口、登录后可调用接口,匿名接口的安全问题最突出,来自互联网的坏人可随机调用匿名接口获取数据。
登录后可调用接口,也有安全问题,坏人注册一下会员登录后就可发起调用。
总方案
1、对传输的数据采用签名+编码的方案来保护
2、对签名使用 盐,通过js混淆、js防调试来保护
3、收缩现在服务端接口的数据广度和数据权限。减少通用接口(通用接口太灵活返回的数据太任意),增加专用接口只返回必要的记录和字段。 (这是最安全有力的方案)
一、数据签名方案
解决:采用签名+base64编码的方案来保护接口。
签名规则 | ||
---|---|---|
项目 | 说明 | 说明 |
业务数据 | 是一个json对象,承载着业务数据, base64(JSON.stringify( 业务数据json对象 )) | 业务数据, 要传给服务端 |
1个盐 | 固化在代码中的盐, 盐的生命周期是长期 | 先准备一个基础 盐 |
签名规则 |
签名 =md5(sha3_256( base64 业务数据 json 串 + 时间戳 + md5( 盐 ))) |
业务数据+ 时间戳+ 盐 ,计算出签名,
签名算法
使用sha-3标准的sha3-256算法 和
md5算法相结合
|
前端向后端 传输的总数据 |
{ data : " base64(JSON.stringify( 业务数据json对象 )) ", make : 时间戳, (取这个名字是为了伪装) random : 签名 (取这个名字是为了伪装) } |
当开发人员要调试时,想查看传输的数据明文, 请网上找一个 在线 base64解码工具,解一下码就可看到了明文了。 |
二、js混淆、js防调试
代码混淆,反调试
https://www.sojson.com/javascriptobfuscator.html
选择:JS加密(最牛加密)
参数配置:
四、实现
前端向后端发送的数据格式,实例:
前端的实现代码
后端的实现代码
SignFilter 签名过滤器,的使用,配置在web.xml文件中
拦截所有的 /api/* 请求
注意: 支持跨域过滤器 在要 SignFilter 签名过滤器之前,验证签名等http请求需要得到跨域支持。
SignHttpServletRequestWrapper 移动端接口签名后的参数处理类
在 \com\sicheng\wap\utils\SignHttpServletRequestWrapper.java
核心原理:
SignFilter 签名过滤器,接收到的参数格式是,如下:
{
data : "base64(业务数据json对象)",
make : 时间戳, (取这个名字是为了伪装)
random : 签名 (取这个名字是为了伪装)
}
通过提取data参数,并base64解码,得到业务数据json对象,这才是业务数据,把业务数据给SignHttpServletRequestWrapper ,让后续的spring mvc和controller 可以不做出修改(早以开发完成不想修改),就能读取到业务数据的参数(只能读取到业务数据,时间戳,、签名无法读到),实现了 后加入的“验证数据签名” 与“早先开发完的controller”做的无缝对接。
数据映射的特性说明
依然操持原spring mvc的特性,前端提交给后端的数据是“表单格式”,这是http规范规定的格式。
前端提交的内容类型是:表单类型,Content-Type: application/x-www-form-urlencoded; charset=UTF-8,这也是默认方式。
它与json格式很像,但不完全一样, 它被称为“浅序列化”,不支持嵌套结构。
而JSON是一个可以多层嵌套结构,对象里有对象有数组等等。这种被称做“深度序列化json格式”
由于使用了签名验证,前后端以经约好好了数据格式(如上),所以不支持 前端提交给后端的数据是“深度序列化json格式”。
数据映射分析支持的数据类型:
数据类型 | 数据类型 | 示例:表单格式 | 支持数据映射 | 示例:json格式 | 支持数据映射 | 说明 |
---|---|---|---|---|---|---|
String | 字符串 | name="张三" | 原生支持 | {name:"张三"} | 原生支持映射为java的 String类型 |
|
Integer | 数据 | age=20 | 原生支持 | {age:20} | 原生 支持映射为java的 Integer 类型 |
|
String[] | 数组 | name="张三"&name="李四" | 原生支持 |
{name:["张三","李四"]}
|
原生不支持这种 复杂结构,但使用了SignHttpServletRequestWrapper 后,本shop程序就支持 映射成java的 String[]。只能是 String[]类型,不能是List或ArrayList类型 |
如果用如下json表达它是一种错误的json格式 {name:"张三",name:"李四"} |
String[] | 本质是字符串,用逗号分隔表达了一个数组的意思 | 无 | 原生不支持映射成java的 String[],可映射成为 String类型 | {爱好:"1,2"} | spring mvc支持,会按逗号分割, 支持映射成java的 String[] |
|
对象 |
|
|
|
{name:"张三",age:20,爱好:"1,2"} | spring mvc支持 把所有参数映射到一个java对象,这个对象里的属性只支持基本基类和 String[], |
|
对象 |
|
|
|
{name:"张三",age :20,爱好:"1,2"} |
spring mvc支持 把所有参数映射到一个java的Map类型,这里只 支持基本基类和 String[] |
|
对象 |
|
|
|
{a:1,b:2,c:[1,2],d:[3,4],e:{ea:10,eb:20}} | e:{ea:10,eb:20} 想单独映射成为一个map是不支持的 |
|
总结:现在依然使用传统的 “浅序列化”的“表单格式”,额外增加支持了 {爱好:"1,2"}映射成为 java的 String[]。
未来的增强: {爱好:"1,2"}映射成为java的List,{ e:{ea:10,eb:20}} 映射成为一个map,这就可实现 把所以参数映射到一个java的Map类型或实体对象了。实现支持“深度序列化json格式”。