You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:09:56