HMAC Kimlik Doğrulama
Tüm Epinpark Integration API istekleri HMAC-SHA256 ile imzalanır. Bu yöntem replay saldırılarına karşı zaman damgası ve nonce ile korunur, body değişiklik tespiti için body hash'i imzaya dahildir.
Zorunlu header'lar
Her istekte dört header olmak zorunda:
| Header | Açıklama |
|---|---|
X-Api-Key | Satıcının açık (public) API key'i |
X-Timestamp | İstek anının Unix saniye değeri (UTC). 300 saniyelik tolerans penceresi |
X-Nonce | İsteğe özgü rastgele string (önerilen: 16 byte hex). Replay korumasıdır |
X-Signature | Aşağıdaki canonical string'in HMAC-SHA256 imzasının base64 encode hâli |
Canonical message formatı
İmza, aşağıdaki kanonik mesajdan üretilir:
METHOD\nPATH\nSHA256(body)\ntimestamp\nnonceHer alanın açıklaması:
METHOD: HTTP metodu, uppercase (GET,POST,PATCH,DELETE,HEAD)PATH: Path + query string. Örn:/v1/orders?page=1&pageSize=10SHA256(body): Request body'nin hex-encoded SHA-256 hash'i. Body yoksa boş string'in SHA-256'sı:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855timestamp:X-Timestampheader'ı ile birebir aynı değernonce:X-Nonceheader'ı ile birebir aynı değer
Alanlar \n (LF, 0x0A) ile ayrılır. CRLF kullanmayın.
Doğru body hash'i kritik
Body'yi göndermeden önce aynen hash'leyin. JSON.stringify çağrısının ardından whitespace eklemeyin, alan sırasını değiştirmeyin, transit'te trim olmasın. Aksi takdirde server-side hash farklı çıkar ve imza doğrulanmaz.
İmza üretme örneği
Sunucu tarafı doğrulama akışı
Server, aldığı isteği şu adımlarla doğrular:
- Dört header'ın varlığı kontrol edilir → eksikse
401 Required HMAC headers are missing X-Timestampparse edilir, 300 saniyelik pencere dışındaysa →401 Timestamp is outside of acceptable window- Request body buffer'lanır,
SHA256(body)hesaplanır - Canonical message yeniden oluşturulur
X-Api-Keyile satıcı bulunur, secret decrypt edilirHMAC-SHA256(secret, canonical)ile imza yeniden hesaplanır- Gönderilen imza ile karşılaştırılır (timing-safe karşılaştırma)
- Başarılıysa
sellerId,apiKeyId,scopesclaim olarak yüklenir
Yaygın hatalar
| Sorun | Çözüm |
|---|---|
| Saatim 300 sn dışında | Sunucunuzu NTP ile senkronize edin |
| Body hash farklı çıkıyor | JSON.stringify ile imzaladığınız aynı string'i gönderin |
| Path yanlış | Query string dahil olmalı, fragment (#...) olmamalı |
| CRLF kullanıyorum | Sadece \n (LF, 0x0A) kullanın |
| URL encoding | Path'i encode etmeyin, URL'de göründüğü gibi imzalayın |
| Nonce tekrar kullanılıyor | Her istek için yeni nonce üretin |
Replay koruması
Aynı nonce aynı timestamp ile kısa bir süre içinde tekrar gönderilse bile,
300 saniyelik pencere geçtikten sonra istek otomatik olarak reddedilir. Yine
de en iyi pratiğe her istekte yeni bir nonce üretmektir.
Secret'ı korumak
- Asla git repo'ya commit etmeyin (env değişkeni veya secret manager kullanın)
- Log'larda asla yazdırmayın
-
- parti monitoring araçlarına göndermeyin
- Frontend kodunda kesinlikle kullanmayın — bu API server-to-server'dır
- Düzenli aralıklarla rotate edin