API連携

バイナンスAPI署名の生成方法:HMAC-SHA256の多言語実装ガイド

バイナンス(Binance)API HMAC-SHA256署名を完全解説:アルゴリズムの原理、パラメータのシリアライズ規則、URLエンコードの詳細、Ed25519による代替案、Python/Node.js/Go/Rust/Javaでの実装例、よくある署名エラーのトラブルシューティング。

バイナンス(Binance)API署名の標準アルゴリズムは HMAC-SHA256 です。その仕組みは、シークレットキー(Secret Key)を鍵、クエリ文字列をメッセージとして、64文字の16進数文字列を生成し、それを signature パラメータとしてリクエストの末尾に付加するというものです。2023年からは、よりセキュリティの高い Ed25519 非対称署名スキームも導入されました。この記事では、アルゴリズムの原理、5つの言語での実装、および8つの一般的な署名エラーの解決方法を詳しく解説します。バイナンスアカウントをお持ちでない方は、まず バイナンス公式サイト で登録を完了させてください。アカウントがない方は 無料登録 も可能です。

一、HMAC-SHA256 の数学的原理

HMAC(Hash-based Message Authentication Code)は、ハッシュ関数に基づいたメッセージ認証コードであり、以下の公式で表されます:

HMAC(K, m) = H((K ⊕ opad) || H((K ⊕ ipad) || m))

ここで:

  • K は鍵(シークレットキー)
  • m はメッセージ(クエリ文字列)
  • H は SHA256 ハッシュ関数
  • ipad = 0x36 を64回繰り返したもの
  • opad = 0x5C を64回繰り返したもの
  • ⊕ は排他的論理和(XOR)、|| は結合を意味します

バイナンスでの具体的なプロセス

  1. すべてのパラメータを順番に key1=value1&key2=value2 の形式で結合します。
  2. シークレットキーを HMAC の鍵、上記の文字列をメッセージとして使用します。
  3. SHA256 ダイジェストを計算し、32バイトを出力します。
  4. これを64文字の16進数文字列に変換します。

二、バイナンス署名の3つのパラメータ規則

規則 1:パラメータの順序は署名時とリクエスト時で一致させる

# 正解:署名に使用した文字列とリクエストの query が一致している
params = {"symbol": "BTCUSDT", "timestamp": 1713027384562}
signature = hmac_sha256("symbol=BTCUSDT&timestamp=1713027384562")
final_query = "symbol=BTCUSDT&timestamp=1713027384562&signature=" + signature

# 不正解:署名に使用した順序と final_query の順序が異なると、-1022 エラーになります。

規則 2:signature フィールド自体は署名対象に含めない

# signature フィールドは常に最後に配置し、HMAC 計算には含めません。
params = {"symbol": "BTCUSDT", "timestamp": 1713027384562}
sig = hmac_sha256(urlencode(params))  # まず署名を計算
params["signature"] = sig               # その後で追加する

規則 3:数値に引用符を付けない、文字列に空白を入れない

# 正しい形式
timestamp=1713027384562

# 誤った形式(署名の結果が変わってしまいます)
timestamp="1713027384562"
timestamp= 1713027384562

三、Python による標準実装

import hmac
import hashlib
from urllib.parse import urlencode

SECRET_KEY = "YOUR_SECRET_KEY"

