接口安全通讯规则
网络货运相关接口数据传输需经过数据加密及数据签名两个过程,以确保数据在传递时的安全性。
以下是加密后发送数据的请求格式:
POST 请求方式:
json
{
"body": "加密数据",
"sign": "签名",
"timestamp": "时间戳"
}GET 请求方式:
body=加密数据&sign=签名×tamp=时间戳数据加解密
使用AES进行数据加密,密钥需在平台生成,一般在菜单「API安全」-> 「密钥管理」中获取(clientSecret)。
POST请求:Json格式数据可转为字符串,然后使用 clientSecret 作为密钥,进行加密。
GET请求:Url参数格式数据,如:b=1&a=2(无需排序),直接使用 clientSecret 作为密钥,进行加密。
返回的数据如果是密文,可使用 clientSecret 作为密钥,进行解密。
数据签名
使用标准签名算法(SHA256WithRSA)进行数据签名,RSA密钥对由客户自行生成,然后填写RSA公钥到平台。一般在菜单「API安全」-> 「密钥管理」RSA公钥处填写。
签名算法:
1、获取加密后的body;
2、获取系统时间戳;
3、将步骤1、2得到的结果,用 # 连接;
4、将步骤3得到的结果,进行MD5摘要计算;
5、将步骤4得到的结果,用RSA私钥进行签名。
请求时效
请求在 10 分钟内有效,超过 10 分钟后,请求将无法通过验证。
JAVA代码示例
java
import com.alibaba.fastjson2.JSONObject;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SignUtils {
public static void main(String[] args) throws Exception {
//在菜单「API安全」-> 「密钥管理」中获取(clientSecret)。
String clientSecret = "YqW641o8PsHejCDN...";
//私钥字符串(Base64 编码格式)
String privateKey = "MIIEugIBADANBgkqhkiG9w0BAQEFAASCBK........";
//待发送的原始数据参数
JSONObject data = new JSONObject();
data.put("r1", "123");
data.put("a1", "456");
//数据加密
String encrypted = aesEncrypt(data.toString(), clientSecret);
long timestamp = System.currentTimeMillis();
JSONObject request = new JSONObject();
request.put("body", encrypted);
request.put("sign", signBody(encrypted, timestamp, privateKey));
request.put("timestamp", timestamp);
// 以下是发送到服务器的数据POST格式
System.out.println("Signed JSON: " + request.toJSONString());
// 发送请求示例(假设使用 HttpClient)
HttpUtil.createPost("https://www.xxyb.cn/v4/api/xxx")
.header("token", token)
.body(request.toString())
.execute()
.body();
}
/**
* AES加密
*/
public static String aesEncrypt(String content, String clientSecret) throws Exception {
byte[] key = clientSecret.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] combined = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(combined);
}
/**
* AES解密
*/
public static String aesDecrypt(String encryptContent, String clientSecret) throws Exception {
byte[] key = clientSecret.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptContent);
byte[] original = cipher.doFinal(encryptedBytes);
return new String(original, StandardCharsets.UTF_8);
}
/**
* 数据签名
*
* @param encryptContent 加密后的请求数据
* @param timestamp 时间戳
* @param privateKeyStr 私钥字符串(Base64 编码)
* @return 签名
*/
public static String signBody(String encryptContent, long timestamp, String privateKeyStr) throws Exception {
// 签名内容
String message = encryptContent + "#" + timestamp;
// MD5摘要计算
byte[] hash = md5(message).getBytes(StandardCharsets.UTF_8);
// 加载私钥
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 使用 SHA256withRSA 签名算法
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(hash);
// 生成签名
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
}
/**
* 计算MD5值
*
* @param data 数据
* @return MD5摘要值
*/
public static String md5(String data) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}