交互校验常用参数:
(1) Authorization/session_id
用户认证参数。
(2) 客户端签名 Signture
签名的功能是校验服务端收到的请求来自于对应的客户端,确保对不是对应客户端发起的请求不予响应。其中常见的签名方法有ASE加密解密,比对信息摘要等。最简单的方式比如将一个随机值+时间戳+约定值进行组合顺序的MD5加密,然后在服务器收到该请求时生成新的签名进行比对,若签名一致则响应该请求,否则不予响应。其中signture可以这样生成:
signture = md5(随机值 + 时间戳timestamp + 约定值)
常见问题举例:
(1) 重放攻击
典型的重放攻击是通过抓包客户端生成的签名不断地进行接口请求。如利用该签名不停地请求短信验证码接口,直到服务器的验证码余额耗光。
防止重放攻击的最有效方式就是保持signture的唯一性。客户端必须生成唯一的signture,同时服务端也要保证对一个signture只响应一次请求。
要确保signture的唯一性,可以在生成签名时采用时间戳timestamp这个参数的唯一性;同时为了确保服务端响应的唯一性,可以标记记录响应过的signture,再重复接收时不予响应。
而在服务器端对signture做记录,一般可以采用 磁盘文件、数据库、缓存(Redis,Memcached等)记录。其中写进磁盘文件存在调用效率低,分布式系统不适用等弊端。若数据量较小时可采用缓存存储,若数据量较大可采取数据库存取(注意:需考虑请求数增加会加大数据库压力的问题)。
(2) 签名超时机制
上述确保签名唯一性的方法,在记录的signture数量增加到一定数量后会效率很低。每次请求都需要去比对之前请求记录下的签名,明显是很不合理的。所以对于签名的记录,应当有一定的时效性,比如做一个数据库临时表,或者是redis缓存。在考虑时效性的同时,我们还需要考虑到记录的签名到期后,会被攻击者继续利用失效签名进行重放攻击的风险。
所以需要引入签名超时机制,当请求中的timestamp参数与当前服务端时间相隔大于signture的缓存时间,则不去响应该请求。一般超时时间需要满足:
(服务端当前时间 - 客户端提交时间) < 超时时间 < signture缓存时间
(3) 超时机制下溢攻击
按照上面超时机制的原理,对应的程序逻辑应该如下:
if( (服务端时间 - 客户端时间) < 超时时间 ){
//正确响应
}else{
//超时,不予响应
}
但是其中也需要考虑客户端提交时间远大于服务器时间的情况,及攻击者在signture失效后,采用超前的timestamp参数生成signture,进行重放攻击。其原理是服务端时间 - 客户端提交时间 = 负数 < 超时时间,从而绕过了超时机制,所以在计算服务端时间与客户端时间间隔时,需要额外判断其间隔为整数。
当然,为了确保服务端与客户端时间的一致性,经常需要服务端提供查询时间接口,使得客户端提交的时间戳参数与服务端的时间一致。
以上是我在做后端交互时的一些总结,后续若遇到其他问题,会继续更新。
若其中有总结错误的地方,也请大家多多指教。