def sign(params: dict) -> str:
    """標準的な署名実装"""
    query = urlencode(params)
    return hmac.new(
        SECRET_KEY.encode('utf-8'),
        query.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

# テスト
params = {
    "symbol": "BTCUSDT",
    "side": "BUY",
    "type": "LIMIT",
    "timeInForce": "GTC",
    "quantity": "0.001",
    "price": "60000.00",
    "timestamp": 1713027384562
}
print(sign(params))
# 出力例: b42e1fa3d8c7e9f2a6b5c4d1e8f9a0b3c2d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9

四、Node.js による標準実装

const crypto = require('crypto');

const SECRET_KEY = 'YOUR_SECRET_KEY';

function sign(params) {
  // URLSearchParams は自動的にエンコードを処理します
  const query = new URLSearchParams(params).toString();
  return crypto
    .createHmac('sha256', SECRET_KEY)
    .update(query)
    .digest('hex');
}

const params = {
  symbol: 'BTCUSDT',
  side: 'BUY',
  type: 'LIMIT',
  timeInForce: 'GTC',
  quantity: '0.001',
  price: '60000.00',
  timestamp: Date.now()
};

console.log(sign(params));

注意:Node.js の JSON.stringify で得られるのは JSON 文字列であり、署名には使用できません。必ず URLSearchParams を使用するか、手動で結合してください。

五、Go による標準実装

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "net/url"
)

func sign(params url.Values, secret string) string {
    query := params.Encode()
    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(query))
    return hex.EncodeToString(h.Sum(nil))
}

func main() {
    params := url.Values{}
    params.Set("symbol", "BTCUSDT")
    params.Set("side", "BUY")
    params.Set("type", "LIMIT")
    params.Set("timeInForce", "GTC")
    params.Set("quantity", "0.001")
    params.Set("price", "60000.00")
    params.Set("timestamp", "1713027384562")

    fmt.Println(sign(params, "YOUR_SECRET_KEY"))
}

重要url.Values.Encode()自動的にアルファベット順にソートし、URLエンコードを行います。これは Python の urlencode と一致した出力を提供します。

六、Rust による実装

use hmac::{Hmac, Mac};
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

fn sign(query: &str, secret: &str) -> String {
    let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
        .expect("HMAC init error");
    mac.update(query.as_bytes());
    hex::encode(mac.finalize().into_bytes())
}

fn main() {
    let query = "symbol=BTCUSDT&side=BUY&type=LIMIT&timeInForce=GTC&quantity=0.001&price=60000.00&timestamp=1713027384562";
    let secret = "YOUR_SECRET_KEY";
    println!("{}", sign(query, secret));
}

Cargo.toml の設定:

[dependencies]
hmac = "0.12"
sha2 = "0.10"
hex = "0.4"

七、Java による実装

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class BinanceSigner {
    public static String sign(String query, String secret) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(
            secret.getBytes(StandardCharsets.UTF_8),
            "HmacSHA256"
        );
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(keySpec);
        byte[] hash = mac.doFinal(query.getBytes(StandardCharsets.UTF_8));

        StringBuilder hex = new StringBuilder();
        for (byte b : hash) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {
        String query = "symbol=BTCUSDT&timestamp=1713027384562";
        String secret = "YOUR_SECRET_KEY";
        System.out.println(sign(query, secret));
    }
}

八、Ed25519 による代替案(新規)

2023年、バイナンスは Self-generated API Key を導入し、Ed25519 非対称署名の使用を可能にしました。利点:シークレット(秘密鍵)がローカル環境から外に出ることはありません

1. 鍵ペアの生成

openssl genpkey -algorithm Ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem
# public.pem をバイナンスの API 管理ページにアップロードします

2. Python による Ed25519 署名

from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64

with open("private.pem", "rb") as f:
    private_key = load_pem_private_key(f.read(), password=None)

def ed25519_sign(query: str) -> str:
    signature_bytes = private_key.sign(query.encode())
    return base64.b64encode(signature_bytes).decode()

# 使用方法は HMAC と似ていますが、署名結果は hex ではなく base64 になります
query = "symbol=BTCUSDT&timestamp=1713027384562"
sig = ed25519_sign(query)
final_url = f"/api/v3/order?{query}&signature={sig}"

九、署名エラーのチェックリスト

-1022 Signature for this request is not valid エラーが発生した場合は、以下の項目を順番に確認してください:

