Bezbednost API integracije: ključevi, IP lista, HMAC potpis i rotacija

9 min čitanja

Fiskalni API izdaje račune pod PIB-om firme, pa ključ za njega vredi koliko pristup računu. Tekst opisuje slojeve zaštite Tezga API-ja, redosled provera i šta znači svaki kod greške, šta radi rotacija i šta nikad ne sme u frontend, repozitorijum ili log.

API ključ za fiskalizaciju je kredencijal koji izdaje račune u ime firme, pa se čuva kao lozinka. Tezga ga prima samo u zaglavlju, čuva samo njegov SHA-256 heš, dozvoljava do 20 imenovanih ključeva po firmi, uz opcije samo za čitanje i listu IP adresa, a telo zahteva može da se potpiše HMAC-SHA256 tajnom. Rotacija se najavljuje mejlom posle 76 dana, ali ključ se sam nikad ne menja.

Ukratko
  • Ključ ima oblik tzg_ i 48 heksadecimalnih znakova, ide isključivo u zaglavlje X-Tezga-Api-Key i vidi se samo jednom, pri pravljenju.
  • Do 20 imenovanih ključeva po firmi, po jedan za svaku integraciju; svaki se pauzira ili opoziva posebno.
  • Ključ može biti samo za čitanje, vezan za listu IP adresa (pojedinačnih ili CIDR opsega) ili namenjen samo terminalu kase.
  • Kad je u podešavanjima postavljena tajna za potpis, svaki poziv koji upisuje mora da nosi X-Tezga-Signature.
  • Ključ nikad ne ide u kod koji izvršava pregledač, u repozitorijum ni u log.

Koji slojevi štite poziv?

Svaki zahtev prolazi kroz provere redom, pa je znanje o redosledu korisno kad tražiš uzrok greške. Pre bilo čega ograničava se veličina tela (512 KB), a tek onda se vidi da li je ključ ispravan.

Redosled provera jednog API zahteva 1. Veličina telo do 512 KB inače 413 2. Ključ u zaglavlju, heš inače 401 3. Opseg čitanje ili upis, namena, 403 4. IP lista van liste: 403 bez IP: odbij 5. Pretplata paket, kredit, inače 402 6. Brojač u minuti po firmi inače 429 7. Potpis tela (HMAC) kad je tajna postavljena pa JSON (400) i pravila (422)

Redosled provera: svaka kapija ima svoj kod, pa se iz koda odmah vidi na kom koraku je zahtev odbijen.

KodŠta značiŠta da uradiš
401Ključ nedostaje ili nije ispravan, ili potpis tela ne valjaProveri zaglavlje i tajnu; potpis računaj nad istim bajtovima koje šalješ
402Pretplata nije aktivna, kredit je potrošen, ili paket ne uključuje APINije problem ključa; proveri paket i pretplatu
403Ključ samo za čitanje pokušava da upiše, ključ je za terminal kase, ili IP adresa nije na listiNapravi ključ prave namene ili dodaj adresu servera na listu
429Prekoračen broj zahteva u minutiSačekaj Retry-After sekundi i ponovi sa istim externalId

Kako se ključ pravi, čuva i opoziva?

Ključ se pravi u Podešavanja, Integracije, sa nazivom koji govori kome pripada (na primer „web shop RS” ili „ERP”). Prikazuje se jednom. U bazi ostaje samo SHA-256 heš i prvih nekoliko znakova za prepoznavanje na spisku, pa ga ni Tezga ne može ponovo da prikaže. Ako se izgubi, pravi se novi.

Pravilo je jedan ključ po sistemu. Tako se pauziranjem jednog ne ruši ostali, a svaki poziv se beleži sa ključem, rutom i ishodom, pa se vidi koja integracija šta radi. Ključ samo za čitanje ne može da izda račun, pa je prava vrednost za sistem koji na sajtu samo prikazuje račun. Ključ sa namenom „terminal kase” važi samo na kasi, a ne za API integracije, i obrnuto.

Lista IP adresa je opciona i vezuje se za ključ: pojedinačne adrese ili CIDR opseg. Kad je lista postavljena, zahtev sa druge adrese se odbija sa 403, pa ukraden ključ ne radi van tvoje mreže. Ako izvorna adresa ne može da se pročita, a lista postoji, zahtev se odbija, a ne propušta.

Šta je potpis tela zahteva i kad je obavezan?

Potpis je dodatni sloj preko ključa. Kad firma u Podešavanja, Integracije postavi tajnu za potpis, svaki poziv koji upisuje dokument (/order, /refund, /advance, /copy, kao i kalkulacija, nivelacija, artikli i kupci) mora da nosi zaglavlje X-Tezga-Signature: sha256= i HMAC-SHA256 tela. Bez tajne se proverava samo ključ. Poređenje je u konstantnom vremenu, a pogrešan potpis daje 401.

// Node.js: potpis se računa nad istim stringom koji se šalje
import { createHmac } from "node:crypto";

const telo = JSON.stringify(porudzbina);
const potpis = "sha256=" +
  createHmac("sha256", process.env.TEZGA_SIGNING_SECRET).update(telo).digest("hex");

await fetch("https://pos.narbiz.com/api/integrations/order?provider=custom", {
  method: "POST",
  headers: {
    "X-Tezga-Api-Key": process.env.TEZGA_API_KEY,
    "X-Tezga-Signature": potpis,
    "Content-Type": "application/json",
  },
  body: telo,
});

