x-ca-key,x-ca-nonce,x-ca-signature与x-ca-signature-headers探索
请求的curl如下
代码语言:javascript复制curl 'https://bizapi.csdn.net/blog-console-api/v3/editor/getArticle?id=xxxxxxxxx&model_type='
-H 'accept: */*'
-H 'accept-language: zh-CN,zh;q=0.9,en;q=0.8'
-H 'cookie: '
-H 'origin: https://editor.csdn.net'
-H 'referer: https://editor.csdn.net/'
-H 'sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"'
-H 'sec-ch-ua-mobile: ?0'
-H 'sec-ch-ua-platform: "Windows"'
-H 'sec-fetch-dest: empty'
-H 'sec-fetch-mode: cors'
-H 'sec-fetch-site: same-site'
-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36'
-H 'x-ca-key: 203803574'
-H 'x-ca-nonce: d73db41b-e7bd-493b-8fe3-3a6995a422b3'
-H 'x-ca-signature: rfYFgB84YDneWj2onHHmtJWeKUTsKC3EKsIurbvvR7E='
-H 'x-ca-signature-headers: x-ca-key,x-ca-nonce'
核心js文件
app.chunk.de89d64e.js
代码语言:javascript复制 _ = function(t) {
var e = t.meth
, n = t.url
, r = t.appSecret
, a = t.accept
, o = t.date
, l = t.contentType
, d = t.params
, m = t.headers
, g = "";
d || -1 === n.indexOf("?") ? d || (d = {}) : (d = v(n),
n = n.split("?")[0]);
g = e "n",
g = a "n",
g = "n",
g = l "n",
g = o "n";
var _ = h(m)// {x-ca-key: '203803574', x-ca-nonce: '924136a4-5eca-42ba-a675-34036764b896'}
, b = c()(s()(_)).sort() //['x-ca-key', 'x-ca-nonce']
, w = !0// treu
, y = !1// false
, x = void 0; //false
try {
// x-ca-key:203803574nx-ca-nonce:924136a4-5eca-42ba-a675-34036764b896n
for (var k, C = i()(b); !(w = (k = C.next()).done); w = !0) {
var L = k.value;
g = L ":" _[L] "n"
}
} catch (t) {
y = !0,
x = t
} finally {
try {
!w && C.return && C.return()
} finally {
if (y)
throw x
}
}
var S = /^(?=^.{3,255}$)(http(s)?://)?(www.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.csdn.net)/
//n 'https://bizapi.csdn.net/blog-console-api/v3/mdeditor/saveArticle'
// T '/blog-console-api/v3/mdeditor/saveArticle'
, T = n.replace(S, "");
return g = f(T, d),
// g 'POSTn*/*nnapplication/jsonnnx-ca-key:203803574nx-ca-nonce:939abdaa-0bdd-4eba-a720-e8fc0b151621n/blog-console-api/v3/mdeditor/saveArticle'
u()(g, r).toString(p.a)
}
入参t
代码语言:javascript复制{
"meth": "POST",
"url": "https://bizapi.csdn.net/blog-console-api/v3/mdeditor/saveArticle",
"accept": "*/*",
"date": "",
"contentType": "application/json",
"headers": {
"Content-Type": "application/json",
"Accept": "*/*",
"X-Ca-Key": "203803574",
"X-Ca-Nonce": "eff837eb-901e-403f-9ed3-d17d0227b16b"
},
"appSecret": "9znpamsyl2c7cdrr9sas0le9vbc3r6ba"
}
说明:
- X-Ca-Key为固定值
- X-Ca-Nonce是随机串,只要随机串相同,同一个请求(get请求参数也要相同)算出来的x-ca-signature就是一样的
- appSecret固定值,可以认为是加密秘钥
- g最终要加密的字符串,x-ca-signature就是g用appSecret加密的结果.
'POSTn*/*nnapplication/jsonnnx-ca-key:203803574nx-ca-nonce:eff837eb-901e-403f-9ed3-d17d0227b16bn/blog-console-api/v3/mdeditor/saveArticle'
Java代码实现
自定义实体
代码语言:javascript复制@Data
@Accessors(chain = true)
public class HmacSHA256Dto {
public String method;
public String accept;
public String contentType="";
public String date = "";
public String url;
public String appSecret = "9znpamsyl2c7cdrr9sas0le9vbc3r6ba";
public Map<String,Object> params;
public String xCaKey = "203803574";
public String xCaNonce;
}
获取要加密的字符串
get请求需要对参数排序,排序规则可能不对,欢迎指导,微信:lxwjy88,或评论区留言
代码语言:javascript复制@SneakyThrows
public static String getMessage(HmacSHA256Dto hmacSHA256Dto) {
URL url = new URL(hmacSHA256Dto.url);
String path = url.getPath();
StringBuffer sb = new StringBuffer();
sb.append(hmacSHA256Dto.method "n")
.append(hmacSHA256Dto.accept "nn")
.append(hmacSHA256Dto.contentType "n")
.append(hmacSHA256Dto.date "n")
.append("x-ca-key:" hmacSHA256Dto.xCaKey "n")
.append("x-ca-nonce:").append(hmacSHA256Dto.xCaNonce "n")
.append(path);
Map<String, Object> params = hmacSHA256Dto.params;
if (params != null) {
// 需要对参数排序,可能是默认排序也可能是其他排序,暂时没有用多参数测试过,临时用key排序,不知道对不对?欢迎留言指导,也可加微信:lxwjy88一起探讨
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i ) {
String value = keys.get(i);
if (StringUtils.hasText(value)) {
if (i == 0) {
sb.append("?").append(value).append("=").append(params.get(value));
} else {
sb.append("&").append(value).append("=").append(params.get(value));
}
}
}
}
return sb.toString();
}
加密
代码语言:javascript复制@SneakyThrows
public static String hmacSHA256(String secret, String message) {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
hmacSha256.init(secret_key);
byte[] bytes = hmacSha256.doFinal(message.getBytes());
String s = Base64.getEncoder().encodeToString(bytes);
System.out.println(s);
return s;
}
测试
代码语言:javascript复制 public static void main(String[] args) {
String appSecret = "9znpamsyl2c7cdrr9sas0le9vbc3r6ba";
HmacSHA256Dto hmacSHA256Dto = new HmacSHA256Dto();
hmacSHA256Dto.setMethod("POST").setAccept("*/*").setContentType("application/json").setXCaNonce("939abdaa-0bdd-4eba-a720-e8fc0b151621").setUrl("https://bizapi.csdn.net/blog-console-api/v3/mdeditor/saveArticlen");
String message = getMessage(hmacSHA256Dto);
hmacSHA256(appSecret, message);
}
小技巧
至于x-ca-signature生成的对不对,可以用页面产生的X-Ca-Nonce作为随机串,看看自己计算出来的和页面生成的x-ca-signature一不一致,如果一致可以认为生成x-ca-signature的逻辑是对的
总结
- x-ca-key与x-ca-signature-headers可以认为是固定值
- x-ca-nonce随机串,应该只要满足位数和格式即可
- x-ca-signature加密串
- 核心是计算需要加密的字符串,然后对字符串加密,加密算法是hmacSHA256