目标

移动端(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解码工具,解一下码就可看到了明文了。

https://www.sojson.com/base64.html


二、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格式”。