# 項目 検証方法
1 シークレットキーの余計な空白/改行 len(secret) を出力し、64文字であることを確認
2 パラメータの順序不一致 署名に使用した文字列と実際の query 文字列を比較
3 signature が HMAC に含まれている 署名を計算してからフィールドを追加しているか確認
4 URL エンコード方式の差異 @%40 とするかなど、署名とリクエストで一貫させる
5 数値に引用符を付けている timestamp="123"timestamp=123 では署名結果が異なります
6 文字コードのエラー 非ASCII文字は必ず UTF-8 でエンコードする
7 鍵タイプの混同 HMAC キーには HMAC アルゴリズム、Ed25519 キーには Ed25519 を使用
8 POST body vs query string パラメータは body または URL のどちらか一方に配置する(重複は不可)

十、署名デバッグ用ツールコード

def debug_sign(params, secret):
    """各ステップを詳細に出力"""
    query = urlencode(params)
    print(f"Step 1. クエリ文字列: {query}")
    print(f"        長さ: {len(query)} バイト")

    sig = hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
    print(f"Step 2. 署名: {sig}")
    print(f"        長さ: {len(sig)} 文字(64文字であるべき)")

    final = f"{query}&signature={sig}"
    print(f"Step 3. 最終 URL: {final}")
    return sig

debug_sign({"symbol": "BTCUSDT", "timestamp": 1713027384562}, "YOUR_SECRET")

十一、よくある質問 FAQ

Q1: 同じパラメータでも署名の結果が毎回同じになるのはなぜですか?

A: HMAC-SHA256 は決定論的なアルゴリズムであり、同じ入力に対しては常に同じ出力を返します。そのため、リプレイ攻撃を防ぐために時間戳(timestamp)をミリ秒単位で変化させ、毎回異なる署名が生成されるようにする必要があります。

Q2: 署名からシークレットキーが特定されることはありますか?

A: いいえ、ありません。SHA-256 は一方通行の関数であり、HMAC 値から鍵を逆算することは数学的にほぼ不可能です(約 2^128 回の計算が必要)。シークレットの流出は、管理上のミスによるものがほとんどです。

Q3: signature はなぜ 64 文字なのですか?

A: SHA-256 の出力は 256ビット = 32バイト です。1バイトを2文字の16進数で表すため、合計で 64文字 になります。これ以外の長さになる場合は実装に誤りがあります。

Q4: タイムスタンプにマイクロ秒(microseconds)を使用できますか?

A: できません。バイナンスはミリ秒(13桁の数字)を要求しています。16桁のマイクロ秒を使用すると、数十年後の未来の時間と認識され、-1021 Timestamp out of recv window エラーが発生します。

Q5: Ed25519 と HMAC-SHA256、どちらが安全ですか?

A: Ed25519 の方が安全です。秘密鍵を一切送信せず、バイナンス側には公開鍵のみを渡すため、万が一バイナンスのサーバーが侵害されても秘密鍵は漏洩しません。ただし、Ed25519 は SDK のサポートが HMAC ほど成熟していないため、一般的な取引戦略であれば HMAC で十分と言えます(シークレットをローカルで暗号化保存する場合)。

署名の原理を理解したら、カテゴリナビ に戻って「API連携」カテゴリの他の技術トピックをチェックしましょう。

引き続き閲覧

バイナンスの利用でまだ疑問がありますか?カテゴリページに戻って同じテーマの他のガイドを探しましょう。

カテゴリナビ

関連ガイド

バイナンスAPIの申請方法:APIキー取得と署名生成の完全ガイド 2026-04-14 バイナンス現物API(Spot API)の使い方:ゼロから最初の注文まで、実行可能なサンプルコード 2026-04-14 バイナンスの Futures と Spot API の違いは?エンドポイント・パラメータ・ウェイトの比較 2026-04-14 バイナンスAPIでIP制限を避けるには?レート制限とウェイト計算の仕組みを解説 2026-04-14