Intégration API

Comment générer la signature de l'API Binance ? Implémentation multi-langage HMAC-SHA256

Guide complet sur la signature HMAC-SHA256 de l'API Binance : principes de l'algorithme, règles de sérialisation des paramètres, détails de l'encodage URL, alternative Ed25519, implémentations en Python/Node.js/Go/Rust/Java et dépannage des erreurs de signature courantes.

L'algorithme standard pour la signature de l'API Binance est le HMAC-SHA256. Le principe consiste à utiliser votre Secret Key comme clé et la chaîne de requête (query string) comme message pour générer une chaîne hexadécimale de 64 caractères, qui est ensuite ajoutée à la fin de la requête en tant que paramètre signature. Depuis 2023, Binance propose également une solution de signature asymétrique Ed25519, plus sécurisée mais moins utilisée. Cet article détaille le fonctionnement de l'algorithme, son implémentation dans 5 langages et le dépannage de 8 erreurs de signature courantes. Si vous n'avez pas encore de compte Binance, veuillez d'abord effectuer votre inscription sur le Site officiel de Binance ; les personnes n'ayant pas de compte peuvent s' inscrire gratuitement.

I. Principes mathématiques du HMAC-SHA256

Le HMAC (Hash-based Message Authentication Code) est un code d'authentification de message basé sur le hachage, dont la formule est :

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

Où :

  • K est la clé (Secret Key)
  • m est le message (chaîne de requête)
  • H est la fonction de hachage SHA256
  • ipad = 0x36 répété 64 fois
  • opad = 0x5C répété 64 fois
  • ⊕ est le OU exclusif (XOR), || est la concaténation

Processus spécifique à Binance :

  1. Concaténer tous les paramètres dans l'ordre sous la forme cle1=valeur1&cle2=valeur2.
  2. Utiliser la Secret Key comme clé HMAC et la chaîne ci-dessus comme message.
  3. Calculer le condensé SHA256 (32 octets).
  4. Convertir en une chaîne hexadécimale de 64 caractères.

II. Les 3 règles des paramètres de signature Binance

Règle 1 : L'ordre des paramètres doit être identique à la signature

# CORRECT : La signature correspond au query de la requête
params = {"symbol": "BTCUSDT", "timestamp": 1713027384562}
signature = hmac_sha256("symbol=BTCUSDT&timestamp=1713027384562")
final_query = "symbol=BTCUSDT&timestamp=1713027384562&signature=" + signature

# ERREUR : Si l'ordre des paramètres utilisé pour la signature diffère de final_query, l'erreur -1022 sera renvoyée.

Règle 2 : Le paramètre signature ne participe pas à la signature elle-même

# Le champ signature est toujours placé à la fin et ne doit pas participer au calcul HMAC
params = {"symbol": "BTCUSDT", "timestamp": 1713027384562}
sig = hmac_sha256(urlencode(params))  # Calculer d'abord la signature
params["signature"] = sig               # Puis l'ajouter

Règle 3 : Pas de guillemets pour les valeurs numériques, pas d'espaces pour les chaînes

# CORRECT
timestamp=1713027384562

# ERREUR (donnera une signature différente)
timestamp="1713027384562"
timestamp= 1713027384562

III. Implémentation standard en Python

import hmac
import hashlib
from urllib.parse import urlencode

SECRET_KEY = "VOTRE_SECRET_KEY"

def sign(params: dict) -> str:
    """Implémentation standard de la signature"""
    query = urlencode(params)
    return hmac.new(
        SECRET_KEY.encode('utf-8'),
        query.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

# Test
params = {
    "symbol": "BTCUSDT",
    "side": "BUY",
    "type": "LIMIT",
    "timeInForce": "GTC",
    "quantity": "0.001",
    "price": "60000.00",
    "timestamp": 1713027384562
}
print(sign(params))
# Sortie attendue : b42e1fa3d8c7e9f2a6b5c4d1e8f9a0b3c2d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9

IV. Implémentation standard en Node.js

const crypto = require('crypto');

const SECRET_KEY = 'VOTRE_SECRET_KEY';

function sign(params) {
  // URLSearchParams gère automatiquement l'encodage
  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));

Remarque : En Node.js, JSON.stringify produit une chaîne JSON qui ne peut pas être utilisée pour la signature ; vous devez utiliser URLSearchParams ou une concaténation manuelle.

V. Implémentation standard en 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, "VOTRE_SECRET_KEY"))
}

Clé : url.Values.Encode() effectue automatiquement un tri alphabétique et un encodage URL, correspondant à la sortie de urlencode en Python.

VI. Implémentation en 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("Erreur d'initialisation HMAC");
    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 = "VOTRE_SECRET_KEY";
    println!("{}", sign(query, secret));
}

Cargo.toml :

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

VII. Implémentation en 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 = "VOTRE_SECRET_KEY";
        System.out.println(sign(query, secret));
    }
}

VIII. Alternative Ed25519 (Nouveau)

