加签和验签
为了确保你的应用与 SHOPLINE 平台之间的数据交互是安全且未被篡改的,你可能需要在特定的场景下对请求进行签名或验证签名:
- 当向 SHOPLINE 发起 HTTP 请求时,对请求进行签名。
- 当 SHOPLINE 向你发起 HTTP 请求时,对请求进行验证签名。
通过阅读本文,你将了解到具体的签名算法以及适用的场景。
应用场景
Admin API 授权
在你使用 Admin Rest API 或 Admin Graphql API 之前,你需要完成授权流程的对接。在授权过程中,涉及到签名和验签操作。详细内容请参阅应用授权。
Webhooks验签
当 Webhook 被触发后,SHOPLINE 将向你配置的地址推送 HTTP 请求。在推送数据时,SHOPLINE 会对请求进行签名处理。你收到请求后,可通过验证签名来验证数据的合法性。详细信息请参阅Webhook 事件推送规约。
签名算法
HMAC-SHA256
HMAC-SHA256 是一种数据验证代码,它采用了 SHA-256 哈希算法并结合了密钥和消息进行加密。它是基于散列函数的消息认证码,由以下两个算法组成:
- HMAC(Hash-based Message Authentication Code)
如需了解更多算法内容,请参考: HMAC
- SHA-256(Secure Hash Algorithm 256-bit)
如需了解更多算法内容,请参考:SHA-2。
操作步骤
前提条件:
- 确认请求的场景是否用到了签名算法,请查阅: 应用场景
- 获取签名所需要的秘钥,获取步骤参考:算法密钥获取步骤
- 确认自己的请求方法 选择对应的操作步骤
- 如果你的应用可以更新了密钥,请及时更新算法用到的密钥,否则可能会造成加验签失败
GET 请求操作步骤
加签
- 组装请求原始的Query参数后,若你的query参数没有经过URLEncode,需要先进行URLEncode,然后对 Query参数进行字典序排列,得到待签名的字符串(source)。
- 使用待签名的字符串(source)和应用密钥(APP Secret)作为参数调用 HMAC-SHA256 算法加签得到签名(sign)。
- 把签名(sign)拼接到原始Query参数的后面,得到最终请求的 Query参数
验签
- 得到请求原始的 Query 参数后,提取 "sign" 这个 Field 后获得签名(sign),对剩余 Query 参数的 Fields 进行字典序排列,得到待签名的字符串(source)。
- 使用待签名的字符串(source)和应用密钥(APP Secret)作为参数调用 HMAC-SHA256 算法加签得到签名(hmacsha256Sign)。
- 签名(sign)与签名(hmacsha256Sign)进行比较,如果相等则认为签名合法,否则认为签名非法
在判断签名合法时,即便签名相等,此时如果该接口的 Query 参数中含有 timestamp
Field,可用当前系统时间戳(13位)减去 timestamp
Field 的值,如果大于一定的时间间隔(SHOPLINE使用的时间间隔为10
分钟),可判定为签名非法,因为该请求可能被泄露后被用于非法模拟请求,添加该额外校验可让程序更加安全。
POST 请求操作步骤
加签
- 组装请求 Body 字符串后(如果请求Body为空,可以使用空字符串),在 Body 字符串后拼接当前系统时间戳(timestamp),长度13位,得到待签名的字符串(source)。
- 使用待签名的字符串(source)和应用密钥(APP Secret)作为参数调用 HMAC-SHA256 算法加签得到签名(sign)。
- 把签名(sign)和当前系统时间戳(timestamp)这两个 Fields 添加到请求 Header 中,请求签名信息组装完成
验签
在需要验证签名的场景下 SHOPLINE 向你发起 HTTP POST 请求
- 原始请求的 Header 中存在 "timestamp" Field 时,取该值并拼接到原始请求的 Body 后,得到待签名的字符串(source)。
- 使用待签名的字符串(source)和应用密钥(APP Secret)作为参数调用 HMAC-SHA256 算法加签得到签名(hmacsha256Sign)。
- 从原始请求的 Header 中获取 "sign" 这个 Field 的值,使用该值与签名(hmacsha256Sign)的值进行比较,如果相等则认为签名合法,否则认为签名非法
在判断签名合法时,即便签名相等,此时如果该接口的 Header 参数中含有 timestamp
Field,可用当前系统时间戳(13位)减去 timestamp
Field 的值,如果大于一定的时间间隔(SHOPLINE使用的时间间隔为10
分钟),可判定为签名非法,因为该请求可能被泄露后被用于非法模拟请求,添加该额外校验可让程序更加安全。
算法示例
采用 HMAC-SHA256 算法配合算法密钥: APP Secret,对请求报文或请求参数进行加签,以下是几种常用语言加签的实现
JAVA
package com.shopline.demo
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class HmacDemo {
public static void main(String[] args) {
System.out.println(hmacSha256("The content to be signed", "Your APP Secret"));
}
/**
* hmacSha256
*
* @param source The content to be signed
* @param secret Your APP Secret
* @return
*/
public static String hmacSha256(String source, String secret) {
if (StringUtils.isNotEmpty(secret) && StringUtils.isNotEmpty(source)) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] bytes = sha256_HMAC.doFinal(source.getBytes(StandardCharsets.UTF_8));
return new String(Hex.encodeHex(bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
PHP
<?php
class HmacDemo {
/**
* Generate HMAC-SHA256 signature.
*
* @param string $source The content to be signed.
* @param string $secret Your APP Secret.
* @return string HMAC-SHA256 signature as a hex string or an empty string if an error occurs.
*/
public static function hmacSha256($source, $secret) {
if (!empty($secret) && !empty($source)) {
try {
return hash_hmac('sha256', $source, $secret);
} catch (Exception $e) {
error_log("Error generating HMAC-SHA256 signature: " . $e->getMessage());
return '';
}
}
return '';
}
}
// Example usage
$source = "The content to be signed";
$secret = "Your APP Secret";
echo "HMAC-SHA256 Signature: " . HmacDemo::hmacSha256($source, $secret);
?>
Python
#python 3
import hmac
import hashlib
def generate_hmac_sha256(source, secret):
if not source or not secret:
raise ValueError("Source and secret must not be empty.")
try:
# Create HMAC-SHA256 signature
signature = hmac.new(bytes(secret, 'utf-8'), msg=bytes(source, 'utf-8'), digestmod=hashlib.sha256).hexdigest()
return signature
except Exception as e:
print(f"Error generating HMAC-SHA256 signature: {e}")
return None
#Example usage
source = 'The content to be signed'
secret = 'Your APP Secret'
signature = generate_hmac_sha256(source, secret)
if signature:
print(f"HMAC-SHA256 Signature: {signature}")
else:
print("Failed to generate HMAC-SHA256 signature.")
算法密钥获取步骤
应用密钥(App Secret)可在【合作伙伴控制面板】中获取。在应用列表中,点击应用名称即可查看应用的 App Secret。