Sigurnost i infrastruktura

Autor: 8 min čitanja

Sigurnost WebShopHR-a je slojevita: baza, kod i produkcijski rubni poslužitelj svaki nose vlastitu obranu, pa se propust na jednom sloju hvata na sljedećem.

Sigurnost od baze do ruba

Podaci više trgovaca dijele istu PostgreSQL bazu, ali nikad iste retke. Svaka transakcijska tablica uključuje tenanta (oznaku kojem dućanu redak pripada) u primarnom ključu ili stranom ključu, a PostgreSQL Row-Level Security (pravilo koje baza sama provjerava na svakom retku, prije nego što aplikacija dobije rezultat) i Force Row Level Security dodatno provjeravaju uvijek aktualnu ulogu aplikacije.

Čak i ako bi upit negdje procurio bez tenanta, baza ga ne bi izvršila.

Lozinke kupaca se ne spremaju nikad u čitljivom obliku. Koristi se Argon2id (algoritam posebno spor za pogađanje lozinke, otporan i na jaka računala) s parametrima prema OWASP preporuci, uz konstantno-vremensku usporedbu i lažni hash za nepostojeće račune kako bi se spriječilo prepoznavanje valjanih e-mail adresa po vremenu odgovora.

Svi odgovori nose sigurnosna zaglavlja: Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy i Strict-Transport-Security. Javne forme dućana koje mijenjaju stanje (košarica, registracija, recenzije i sl.) štiti CSRF dvostruki kolačić, pa mehanizam radi i uz predmemorirane stranice.

Brza zloupotreba se sprječava na kritičnim tokovima: naplata, prijava, magic link, registracija, recenzije, izvoz, AI chat i napuštene košarice imaju ograničenja po IP-u. Kod naplate i AI chata ta ograničenja dodatno skaliraju prema paketu trgovca.

Odlazni webhookovi ne mogu pogoditi privatne IP raspone, ne slijede preusmjerenja i imaju zaštitu od DNS rebindinga. Ako konfiguracija nedostaje (bilo da je riječ o imgproxyju, plaćanju, mailu ili Zitadelu), značajka se isključi, a ne prebaci na prikladniji dev default.

GDPR i usklađenost

Kupac može zatražiti brisanje svojih osobnih podataka. Sustav u jednoj transakciji anonimizira kupca i njegove narudžbe povezane s računom, ali ostavlja financijske zapise netaknute. Narudžbe koje je ista osoba napravila kao gost, prije otvaranja računa, anonimizacija ne dira. Računovodstvo mora ostati ispravno, a osobni identifikatori se uklanjaju. Proces je idempotentan: ponovljeni poziv ne rastura već anonimizirane zapise.

Izvoz podataka pokriva cijeli katalog, kupce i narudžbe u jednoj konzistentnoj snimci, dostupan kao JSON ili zip s CSV-om. Lozinke se nikad ne izvoze. Odlazna datoteka ne sadrži hash lozinke.

Kolačići se ne učitavaju prije privole. Google Analytics 4 i povezane skripte pokreću se tek nakon eksplicitnog pristanka kupca, a ako JavaScript nije dostupan, default stanje je „bez privole“. Pristanak se pamti godinu dana, a mogućnost povlačenja je uvijek na dohvat ruke.

Automatizirano zadržavanje podataka uklanja audit logove nakon dvanaest mjeseci, razgovore s AI agentom nakon trideset dana i napuštene košarice nakon trideset dana. To se odvija u pozadinskim poslovima bez ručnog zahvata. Svaka izmjena u CMS-u bilježi se u audit log: rutu, metodu, status i vrijeme, bez da se u log sprema tijelo zahtjeva ili bilo kakve tajne.

Hosting i infrastruktura

Produkcija živi na Hetzner serveru u Berlinu, što znači da se podaci ne napuštaju EU. Aplikacija se pakuje u multi-stage Docker sliku i u runtimeu radi kao neprivilegirani korisnik. Unutar produkcijskog composea niti jedan unutarnji servis ne objavljuje host port. Jedini javni dodirni rub je Traefik na 80/443.

Baza je PostgreSQL 17 s pgvector ekstenzijom, što omogućuje semantičko pretraživanje artikala i AI preporuke unutar iste baze. Zadano, umjetna inteligencija ne poziva vanjske API-jeve: LLM i embeddinge generira vlastiti Ollama poslužitelj u berlinskom okruženju, a vektori ostaju u Postgresu. Adresa Ollama poslužitelja je konfigurabilna postavka, ne tvrdo ugrađena vrijednost.

Promet se preusmjerava s HTTP na HTTPS, a za sve poddomene *.web-shop.hr koristi se jedan wildcard Let’s Encrypt certifikat izdan DNS-01 izazovom. Kad trgovac priključi vlastitu domenu, sustav proaktivno potiče izdavanje certifikata prije prvog stvarnog posjetitelja.

Praćenje zdravlja aplikacije radi kroz /health (liveness) i /health/ready (readiness). Readiness pinga bazu, predmemoriju, tražilicu i pohranu objekata. Javni odgovor nosi samo agregatni status. Detalji po servisu dostupni su isključivo s unutarnjim tokenom. Prometheus metrike i OpenTelemetry praćenje su ugrađeni, a praćenje se isključuje ako kolektor nije konfiguriran. Server ne pada zbog nedostupnog observabilityja.

Migracije baze se pokreću prije nego što se digne nova verzija aplikacije, a svaki servis ima restart: unless-stopped. Logička obnova baze (pg_dump/pg_restore na odvojenoj bazi) dokumentirana je i isprobana kao dodatni sloj obrane, s provjerom broja redaka i RLS policyja nakon obnove.