Isti princip važi u suprotnom smeru: webhook poruke Tezge nose potpis tvoje adrese, koji tvoj server proverava, kako je opisano u tekstu o webhook-ovima fiskalizacije. Tajna adrese počinje sa whsec_, čuva se šifrovano i ne rotira se sama: menjaš je u podešavanjima.

Šta radi rotacija, a šta ne?

Pozadinski posao jednom nedeljno proverava starost ključeva. Ključ star 76 dana donosi mejl firmi sa porukom da napravi novi. Ključ star 90 i više dana se gasi samo ako firma već ima noviji aktivan ključ i ako stari ključ nije korišćen bar 14 dana, jer integracija koja i dalje kuca na stari ključ ne sme da pukne tiho. U suprotnom podsetnik stiže svake nedelje. Posao nikad ne pravi ni ne menja ključeve.

Ispravan redosled za rotaciju je zato: napravi novi ključ, prebaci integraciju, sačekaj da stari miruje, pa ga opozovi. Dnevnik poziva po ključu pokazuje da li neko još koristi stari.

Gde ključ ne sme da bude?

  • U kodu pregledača. React, Vue i mobilna aplikacija pozivaju sopstveni server, a on Tezgu. Ključ vidljiv u alatima za programere je ključ koji je javan.
  • U adresi. Ključ se prihvata samo iz zaglavlja, ne iz parametra adrese, jer bi završio u pristupnim logovima, referer zaglavljima i istoriji pregledača.
  • U repozitorijumu. Ključ ide u promenljivu okruženja ili sef tajni, i nikad u fajl pod verzijom.
  • U logovima. Ne loguj zaglavlja zahteva; u logu odgovora dovoljan je externalId i PFR broj.
  • Zajednički za sve. Jedan ključ za pet sistema ne može da se opozove bez prekida svih pet.

Kako se sprečava da test izda pravi račun?

Okruženje je osobina naloga, ne ključa: testni i produkcijski ključ izgledaju isto. Zato pri pokretanju pozovi GET /tax-labels i pročitaj polje okruzenje (produkcija, sandbox, simulacija ili nepovezano), pa test konfiguraciji ne dozvoli da nastavi ako je vrednost produkcija. Pravi račun ima verifikacioni link na suf.purs.gov.rs, a simulirani PFR broj počinje sa MOCK.

Izvori: OpenAPI opis Tezga eKase, verzija 1.6.0 (pos.narbiz.com/api/openapi.json), ИБ 1597; uputstvo za integratore (pos.narbiz.com/api-dokumentacija.pdf); strane Sigurnost i zaštita podataka i Enterprise (tezgafiskal.com); RFC 2104 (HMAC); OWASP API Security Top 10.

Česta pitanja

Mogu li da vidim API ključ ponovo posle pravljenja?

Ne. Ključ se prikazuje jednom, a u bazi ostaje samo SHA-256 heš i nekoliko prvih znakova za prepoznavanje na spisku. Ako se ključ izgubi, pravi se novi, a stari se opoziva.

Šta da radim ako je ključ procurio?

Pauziraj ili opozovi taj ključ, napravi novi za tu integraciju i pogledaj dnevnik poziva po ključu da vidiš šta je izdato. Pošto je svaka integracija imala svoj ključ, ostali sistemi nisu pogođeni. Ako je lista IP adresa bila postavljena, ukradeni ključ nije radio van tvoje mreže.

Koja je razlika između 401 i 403?

401 znači da ključ nedostaje ili nije ispravan, ili da potpis tela ne valja: sistem ne zna ko si. 403 znači da znamo ko si, ali ključ nema pravo na to: samo je za čitanje, namenjen je kasi, ili zahtev dolazi sa IP adrese van liste.

Da li je potpis tela zahteva obavezan?

Nije, uključuje se po firmi. Kad je tajna postavljena u Podešavanja, Integracije, svaki poziv koji upisuje dokument mora da nosi X-Tezga-Signature, a poziv bez ispravnog potpisa dobija 401. Preporuka za produkciju je da bude uključen.

Koliko često treba rotirati ključ?

Tezga podseća posle 76 dana, a ključ star 90 dana se gasi samo ako postoji noviji aktivan ključ i ako stari nije korišćen 14 dana. Dobra praksa je rotacija na tri meseca ili odmah po odlasku člana tima koji ga je poznavao.

Zašto ključ ne radi kao parametar u adresi?

Namerno. Ključ u adresi završava u pristupnim logovima, zaglavljima referera i istoriji pregledača. Prihvata se samo iz zaglavlja X-Tezga-Api-Key.

Može li ključ da važi samo za čitanje?

Može. Takav ključ ne može da izda račun ni da upiše artikal, i vraća 403 na upis. To je prava vrednost za sistem koji prikazuje račun ili stanje dokumenta, ali ništa ne izdaje.

Koliko ključeva firma može da ima?

Do 20 imenovanih ključeva po firmi, po jedan za svaku integraciju. Ograničenje je zaštita od nekontrolisanog rasta, ne poslovno pravilo, a svaki poziv se beleži sa ključem, rutom i ishodom.

Bezbednosne postavke možeš da prođeš na simulaciji pre produkcije, sa istim ključem i istim kodom. Probni pristup traje 48 sati i otvara se na strani probaj fiskalnu kasu, a opšti opis zaštite podataka je na strani sigurnost i zaštita podataka.