本文为你讲解如何设计接口字段,保证你的数据安全,避免被第三方抓包改动,尤其是对外接口、涉及交易的接口,设计一个安全的接口是必须的,以微信支付接口为例,为你讲解如何做好接口数据安全校验。

1. 什么情况需要考虑接口安全 ?

如果你的应用是涉及金钱的,通常都需要考虑接口的安全。
最常见的微信支付、支付宝支付,直接就是跟钱打交道的,必须保证数据在传输过程中不被篡改。
还有我们常见的一些 App 送礼、购买商品、充值,都是需要保证数据安全的。
任何时候,只要你的接口数据是很重要的,被第三方改动后会导致损失的,都应该考虑接口安全。

2. 接口数据是怎样被篡改的 ?

现在有很多的抓包工具,例如 Wireshark、Charles,都可以抓取到我们接口传输过程中的数据,并且可以修改传输的数据。
举个简单的例子,假设 App 里面有送礼功能,送礼成功后就播放一个礼物特效,但是接口返回余额不足,赠送失败。这时候你可以用抓包工具拦截响应数据,把响应数据改为成功,就能播放到这个礼物特效了;我们还可以拦截送礼的请求数据,把送礼数量从 1 改为 -1 ,如果服务端没有做负数的校验,我们的账户就不是扣钱了,而是加钱了。
再举个例子,假设没有接口安全校验,我们就能拦截并修改微信支付的回调通知数据,我们就可以把支付失败改成支付成功,还可以把支付1元改成支付1万等各种操作

3. 如何保证数据安全

首先就是要使用 https 协议,这样数据传输过程中是加密的,会加大抓包工具的抓取难度。
另外就是要做字段的签名校验,这样可以知道数据在传输过程中有没有被第三方改动过。
这里我们重点来讲解下如何做接口字段的签名校验,我们直接学习微信支付接口的签名。

4. 微信是如何做接口签名校验的

我们来看看微信支付是如何做接口签名的(微信支付接口签名文档

  1. 所有字段按照字典升序排列
  2. 把参数按照 key1=value1&key2=value2… 拼接起来
  3. 后面再拼接一个秘钥 key=xxx
  4. 把拼接好的字符串进行 MD5 编码,然后转为大写得到最后的签名字符串

签名举例,假设参数有:

1
2
3
4
5
{
"money": 1,
"random": "abc123",
"appid": "wxd678efh567hg6787"
}

按照字典升序排列:appid, money, random
拼接字段得到:appid=wxd678efh567hg6787&money=1&random=abc123
拼接秘钥:appid=wxd678efh567hg6787&money=1&random=abc123&key=xxxx
最后 MD5 大写得到最终的签名:81E18290765276E1C879DE2BCDD9FA60

最后发出去的数据就是:

1
2
3
4
5
6
{
"money": 1,
"random": "abc123",
"appid": "wxd678efh567hg6787",
"sign": "81E18290765276E1C879DE2BCDD9FA60"
}

以上就是微信支付接口的字段签名,签名算法还是非常简单方便的(相比支付宝的)。
最终我们发送的数据只是增加了一个sign,为什么这样就能保证接口数据不被篡改了呢?
因为每个字段都参与了 MD5 的签名, MD5 的特性就是只要改动了任何一点数据,结果就不一样了。
你可能会疑问,那我篡改数据后自己重新计算下签名不就可以了?
事实并非如此,因为参与签名的还有一个密钥,这个是只有微信和你自己知道的,第三方要想篡改数据后重新计算出正确的签名就需要知道这个密钥,否则是计算不出正确的签名的,所以我们必须保证密钥 key 的安全不泄露。
还有人可能会问,那我拦截到这个数据后,保存起来,后面反复用这个数据请求不就可以了?也就是重放攻击。
其实我们发送的数据中还有一个 random 字段,我们可以校验这个随机值是否最近有被使用过,如果已经用过了,我们可以认为这是一个重复的数据,从而忽略掉。
我们还可以增加一个时间戳字段,这样能方便的知道这个请求什么时候发起的,时间偏差太大的情况,我们也可以认为是一次不安全的请求。

最后总结下:所有字段参与签名,确保你的密钥字符串的安全,字段中要包含一个随机字符串。