API i integracije

CMS koristi JSON REST API. Cijela dokumentacija javno dostupna na /api/docs koristeći self-hostani Scalar, s istovremeno objavljenim OpenAPI 3 specifikacijom. Nema prijave za čitanje dokumentacije.

Autentikacija trgovaca ide preko Zitadel OIDC: svaki dućan ima vlastitu organizaciju, a JWT tokeni (digitalno potpisane propusnice koje aplikacija provjeri bez upita u bazu) se validiraju preko JWKS endpointa (javnog kataloga ključeva za provjeru potpisa). Prihvaćaju se samo RS256 potpisi (jači, asimetrični potpis, ne dijeljena lozinka), istek tokena je obavezan, a ciljana publika se može strogo podesiti.

Dolazni Stripe webhookovi se primaju na trgovčevoj domeni i provjeravaju se njegovim vlastitim webhook secretom. Obrada je idempotentna: ponovljeni poziv neće dva puta promijeniti status narudžbe. Odlazni webhookovi koje trgovac postavi za vlastiti sustav potpisuju se HMAC-SHA256 (kriptografskim potpisom kojim primatelj sam provjeri da poruku nitko nije usput izmijenio), imaju maksimalno pet pokušaja isporuke, timeout od deset sekundi i vidljiv log zadnjih pedeset pokušaja.

Izvoz cijelog dućana (katalog, kupci, narudžbe) vrši se u jednoj transakciji kako bi snimak bio konzistentan, bez obzira na to tko je u međuvremenu kupio ili spremio. Kroz CMS je jednim klikom dostupan izvoz kupaca; puni izvoz kataloga i narudžbi trenutno ide izravnim API pozivom. To ujedno znači da trgovac uvijek može izvući svoje podatke i nije zaključan u platformi.

ArgesERP kao first-party integracija

Arges integracija nije generični third-party plugin. Radi se o first-party SDK-u istog tima. Veza se uspostavlja jednostavnim Arges API tokenom koji trgovac unese u postavkama, bez da WebShopHR dobiva pristup trgovčevu računu.

Jednom spojen, sinkronizaciju pokrećeš klikom, a ona povlači artikle i usluge, poslovne prostore i stanja po lokacijama. Artikli i usluge ulaze u katalog, a poslovni prostori postaju lokacije sa zalihama. Negativne cijene se preskaču, opisi i slike koje je trgovac ručno prilagodio u WebShopHR-u ostaju netaknute, a stanja se bilježe decimalno: s tri decimale za kilograme, litre ili metre.

Sinkronizacija artikala, usluga i zaliha iz Arges ERP-a

Kad narudžba prijeđe u stanje plaćeno, WebShopHR u jednom pozivu kreira, zaključa i fiskalizira račun u Argesu, a dobiveni JIR i ZKI se odmah zapisuju uz narudžbu. Cijeli je tok idempotentno povezan prema Arges ID-u, pa se ista stvar ne može fiskalizirati dvaput.

Ako Arges nije povezan, Free paket zadržava osnovne limite. Kada je povezan, Free paket dobiva neograničen katalog, više operatera i 0% provizije. WebShopHR nije profitni centar, već prodajni kanal Argesa.

Grane.

Česta pitanja.

Mogu li druge trgovine na istoj platformi vidjeti moje podatke ili podatke mojih kupaca?

Ne. Svaka transakcijska tablica nosi identifikator dućana, a PostgreSQL Row-Level Security to provjerava na razini baze. Čak i kad bi neki upit negdje procurio bez tog konteksta, baza ne bi vratila tuđe retke.


Gdje se fizički nalaze podaci mojih kupaca?

Na Hetzner serveru u Berlinu. Podaci ne napuštaju Europsku uniju, uključujući bazu, predmemoriju, pohranu slika i AI dio (embeddinge generira vlastiti Ollama poslužitelj u istom okruženju).


Kako WebShopHR postupa kad kupac zatraži brisanje svojih podataka po GDPR-u?

Sustav u jednoj transakciji anonimizira kupca i njegove narudžbe povezane s računom, dok financijski zapisi ostaju netaknuti radi računovodstvene ispravnosti. Narudžbe koje je ista osoba napravila kao gost, prije otvaranja računa, ostaju nepromijenjene. Postupak je idempotentan, pa ponovni poziv ne rastura već očišćene zapise.


Mogu li povezati WebShopHR s Arges ERP-om bez dvostrukog unosa artikala i zaliha?

Da, kroz first-party Arges integraciju: sync povlači artikle, usluge, poslovne prostore i stanja po lokacijama, a kad narudžba prijeđe u plaćeno, račun se automatski kreira i fiskalizira u Argesu.


Ako neki servis (baza, keš, plaćanje) padne, hoće li cijeli dućan prestati raditi?

Ne nužno. Fail-closed pristup znači da nedostajuća konfiguracija gasi samo tu značajku, a ne cijelu aplikaciju. Ako keš ili rate-limit sloj otkažu, dućan se nastavlja servirati iz baze.


Šalju li se moji podaci ikad izvan EU-a preko treće AI usluge?

Ne po zadanim postavkama. LLM i embeddinge generira vlastiti Ollama poslužitelj u istom berlinskom okruženju, a vektori ostaju u istoj PostgreSQL bazi. Adresa Ollama poslužitelja je konfigurabilna postavka, pa krajnji odabir ostaje na operateru platforme, ne na fiksnoj vanjskoj integraciji.

Povezani vodiči.

Otvori vlastiti webshop u par minuta.

Besplatan paket traje bez roka i ne traži karticu.