在web开发的过程中,当对外提供的接口能够被随意调用时,可能造成非法用户能够对我们的服务器进行恶意攻击,导致服务器不能有效处理正常的业务请求,因此需要考虑对这些暴露出去的http接口做防刷限制。
今天主要讲一下我们的项目中用到的一种防刷机制——给对外接口加验证身份的签名(即验签)。
具体到业务中,当调用者B请求调用服务者A的接口时,服务者A需要验证调用者B的身份,并通过签名来验证调用者的身份,整个流程大致如下:
首先服务者A为自己暴露的接口生成一个密钥key,并存储在数据库中,而且A提供生成签名的加密算法(比如HmacSHA1算法)
调用者B每次调用A的接口之前,首先采用某种加密算法,使用密钥key对B要传给A的数据进行加密,生成一串签名摘要signature。
然后调用者B在调用A的接口时,将原有的参数数据连同这个签名摘要一起传递给A。
服务者A接收到B的调用请求时,首先要验证B传过来的签名是否合法,若验证通过则继续后续的处理;否则将返回一个错误,中断处理流程。
服务者A验证签名的方法大致为:首先采用相同的加密算法和密钥key对B传来的参数数据进行加密,生成一个新的签名摘要newSignature,然后比较生成的newSignature和signature是否相同,若相同则验证通过;否则验证不通过。
服务者A把一套规则(密钥和加密算法)告诉调用者B(而且只告诉B,第三方无法得知),当B要调用A的接口时,B可以使用这套规则对自己要传递的数据info进行加密得到一个签名,然后把info和签名一起发送给服务者A,A接收到B传过来的数据后,使用相同的规则对接收的info进行加密,得到一个新的签名,若这个新签名和B传过来的签名相同,则说明生成这两个签名所使用的info、加密算法和密钥都是相同的,info没有被篡改过,B的身份是真实的;若生成的新签名和B传过来的签名不相同,则说明生成这两个签名所使用的info、加密算法和密钥不是完全相同的(注意密钥和加密算法封装隐蔽在服务者A的内部,不会泄露出去),有可能info被篡改了,也有可能info没被篡改,但是使用的加密算法或密钥和服务者A约定的不同,那么这个调用者可能就不是真实的B,真实的B肯定使用服务者A约定的算法和密钥去生成info签名,得到的签名和服务者A计算出的一定是相同的(基于下方所述的SHA1的特性)。
所以通过验证签名,可以验证两个事情:1.调用者传送的信息在传输过程中是否被篡改过 或 2.调用者身份是否是合法的。
不管是传送的信息被篡改,还是接口被非法调用,服务者A都会视为认证错误,中断处理流程。
HMAC是指基于哈希的信息认证编码(hash-based message authentication code)
SHA1是一种安全哈希算法,对于限定长度的信息,通过SHA1可以生成一个固定长度的信息摘要,可以使用信息摘要验证信息的完整性。SHA1具有两个特性:1.不可逆,无法根据信息摘要获取原信息。2.两个不同的信息不会产生同样的信息摘要。
HMAC-SHA1则指使用SHA1哈希算法和一个私钥加密生成HMAC的一种MAC(信息认证码)算法。
或者说更生动、形象一些,这太重要了,生动形象让人印象深刻。
A对B说,要使用的我的服务,必须要按照我的规则来调。
B:什么规则?
A:每次调用我的服务,都要用我提供的密钥和加密算法来加密你要给我发的信息,生成一个签名,然后将你的信息连同这个签名一块发送给我。
B:why?
A:因为我要验证你的身份啊,我只给你一个人提供这个服务,其他人都没门。只要我用相同的密钥和加密算法对你的信息进行加密得到的签名,和你发给我的签名是一样的,那你肯定就是你了。
B:pardon,你说你会把什么告诉我 ?
A:我说我会把密钥和加密算法告诉你,...,oh no,直接告诉你太不安全了,告诉你密钥的代号吧,就叫X,到时候给我代号X就行。至于加密算法,我只能把接口告诉你,怎么实现的我得隐藏起来,只要你拿着代号X和信息来调我这个接口,我就会去找对应的密钥,并用我的加密算法来加密你的信息,哎呀,这刚刚好像说过了,总之我得尽量把这些重要的信息藏起来,尽量用暗号和你通信!
B:oh,我好像明白一些了,可是你不担心我胡乱调用吗?我要是一下给你发成千上万个调用请求,你吃得消吗?
A:啊呸!都是自己人,何必这样为难我呢,你不会控制一下吗?
B:我怕我控制不了我自己啊。。。
A:容我想想,想好了再告诉你。
B:Fine,thank u.
A:What?and you?