【项目】API接口的加签和验签
近期工作学习中,遇到了几个对接第三方 API 的需求。对于提供接口的平台,提供的接口为什么能保证安全可靠呢?这其中又是如何防止第三方的恶意使用呢?如何鉴别调用者的身份呢?
API 接口加密的原理
API 接口加密的原因无非就两个:
- 核实调用方的身份,签名验签
- 验证调用传输数据,数据加密
加密和解密的方式,根据加解密方式的异同可以分为:对称加密和非对称加密。
- 对称加密,加密和解密使用的是同一把密钥。常用的对称加密算法:DES,AES,3DES
- 非对称加密,加密和解密使用的是不同的密钥,一把作为公开分享给加密方的叫做公钥,另一把不分享作为解密的私钥。公钥加密的密文只有私钥能进行解密;私钥加密的密文也只有公钥能进行解密。常见的非对称加密算法:RSA,ECC
- 在效率上来说,对称加密的效率显然更高,但是非对称加密的安全性更高。所以一般在实际的HTTPS加密过程中,首次连接使用的是公钥加密算法(非对称加密)来传输数据加密所要使用的对称加密的密钥,之后传输中使用的都是对称加密算法。
公私钥加密和解密
鉴于对称加密的安全性通常并不高,所以通常是使用非对称加密的方式。这种方式,可以很大程度保证一个数据的安全。举个例子:
发送方将数据加锁,但是钥匙只有接收方才有。这样在数据加密之后,这段数据都是相对比较安全的状态。
发送者和接收者都有两种加解密的方法,而且把其中一套加密方法和解密方法都对外公开。这里默认加密方法是不能反推出解密方法的,解密方法是不能反推出加密方法的。也就是说,A 加密就必须 A 解密,B 加密就必须 B 解密。
在 HTTPS 中,使用非对称加密方式。比如 RSA 加密方式,使用的是大数取模运算,通过欧拉公式,得到加密之后的密文;但是因为取模运算本身不可逆,再加上大数取模运算,以现有的计算水平也很难在短时间内破解,所以只有拿到私钥才能知道原文的内容。
- 在 A 向 B 发送信息的同时,需要带上自己的签名,这个时候 A 用自己才知道的加密方法 b 进行签名加密,因为任何人都知道解密方法 b,所以任何人都可以看到 A 的签名,也就是任何人都知道这条是 A 发出来的信息,但因为签名不是不能公开的信息,所以被解密了也没有关系。
- 对于真正要发送的数据,A 会使用接收方公开的加密方式 c 来对数据进行加密。这样只有 B 使用自己的解密方法 c 才能解开,任何人即便获取了这个密文,包括 A 在内都无法再针对密文进行反向解密操作。
这样的方式下:
① 签名可以被任何人解密和获取,但是签名不涉及核心数据,无影响;
② 发送方使用接收方公开的加密方式进行数据加密,加密的数据只有接收方才能解密得到原始数据;
③ 接收方在收到调用方的数据之后,首先需要核验签名,如果签名不正确,那么数据也就不需要解密,直接抛弃该请求。
这样的过程会有一些问题存在:
一、因为签名可以被第三方破解,会不会出现签名伪造的情况?
不会。因为签名使用的加密方式,应该是发送方私有的加密方式,第三方即便知道解密后的签名,但是因为签名加密方法未知(请求方私有),还是无法伪造签名。
二、如果直接获得发送方的加密消息和签名呢?如何识别该请求来自于 A 呢?
就近期的工作中遇到的实际情况来说,这种情况不需要考虑,接受直接返回正常处理过后的数据即可。因为会考虑到请求方有使用其他客户端程序的情况,所以这种情况一般不予考虑。
原因有:
① 方便请求方的各种调试
② 接口提供方通常使用的是 Https 协议
三、这种方式的具体实现形式有哪些?
一般接口提供方会以 SDK 、 人工认证、平台文档的形式提供可公开的部分数据加解密方式,对应于图中的公开环境部分。
所接触到的各种验证方式,有:各种形式的 Token 结合使用、OAuth 验证对象传输。
公私钥的非对称加密 + session key 对称加密
公私钥的加密和解密方式,跟 Https 的公私钥加密是有部分相似的。
加密的过程中,一样使用的是公钥加密和私钥解密。区别是 Https 中使用的是 CA 来进行签名的核验和公钥的发布,使用的是系统层面写定的 CA 证书,相比于网络环境中公开的天然具有更高的安全性。
说回到 API 的公私钥的加解密方式,这样的方式中:
无论签名还是数据,使用的都是非对称加密和解密的方式进行。这类运算,通常使用的算法是比较复杂的,会对计算性能有一定的要求和影响。为了提高程序的性能表现,我们需要更加高效且能保证安全的加解密方式。
于是就有了公私钥的非对称加密 + Session Key 的方式。
这种方式,通信过程:
- 发送方使用加密方式 b 加密自己的签名,接收方就可以利用解密方法 b 对签名进行解密操作。
- 接收方生成一个 Session Key ,之后使用加密方法 a 对 Session Key 进行加密操作。之后接收方将加密之后的 Session Key 发送给发送方。发送方使用解密方法 a 对加密之后的 Session Key 进行解密操作。
- 这样发送和接收双方都得到了相同的 Session Key ,之后的数据都使用 Session Key 作为密钥进行加密。协商之后,流通在网络环境中只有加密的数据,而不会再有和 Session Key 有关的数据。
实际生产中,这样的措施还有一定的安全风险。所以一般会对生成的 Session Key 有时效限制,在失效之后会重新进行第二步的 Session Key 生成和传输。
① 保证对称加密的密钥具有时效性,避免固定的规律被破解
② 由非对称加密转为了非对称加密
一、Session Key 被获取之后,如何保证安全?
首先,Session Key 被获取本身就非常困难。其次,被获取之后,Session Key 是具有时效性的,获取之后在一定时间之后会失效。再者,知道了 Session Key ,但是无法知道签名的加密方法,无法伪造发送方的身份,还是无法正常调用接口。
二、该方式和 Https 有什么区别?
实际上,该方式就是现在普遍使用的 Https 的方法的原理。先非对称加密,之后对称加密。只是对于时效性的控制上,会存在区别。
生产环境中的 Session Key/Token/Signature 更新实现
根据所接触过的生产案例,对于 Session Key/Token/Signature (简称 Token)数据,都会有时效性限制。一般常用的有三种方式更新:
一、附带一个 Refresh 值
在发送请求的时候,附带一个 refresh key ,该值和 token 的失效时长并不保持一致,通常会比 token 拥有更长的有效期。于是,两者就会存在一个时间差。当处在这段时间差时,表示 token 已经失效,但是 refresh 值还是有效状态,这个时候就可以将这两个值重新返回新值。
设计上,需要将这两个值设置为 k-v 结构,在使用时才能保证安全性。
二、使用原始的 client_id 和 client_secret 重新请求生成
一旦 token 失效,会提供一个专门的接口用来生成 token 并且回调。这个时候就需要根据原有的 client_id 以及 client_secret 进行重新获取 token 操作。
三、使用一次性 Token
每一次请求都会返回新的 token 值覆盖掉原有的 token 值。这意味着 token 只有一次的有效期。这样接口在返回的时候,会需要每次都返回下一次需要使用的 token 。
三者的选择:
在效率上考量,第二种会更好一些。因为网络 IO 中不需要服务方返回 Token 值,传输的数据量会更好。
安全性上考虑,一次性 token 的方案会更好。
难易程度考虑,前两者区别不大,第三种会对客户端带来一定的不便。
总结
接口的安全性,和网络是分不开的。所以大多数情况下,还是需要考虑网络环境的安全性。提到的解决方案,也有很多思想借鉴于网络协议。
参考文档:API接口入门(二):API接口的签名验签和加解密原理
API 接口签名验签_新猿一马的博客-CSDN博客_接口签名