Kötelező kérésfejlécek
Minden kérésnek (kivéve /v1/health) tartalmaznia kell ezt a négy fejlécet. Ha bármelyik hiányzik vagy érvénytelen, a szerver HTTP 401 hibával utasítja vissza.
| Header | Format | Description |
|---|---|---|
KH-Key | kh_live_[A-Z0-9]{32} | Nyilvános kulcsazonosító. Nem titok, megjelenhet naplókban. |
KH-Timestamp | Unix-másodperc (10 számjegy) | Aktuális időbélyeg. Tűréshatár +-300 másodperc. |
KH-Nonce | 22-44 base64url karakter | Kérésenként egyszer használatos érték. 600 másodpercig tárolva, utána újrahasználható. |
KH-Signature | 64 hex | HMAC-SHA256(secret, signing_string), hex kódolással. |
Az aláírási karakterlánc felépítése
Az aláírandó karakterlánc öt komponensből áll, sortöréssel (\n) elválasztva.
signing_string = METHOD + "\n"
+ PATH + "\n"
+ TIMESTAMP + "\n"
+ NONCE + "\n"
+ SHA256_HEX(BODY)
signature = HEX( HMAC_SHA256(secret, signing_string) )
A PATH a teljes kéréskori útvonalat tartalmazza a lekérdezési karakterlánccal együtt, host és fragmens nélkül. A BODY a nyers törzsbájtokat jelenti; GET/DELETE kérések esetén törzs nélkül a BODY üres karakterlánc, melynek SHA256-ja az ismert konstans e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
Referenciaimplementációk
PHP:
$method = 'POST';
$path = '/v1/orders';
$body = json_encode(['product_id' => 42, 'billing_cycle' => 'monthly']);
$ts = (string) time();
$nonce = bin2hex(random_bytes(16));
$signing = "{$method}\n{$path}\n{$ts}\n{$nonce}\n" . hash('sha256', $body);
$sig = hash_hmac('sha256', $signing, $KH_SECRET);
$ch = curl_init('https://www.kernelhost.com/cp/kh_reseller_api/v1/orders');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"KH-Key: {$KH_KEY}",
"KH-Timestamp: {$ts}",
"KH-Nonce: {$nonce}",
"KH-Signature: {$sig}",
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$res = curl_exec($ch);
Node.js:
import crypto from 'crypto';
const method = 'POST';
const path = '/v1/orders';
const body = JSON.stringify({ product_id: 42, billing_cycle: 'monthly' });
const ts = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(16).toString('hex');
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const signing = `${method}\n${path}\n${ts}\n${nonce}\n${bodyHash}`;
const sig = crypto.createHmac('sha256', KH_SECRET).update(signing).digest('hex');
const res = await fetch('https://www.kernelhost.com/cp/kh_reseller_api/v1/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'KH-Key': KH_KEY,
'KH-Timestamp': ts,
'KH-Nonce': nonce,
'KH-Signature': sig,
'Idempotency-Key': crypto.randomBytes(16).toString('hex'),
},
body,
});
Visszajátszás-védelem
Egy sikeresen aláírt kérést NEM lehet újra elküldeni. A szerver minden nonce-ot 600 másodpercig tárol az adatbázisban; egy második kérés ugyanazzal a nonce-szal replay_detected hibával elutasításra kerül. Hasonlóképpen elutasításra kerül minden olyan kérés, amelynek időbélyege több mint 300 másodperccel eltér a szerver idejétől.
Jogosultsági modell
Minden kulcsnak van egy kifejezett jogosultsági listája. Az útvonalak ellenőrzik a szükséges jogosultságot; ha hiányzik, HTTP 403 forbidden_scope a válasz. Az íráshoz és érzékeny adatokhoz tartozó jogosultságokat kifejezetten engedélyezni kell a kulcs létrehozásakor.
read:products,read:orders,read:services,read:billing,read:webhooksread:credentials(Szolgáltatási hozzáférési adatok olvasása (root jelszavak, FTP, VNC). Külön credentials.read audit-bejegyzést hoz létre minden híváshoz.)write:orders(Megrendelések leadása és fizetése.)write:services(Szolgáltatási műveletek futtatása (start/stop/reboot/reinstall/terminate).)write:webhooks(Webhook URL beállítása.)