En 2023, Binance a lancé la Self-generated API Key permettant d'utiliser des signatures asymétriques Ed25519. Avantage : Le Secret ne quitte jamais votre machine locale.

1. Générer la paire de clés

openssl genpkey -algorithm Ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem
# Téléchargez public.pem sur la page de gestion de l'API Binance

2. Signature Ed25519 en Python

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()

# Utilisation similaire au HMAC, mais le résultat est en base64 au lieu de hex
query = "symbol=BTCUSDT&timestamp=1713027384562"
sig = ed25519_sign(query)
final_url = f"/api/v3/order?{query}&signature={sig}"

IX. Liste de contrôle pour le dépannage des erreurs de signature

Lorsque vous rencontrez l'erreur -1022 Signature for this request is not valid, vérifiez les points suivants dans l'ordre :

# Problème Méthode de vérification
1 Espaces/retours à la ligne superflus dans la Secret Key Affichez len(secret), elle doit faire 64 caractères.
2 L'ordre des paramètres diffère entre signature et requête Affichez la chaîne utilisée par le signer et le query réel pour comparer.
3 Le paramètre signature participe au HMAC Vérifiez si le code calcule la signature avant d'ajouter le champ.
4 Méthode d'encodage URL différente Le caractère @ est codé %40 par certaines bibliothèques, assurez-vous de la cohérence.
5 Guillemets ajoutés aux valeurs numériques timestamp="123" et timestamp=123 produisent des signatures différentes.
6 Erreur de jeu de caractères Les caractères spéciaux doivent être encodés en UTF-8.
7 Mélange des types de clés Une clé HMAC correspond à l'algorithme HMAC, Ed25519 à Ed25519.
8 POST body vs query string En POST, les paramètres doivent être dans le corps OU l'URL, les mettre aux deux endroits crée un conflit.

X. Code d'outil de débogage de signature

def debug_sign(params, secret):
    """Affiche chaque étape en détail"""
    query = urlencode(params)
    print(f"Étape 1. Chaîne de requête : {query}")
    print(f"         Longueur : {len(query)} octets")

    sig = hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
    print(f"Étape 2. Signature : {sig}")
    print(f"         Longueur : {len(sig)} caractères (doit être 64)")

    final = f"{query}&signature={sig}"
    print(f"Étape 3. URL finale : {final}")
    return sig

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

XI. Questions fréquemment posées (FAQ)

Q1 : Pourquoi le résultat de la signature est-il toujours le même (avec les mêmes paramètres) ?

R : HMAC-SHA256 est un algorithme déterministe, une même entrée produit toujours la même sortie. C'est pourquoi l'horodatage doit changer — timestamp est différent à chaque milliseconde, garantissant une signature unique à chaque fois pour prévenir les attaques par rejeu.

Q2 : Est-il possible de retrouver la Secret Key à partir de la signature ?

R : Non. SHA-256 est une fonction à sens unique, retrouver la Secret à partir d'une valeur HMAC est mathématiquement infaisable (nécessiterait environ 2^128 calculs). Une fuite de Secret ne peut provenir que d'une erreur de votre part.

Q3 : Pourquoi la signature fait-elle 64 caractères ?

R : SHA-256 produit 256 bits = 32 octets. Chaque octet étant converti en deux caractères hexadécimaux, on obtient exactement 64 caractères. Si votre signature ne fait pas 64 caractères, votre implémentation est incorrecte.

Q4 : Peut-on utiliser des microsecondes pour l'horodatage ?

R : Non. Binance exige des millisecondes (nombre à 13 chiffres). L'utilisation de microsecondes (16 chiffres) sera interprétée comme une date située dans plusieurs dizaines d'années, entraînant l'erreur -1021 Timestamp out of recv window.

Q5 : Lequel est le plus sûr entre Ed25519 et HMAC-SHA256 ?

R : Ed25519 est plus sûr : la clé privée ne quitte jamais votre machine, Binance n'obtient que la clé publique. Même en cas de piratage des serveurs de Binance, vos actifs ne seraient pas compromis. Cependant, le support SDK pour Ed25519 est bien moins mature que pour HMAC ; pour une stratégie de trading algorithmique classique, le HMAC est suffisant (en stockant le Secret dans un fichier local chiffré).

Après avoir consulté les principes de signature, revenez à la Navigation par catégorie pour découvrir d'autres sujets techniques dans la catégorie « Intégration API ».

Continuer la navigation

Vous avez encore des questions sur l'utilisation de Binance ? Retournez à la page de catégorie pour trouver d'autres tutoriels sur le même sujet.

Navigation par catégorie

Tutoriels connexes

Comment demander une API Binance ? Comment générer généralement les signatures de clés 2026-04-14 Comment utiliser l'API Binance Spot ? Code prêt à l'emploi de zéro à votre premier ordre 2026-04-14 Quelles sont les différences entre l'API Binance Futures et l'API Spot ? Comparaison des endpoints, paramètres et poids 2026-04-14 L'API Binance peut-elle bloquer mon IP ? Explication détaillée de la stratégie de limitation de débit et du calcul du poids 2026-04-14