调用Kraken API查询账户余额时出现403错误的求助
调用Kraken REST API查询账户余额时返回403禁止访问
我使用OpenSSL、CPR和Chrono库调用Kraken的RESTful API查询账户余额,但收到403请求禁止的响应。
原代码
#include <iostream> #include <string> #include <cpr/cpr.h> #include <nlohmann/json.hpp> #include <chrono> #include <openssl/sha.h> #include <openssl/hmac.h> using namespace std; using namespace cpr; using namespace chrono; using json = nlohmann::json; int main(){ //variables string key = "XXXXXXXXXXX"; string secret = "XXXXXXXXXXXXXXX"; string baseUrl = "https://api.kraken.com/0/private/Balance"; //get nonce const auto p1 = system_clock::now(); int T1 = duration_cast<seconds>(p1.time_since_epoch()).count(); string timestamp = to_string(t1); string postData = "nonce=" + timestamp; //get signature string rPath = "/0/private/Balance"; string message = rpath + timestamp + postData; unsigned char hmac_result[EVP_MAX_MD_SIZE]; unsigned int hmac_result_len; HMAC( EVP_sha256(), secret.c_str(), secret.length(), (unsigned char*)message.c_str(), message.length(), hmac_result, &hmac_result_len ); string signature = string(reinterpret_cast<char*>(hmac_result), hmac_result_len); //cpr request Response r; Header header; header.insert({ "API-Key", key }); header.insert({ "API-Sign", signature }); r = Post(Url{ baseUrl }, Body{ postData }, Header{ header }); cout << "Status Code: " << r.status_code << endl; cout << r.text << endl; }
原错误响应
Status Code: 403 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="robots" content="noindex" /> <title>That is Not Allowed</title> <style type="text/css">body,html{height:100%;width:100%}body{background-color:#0d0c52;color:#fff;font-family:Helvetica,sans-serif;margin:0}article{display:grid;grid-template-columns:100%;grid-template-rows:auto 1fr auto;min-height:100%}footer,header{background-color:#5740d9;padding:34px 0 30px 40px}main{align-items:center;display:inline-grid;grid-template-columns:50% 50%;padding:50px 0}main>div:first-child{padding-left:30%}@media (max-width:800px){main{grid-template-columns:100%}main>div:first-child{padding:0 40px}main>div:last-child{display:none}}a{color:#fff}</style> </head>
问题分析与修正方案
403错误的核心原因是签名逻辑不符合Kraken要求,加上变量笔误,具体修正点如下:
1. 修正Nonce变量大小写笔误
原代码中定义了int T1,但后续用了to_string(t1)(小写t),导致nonce值无效,直接破坏签名。需统一变量名:
long long T1 = duration_cast<seconds>(p1.time_since_epoch()).count(); string timestamp = to_string(T1);
2. 严格遵循Kraken签名规则
Kraken的签名步骤为:
- 对POST数据(含nonce)计算SHA-256哈希
- 将API路径与SHA-256哈希结果拼接成消息
- 用base64解码后的API密钥,通过HMAC-SHA512算法对消息签名
- 对签名结果做base64编码,作为
API-Sign头的值
原代码错误使用SHA-256做HMAC,未解码密钥,也未对签名结果编码。需补充base64编解码函数,并修正签名逻辑:
// 新增base64编解码工具函数 #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/buffer.h> #include <vector> string base64_encode(const unsigned char* data, size_t length) { BIO *bio, *b64; BUF_MEM *bufferPtr; b64 = BIO_new(BIO_f_base64()); bio = BIO_new(BIO_s_mem()); bio = BIO_push(b64, bio); BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); BIO_write(bio, data, length); BIO_flush(bio); BIO_get_mem_ptr(bio, &bufferPtr); BIO_set_close(bio, BIO_NOCLOSE); BIO_free_all(bio); string result(bufferPtr->data, bufferPtr->length); BUF_MEM_free(bufferPtr); return result; } vector<unsigned char> base64_decode(const string& input) { BIO *bio, *b64; vector<unsigned char> buffer(input.size()); int decodedLen = 0; b64 = BIO_new(BIO_f_base64()); bio = BIO_new_mem_buf(input.data(), input.size()); bio = BIO_push(b64, bio); BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); decodedLen = BIO_read(bio, buffer.data(), input.size()); BIO_free_all(bio); buffer.resize(decodedLen); return buffer; } // 修正后的签名逻辑 unsigned char sha256_hash[SHA256_DIGEST_LENGTH]; SHA256((unsigned char*)postData.c_str(), postData.length(), sha256_hash); string message; message.reserve(rPath.length() + SHA256_DIGEST_LENGTH); message += rPath; message.append((char*)sha256_hash, SHA256_DIGEST_LENGTH); vector<unsigned char> decoded_secret = base64_decode(secret); unsigned char hmac_result[EVP_MAX_MD_SIZE]; unsigned int hmac_result_len; HMAC( EVP_sha512(), decoded_secret.data(), decoded_secret.size(), (unsigned char*)message.c_str(), message.length(), hmac_result, &hmac_result_len ); string signature = base64_encode(hmac_result, hmac_result_len);
3. 添加必要的请求头
需添加Content-Type头,确保Kraken正确解析POST数据:
header.insert({ "Content-Type", "application/x-www-form-urlencoded" });
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

