Webhook-验签
在商家端后台,添加webhook订阅的时候,会有一个是否验签的选项,您开启后,并生成了secretKey密钥,那么在推送数据的时候,将会出现一个access_key. 也就是签名。
签名是为了安全,对于fecify推送的数据,接收方先进行签名的验证,验证通过后,在继续其他的数据的处理,因为在理论上,知道您的推送地址的任何人都可以推送数据到 您的接收地址url。但是在实际操作中,这种情况很少发生,因此,为了省劲,您不进行验签也没啥大问题(可以将您的接收数据的url用的长一点),这个看您对数据安全的衡量。
签名的本质:就是fecify这边通过一个算法逻辑,将发送的post数据和密钥通过算法得到一个字符串,这个字符串就是签名字符串。 发送到第三方系统后,第三方系统本地也保存了一份相同的密钥字符串,第三方系统使用相同的算法,通过接收的post数组和密钥得到一个字符串。 将计算得到的签名字符串,和post发送的签名字符串进行核对,如果字符串一致,则验签通过,否则验签失败。 大多数的支付方式发送webhook消息(譬如:订单支付成功,订单支付失败等),都会加入签名机制,用于验证发送数据的安全性。
验签步骤逻辑:
1.fecify会请求第三方系统的url,post请求,会发送一个post参数数组。为了容易表述,我们将post参数数组赋值到变量$postParams
2.从post参数中得到fecify发送的签名字符串: $postParams['access_key']
(也就是post数组,数组key为access_key
就是系统发送的签名字符串)
然后我们需要通过逻辑计算出来一个签名,然后和post参数中传递的签名进行字符串对比,如果一致则验签通过,如果不一致则验签失败。
3.计算签名
3.1fecify系统中创建webhook后,会生成一个密钥,您需要将密钥保存到第三方系统中,用于验签。
3.2计算签名函数(通过下面的php代码部分可以看到该函数的逻辑逻辑)
getSignKey($postParams, $secret_key)
- $postParams 是post数组
- $secret_key是私钥字符串
3.3通过调用函数getSignKey()
来得到签名,然后核验计算出来的签名和系统发送的签名是否一致即可
- 字符串一致,验签通过
- 字符串不一致,验签失败
签名原理
webhook,本质是一个post类型的api请求,发送一个post数组参数。为了容易表述,我们将post参数数组赋值到变量$postParams
1.我们通过一个封装函数,进行签名的生成,再这个函数里面,将密钥加入$postParams
, 数组key为'secret_key'
, 譬如php代码: $postParams['secret_key'] = $secretKey;
($secretKey是密钥字符串)
2.将推送的post数组,进行排序, 对数组根据键名升序排序
3.将排序后的数组,转换成json格式的字符串
4.进行sha256哈希加密处理,返回的字符串就是签名
到这里,通过计算就得到签名字符串了。
php示例代码
/**
* 得到签名
* @param $params
* @param $secretKey
* @return mixed
* @author Terry
*/
public static function getSignKey(array $params, $secretKey)
{
if (isset($params['access_key'])) {
// 如果存在key:access_key,则该字段不参与签名,因为这个字段是签名
unset($params['access_key']);
}
// 加入私钥(本地存储)
$params['secret_key'] = $secretKey;
$params = self::paraFilter($params);
$params = self::argSort($params);
$params = json_encode($params);
return hash('sha256', $params);
}
public static function paraFilter($para)
{
$para_filter = array ();
foreach ($para as $key=>$va) {
$para_filter [$key] = $para [$key];
}
return $para_filter;
}
public static function argSort($para)
{
ksort ( $para );
reset ( $para );
return $para;
}
调用:
getSignKey($postParams, $secret_key)
- $postParams 是post数组
- $secret_key是私钥字符串