# Sigurno javno postavljanje aplikacije

Ovaj paket dodaje osnovnu zastitu za Apache/shared hosting, ali server prije javne objave treba pripremiti prema sljedecim koracima.

## Sta je vec ugradeno u aplikaciju

- sigurne sesije, vremensko ogranicenje sesije i regeneracija ID-a nakon prijave;
- hashiranje lozinki i obavezna promjena svakog naloga koji jos koristi staru tekstualnu lozinku;
- ogranicavanje ponovljenih neuspjelih prijava po korisniku i IP adresi;
- centralna prijava, korisnicke dozvole i dodatna administratorska provjera osjetljivih stranica;
- CSRF i provjera porijekla za zahtjeve koji mijenjaju podatke;
- POST-only brisanje, sigurnosna potvrda i audit evidencija promjena;
- prepared SQL upiti/allowliste na osjetljivim rutama i escapovanje dinamickog HTML izlaza;
- provjera MIME tipa, velicine i sadrzaja logotipa uz zabranu izvrsavanja koda u `uploads`;
- sigurnosna HTTP zaglavlja, zabrana listanja direktorija i blokada pristupa konfiguraciji, SQL/ZIP/log fajlovima.
- vanjske CSS/JavaScript biblioteke imaju fiksirane verzije i SRI provjeru integriteta.
- obavezna TOTP dvofaktorska prijava putem Google/Microsoft Authenticatora, uz jednokratne rezervne kodove;
- strukturirana evidencija uspjesnih korisnickih izmjena i administratorska statistika.

Ove mjere znacajno smanjuju rizik, ali nijedna aplikacija ne moze dobiti garanciju potpune zastite. Sigurnost zavisi i od hostinga, TLS-a, azuriranja, lozinki, backupa i nadzora logova.

## Obavezno prije objave

1. Promijenite lozinku korisnika baze. Svaku lozinku koja je ranije bila u ZIP-u ili `config.php` tretirajte kao kompromitovanu.
   Nakon postavljanja paketa prijavite se svakim postojecim korisnickim nalogom i postavite novu jedinstvenu lozinku; stari tekstualni nalozi bit ce automatski zaustavljeni na ekranu za promjenu lozinke.
2. Tajne podatke baze cuvajte izvan `public_html` direktorija, u privatnom konfiguracijskom fajlu s pravom `600`. Korisniku baze dodijelite samo dozvole koje aplikacija stvarno koristi.
3. Ukljucite vazeci TLS certifikat i provjerite da HTTP adresa automatski prelazi na HTTPS. Tek na HTTPS-u prijava i sesijski kolacici mogu biti sigurni.
   Postavite i `APP_ALLOWED_HOSTS` na tacnu domenu aplikacije, npr. `APP_ALLOWED_HOSTS=app.example.ba,www.app.example.ba`, kako zahtjevi s laznim Host zaglavljem ne bi bili prihvaceni.
4. Ne ostavljajte ZIP arhive, SQL kopije, `error_log`, stare verzije ili rezervne kopije u `public_html`. Backup baze i fajlova cuvajte izvan web-roota i redovno testirajte vracanje podataka.
5. Preporucena prava su `644` za javne fajlove i `755` za direktorije. Privatni config neka bude `600`. Nikada ne koristite `777`.
6. PHP log postavite izvan `public_html` (cPanel MultiPHP INI Editor ili hosting podrska) i uvedite rotaciju/brisanje starih logova.
7. Nadogradite hosting na podrzanu verziju PHP-a, najmanje PHP 8.2, nakon provjere kompatibilnosti. PHP 7.4 vise ne prima sigurnosne ispravke.
8. Prije prve prijave pokrenite `sql/mfa_activity.sql`. U privatni `komercijala-config.php`
   preporuceno je dodati zaseban nasumicni `mfa_key` od najmanje 32 znaka. Ako nije
   postavljen, aplikacija koristi kompatibilni kljuc izveden iz DB konfiguracije, pa bi
   promjena DB lozinke zahtijevala ponovno povezivanje autentifikatora.

## Autentifikator i aktivnosti korisnika

- Pri prvoj prijavi nakon nadogradnje svaki korisnik rucno unosi prikazani TOTP kljuc
  u Google Authenticator ili Microsoft Authenticator i potvrduje sestocifrenim kodom.
