MAC pre vlastné služby
Kruh kľúčov dokáže ručiť aj za správy, ktoré nie sú modelmi ani HTTP požiadavkami — záznamy logov, obsah fronty, vlastné webhooky — od odosielateľov, ktorí s vami zdieľajú tajomstvo, v akomkoľvek jazyku. verifyMac() overí MAC kľúčom, ktorý kid v danom kruhu pomenúva, a vráti jeho KeyInfo (vlastník, label — nikdy materiál), takže správu môžete naviazať na jej odosielateľa:
use RoundlyConsulting\Sentinel\Exceptions\MacVerificationException;
try {
$key = Sentinel::keys()->ring('logs')->verifyMac($entry['kid'], $payload, $entry['mac']);
} catch (MacVerificationException $exception) {
report($exception); // $exception->reason() is a MacRejection
return;
}
// Bind the key to the sender: one key per sender, its label (or owner) is the sender's identity.
abort_unless($key->label === $entry['service'], 403);Label aj vlastník sú viazané v obálke kľúča v databáze, takže zapisovateľ do databázy nemôže úpravou riadku presmerovať kľúč na iného odosielateľa: kľúč neprejde kontrolou integrity a verifyMac() odmietne s MacRejection::UnknownKey. Na inštalácii aktualizovanej z 1.1 najprv kľúče prepečaťte a zapnite require_bound_label (pozri Správa kľúčov).
Výpočet MAC
Ľubovoľný odosielateľ ho vypočíta obyčajným HMAC — bez Sentinelu, bez HKDF:
// Node
const mac = crypto.createHmac('sha256', secret).update(payloadBytes).digest('base64url');// PHP without Sentinel
$mac = rtrim(strtr(base64_encode(hash_hmac('sha256', $payload, $secret, true)), '+/', '-_'), '=');Odosielateľ v PHP, ktorý má kruh k dispozícii, namiesto toho zavolá mac() — ten počíta aktuálnym podpisovým kľúčom kruhu:
$issued = Sentinel::keys()->ring('logs')->mac($payload); // IssuedMac, made with the ring's current signing key
$issued->keyId; // send it along with the message
$issued->mac; // unpadded base64url
$issued->algorithm; // Algorithm::HmacSha256Formát je mac = base64url-bez-paddingu(HMAC(surové tajomstvo, presné bajty správy)) (RFC 4648 §5). Tajomstvo je surový materiál kľúča — bajty za jeho tvarom base64: — použitý tak, ako je, presne ako kľúč HMAC pre RFC 9421, takže odosielateľ potrebuje len tajomstvo. Správa sa hashuje bajt po bajte: normalizujte ju (kódovanie JSON, Unicode NFC) na strane odosielateľa — Sentinel ju nikdy nekóduje znova.
Pravidlá
- Kruh musí byť nakonfigurovaný a nesmie to byť kruh, ktorý používajú pečate (keys.default_ring), denník (ledger.ring) ani podpisy HTTP správ (signatures.outbound.ring, ring každého profilu) — SealingMisconfiguredException::notAMacRing. Tajomstvá MAC zdieľate s odosielateľmi: v kruhu pečatí či denníka by si odosielateľ mohol odvodiť podkľúče HKDF a falšovať pečate a v kruhu podpisov by MAC nad základom podpisu bol platným HTTP podpisom. Ani pečať nikdy nesmerujte na kruh pre MAC — Sentinel to zo samotného kruhu nespozná.
- Kid sa hľadá len v danom kruhu: kid iného kruhu — aj s platným MAC pod kľúčom toho kruhu — je unknown_key a reťazec, ktorý nie je platný kid, sa odmietne bez vyhľadávania.
- Overujú aktívne kľúče a kľúče len na overovanie (vrátane kľúča z konfigurácie, ktorý rotácia presunula do previous, a importovaného kľúča len na overovanie); čakajúce, vyradené a odvolané kľúče — aj cez SENTINEL_REVOKED_KEYS — sa odmietnu.
- Algoritmus určuje kľúč, nikdy správa: hmac-sha256, prípadne hmac-sha384 / hmac-sha512, ak ich algorithms kruhu povoľuje.
- Kódovanie je striktné: base64url bez paddingu s presnou dĺžkou hashu kľúča (43 znakov pre SHA-256, 64 pre SHA-384, 86 pre SHA-512). Padding, + či /, medzery, hex, nekanonický posledný znak, prázdny reťazec aj krátky či dlhý MAC sú malformed_mac.
- Konštantný čas: keď sa nájde použiteľný kľúč, Sentinel vždy vypočíta celý HMAC a porovná ho v konštantnom čase a až potom skontroluje kódovanie a dĺžku — chybne formátovaný MAC stojí toľko isto ako nesprávny a neprejde ani predpona, ani predĺženie správneho MAC.
Odmietnutia
Odmietnutie vyhodí MacVerificationException: reason() je MacRejection, ring() a keyId() uvedú kruh a kid tak, ako boli zadané. Správa výnimky uvedie kruh a ošetrený kid — nikdy MAC, správu ani materiál kľúča. Kontroly idú v poradí: kruh → kid → stav → algoritmus → HMAC a porovnanie → kódovanie a dĺžka → zhoda.
| MacRejection | Hodnota | Kedy |
|---|---|---|
UnknownKey | unknown_key | Taký kid v tomto kruhu nie je — aj kid iného kruhu, neplatný kid, riadok kľúča, ktorý neprejde kontrolou integrity. |
PendingKey | pending_key | activates_at je v budúcnosti. |
RetiredKey | retired_key | Kľúč je vyradený. |
RevokedKey | revoked_key | Odvolaný vo svojom úložisku alebo cez SENTINEL_REVOKED_KEYS. |
UnsupportedAlgorithm | unsupported_algorithm | Kľúč je Ed25519 alebo ECDSA, nie hmac-*. |
AlgorithmNotAllowed | algorithm_not_allowed | HMAC algoritmus kľúča nie je v algorithms kruhu. |
Malformed | malformed_mac | Nie je to kanonický base64url bez paddingu alebo nemá plnú dĺžku hashu. |
Mismatch | mismatch | Správne formátovaný, no nie je to MAC tejto správy pod týmto kľúčom. |
mac() odmietne s NoSigningKeyException (žiadny aktívny kľúč s tajomstvom — ani odvolaný), AlgorithmNotAllowedException::notHmac (podpisový kľúč je Ed25519 či ECDSA) alebo ::forRing (jeho algoritmus už nie je povolený), plus chyby kruhu uvedené vyššie.
Nastavenie kruhu pre MAC
Kľúč z konfigurácie pre vlastných odosielateľov v PHP a databázové úložisko pre jeden importovaný kľúč na každého externého odosielateľa:
// config/sentinel.php → keys.rings
'logs' => [
'driver' => 'chain',
'drivers' => ['config', 'database'],
'algorithms' => ['hmac-sha256'],
'key_id' => env('SENTINEL_LOGS_KEY_ID'),
'key' => env('SENTINEL_LOGS_KEY'),
],// one verify-only key per sender, bound to it
Sentinel::keys()->ring('logs')->import('billing-2026-10', Algorithm::HmacSha256, 'base64:…', label: 'billing');Odosielateľa rotujete tak, že importujete jeho ďalší kľúč, odosielateľa naň prepnete a starý kid vyradíte; uniknutý kľúč odvolajte (alebo ho uveďte v SENTINEL_REVOKED_KEYS).
Fasáda, DI a akcia
use RoundlyConsulting\Sentinel\Actions\Keys\VerifyMacAction;
$info = Sentinel::verifyMac('logs', 'billing-1', $payload, $mac); // KeyInfo, or MacVerificationException
$issued = Sentinel::mac('logs', $payload); // IssuedMac
$this->sentinel->verifyMac('logs', $kid, $payload, $mac); // an injected SentinelManager
app(VerifyMacAction::class)->execute('logs', $kid, $payload, $mac); // the raw actionSo Sentinel::fake() sa obe volania zaznamenajú a zachovajú produkčné kontroly kruhu, kid, stavu, algoritmu aj kódovania; fakeVerifiedMac(), rejectMacs() a štyri asercie pre MAC ich naskriptujú a overia (pozri Testovanie).
Obmedzenia
- Prehratie: MAC dokazuje, kto bajty poslal, nie to, že prídu len raz. Do správy chránenej MAC vložte poradové číslo alebo časovú značku a duplikáty odfiltrujte na svojej strane — pomôžu nonce (pozri Nonce a jednorazové URL).
- Symetria: platný MAC dokáže vytvoriť prijímajúca aplikácia aj každý odosielateľ s rovnakým kľúčom. Každému odosielateľovi dajte vlastný kľúč viazaný labelom alebo vlastníkom, aby sa jeden nemohol vydávať za iného; kde overovateľ nesmie vedieť podpisovať, použite podpisy HTTP s Ed25519.
Testovací vektor pre iné jazyky
Balík obsahuje tests/Fixtures/mac-vector.json: bajty tajomstva 000102…1f (base64:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=), správu v UTF-8 s ne-ASCII znakmi (presné bajty v message_hex) a MAC Y1UfB_bFvWHrQqhxf-i-W3nf1_GipIV2KqQNdu_aFRk — obsahuje - aj _, takže odosielateľ so štandardným base64 neprejde — plus jedenásť chybných kódovaní. Testy balíka ho overujú obyčajným hash_hmac aj cez node:crypto.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.