- Rezervni kodovi prikazuju se samo jednom. Administrator moze u `Korisnici` resetovati
  izgubljeni autentifikator; korisnik ga zatim ponovo povezuje pri sljedecoj prijavi.
- Administrator u profilnom meniju otvara `Aktivnosti korisnika`, filtrira period,
  korisnika i modul te vidi ukupan broj izmjena, izvoza, uvoza i prodatih naloga.
- Klikom na aktivnost otvara se zaseban detaljni prikaz sa sigurnim snimkom podataka
  prije i poslije izmjene. Autentifikacijske tajne, lozinke i sigurnosni tokeni se maskiraju.
- Statistika pocinje od trenutka instaliranja ove verzije; ranije zapise nije moguce
  pouzdano pripisati korisniku ako ta informacija prethodno nije bila evidentirana.

## Premjestanje konfiguracije baze

Sigurnosni ZIP za javnu objavu namjerno ne sadrzi `config.local.php` niti `error_log`.

1. Kopirajte `config.local.example.php` jedan nivo iznad direktorija u kojem se nalaze PHP fajlovi i preimenujte ga u `komercijala-config.php`.
2. U novi fajl upisite novu DB lozinku i ostale podatke, pa mu postavite dozvolu `600`.
3. Otvorite aplikaciju i provjerite prijavu. Tek nakon uspjesne provjere uklonite `config.local.php` iz `public_html`.
4. Ako hosting koristi drugaciju strukturu direktorija, postavite `APP_CONFIG_FILE` na apsolutnu putanju privatnog PHP konfiguracijskog fajla.

Ako shared hosting ne dozvoljava konfiguraciju izvan web-roota, `komercijala-config.php`
moze privremeno biti i u istom direktoriju kao `config.php`; ukljucena `.htaccess`
pravila blokiraju njegovo direktno preuzimanje. Varijanta izvan web-roota je i dalje sigurnija.

## Apache / shared hosting

- Prenesite i skrivene fajlove `.htaccess`, `.user.ini` i `uploads/.htaccess`.
- Apache mora dozvoljavati `.htaccess` pravila (`AllowOverride`). Ako bilo koje pravilo izazove HTTP 500, posaljite sadrzaj hosting podrsci; nemojte samo ukloniti sigurnosnu zastitu.
- `.user.ini` se na PHP-FPM/CGI hostingu moze osvjezavati s odgodom od nekoliko minuta.
- U cPanelu ukljucite ModSecurity, automatski SSL i, ako je dostupno, zastitu prijave/rate limiting.
- `session.cookie_secure=1` ukljucite u produkcijskom `.user.ini` tek kada je potvrdeno da je cijela aplikacija dostupna iskljucivo preko HTTPS-a.
- Ako je aplikacija iza Cloudflare-a ili drugog reverse-proxyja, HTTPS preusmjerenje podesite na proxyju. Varijablu `APP_TRUST_PROXY=1` koristite samo kada hosting potvrdi da uklanja klijentski `X-Forwarded-Proto` i sam upisuje pouzdanu vrijednost.

## Nginx

Nginx ne cita `.htaccess`. Administrator servera mora prenijeti ista pravila u konfiguraciju virtualnog hosta, posebno:

```nginx
location ~* /(?:config(?:\.local(?:\..*)?)?\.php|komercijala-config\.php|error_log|.+\.(?:sql|log|ini|zip|bak|env))$ { deny all; }
location ~* ^/uploads/.*\.(?:php[0-9]?|phtml|pht|phar|cgi|pl|py|rb|sh|shtml|html?|svg|js)$ { deny all; }
location ^~ /uploads/ { autoindex off; }
```

Sigurnosna zaglavlja i HTTP-u-HTTPS preusmjerenje takoder treba postaviti u Nginx virtualnom hostu.

## Brza provjera nakon postavljanja

- `http://domena/` mora preci na `https://domena/`.
- `/error_log`, `/sql/komitenti_dopuna.sql` i bilo koji `.zip` moraju vratiti `403 Forbidden`.
- PHP fajl postavljen unutar `/uploads/` mora vratiti `403 Forbidden`.
- PNG/JPG/GIF/WEBP logo do 5 MB mora se moci ucitati; SVG, PHP i datoteke s laznom ekstenzijom moraju biti odbijene.
- Nakon odjave, direktno otvaranje zasticene PHP stranice mora vratiti prijavu ili `403`, bez prikaza podataka.
