Riscuri de securitate
Bazele de date conțin adesea date sensibile și permit efectuarea de operațiuni periculoase. Pentru a lucra în siguranță cu Nette Database, aspectele cheie sunt:
- Înțelegerea diferenței dintre API securizat și nesigur
- Utilizarea interogărilor parametrizate
- Validarea corespunzătoare a datelor de intrare
Ce este injecția SQL?
Injecția SQL este cel mai grav risc de securitate atunci când se lucrează cu baze de date. Aceasta apare atunci când datele nefiltrate introduse de utilizator devin parte a unei interogări SQL. Un atacator își poate introduce propriile comenzi SQL și astfel:
- extrage date neautorizate
- Modificarea sau ștergerea datelor din baza de date
- Ocolirea autentificării
Același lucru este valabil și pentru Database Explorer:
Interogări parametrizate securizate
Apărarea fundamentală împotriva injecției SQL este reprezentată de interogările parametrizate. Nette Database oferă mai multe modalități de utilizare a acestora.
Cea mai simplă modalitate este de a utiliza semne de întrebare:
Acest lucru se aplică tuturor celorlalte metode din Database Explorer care permit inserarea de expresii cu marcaje de întrebare și parametri.
Pentru clauzele INSERT
, UPDATE
, sau WHERE
, puteți trece valorile într-un array:
Validarea valorii parametrilor
Interogările parametrizate reprezintă piatra de temelie a activității sigure în bazele de date. Cu toate acestea, valorile trecute în acestea trebuie să treacă prin mai multe niveluri de validare:
Verificarea tipului
Asigurarea tipului corect de date al parametrilor este esențială – aceasta este o condiție necesară pentru utilizarea în siguranță a bazei de date Nette. Baza de date presupune că toate datele de intrare au tipul de date corect corespunzător coloanei.
De exemplu, dacă $name
din exemplele anterioare a devenit în mod neașteptat un array în loc de un string,
Nette Database ar încerca să introducă toate elementele sale în interogarea SQL, ceea ce ar duce la o eroare. Prin urmare,
nu utilizați niciodată date nevalidate din $_GET
, $_POST
, sau $_COOKIE
direct în
interogările bazei de date.
Validarea formatului
Al doilea nivel verifică formatul datelor – de exemplu, asigurându-se că șirurile de caractere sunt codate UTF-8 și că lungimea lor corespunde definiției coloanei sau verificând dacă valorile numerice se încadrează în intervalul permis pentru tipul de date al coloanei.
La acest nivel, vă puteți baza parțial pe baza de date în sine – multe baze de date resping datele invalide. Cu toate acestea, comportamentul poate varia: unele pot trunchia în mod silențios șirurile lungi sau pot tăia numerele care sunt în afara intervalului.
Validarea specifică domeniului
Al treilea nivel implică verificări logice specifice aplicației dumneavoastră. De exemplu, verificarea faptului că valorile din casetele de selectare corespund opțiunilor disponibile, că numerele se încadrează într-un interval așteptat (de exemplu, vârsta 0–150 de ani) sau că relațiile dintre valori au sens.
Metode de validare recomandate
- Utilizați Nette Forms, care gestionează automat validarea corectă a tuturor intrărilor.
- Utilizați Presenters și declarați tipurile de date ale parametrilor în
metodele
action*()
șirender*()
. - Sau implementați un strat de validare personalizat folosind instrumente PHP standard precum
filter_var()
.
Lucrul sigur cu coloanele
În secțiunea anterioară, am acoperit modul de validare corespunzătoare a valorilor parametrilor. Cu toate acestea, atunci când se utilizează matrici în interogările SQL, trebuie acordată aceeași atenție cheilor acestora.
Pentru comenzile INSERT și UPDATE, acesta este un defect de securitate major – un atacator poate introduce sau modifica
orice coloană din baza de date. Acesta ar putea, de exemplu, să seteze is_admin = 1
sau să introducă date
arbitrare în coloane sensibile (cunoscută sub numele de Vulnerabilitatea atribuirii în masă).
În condițiile WHERE, este și mai periculos, deoarece acestea pot conține operatori:
Un atacator poate utiliza această abordare pentru a descoperi sistematic salariile angajaților. Ar putea începe cu o interogare pentru salarii mai mari de 100 000, apoi mai mici de 50 000, iar prin restrângerea treptată a intervalului, poate dezvălui salariile aproximative ale tuturor angajaților. Acest tip de atac se numește enumerare SQL.
Metodele where()
și whereOr()
sunt și mai flexibile și
acceptă expresii SQL, inclusiv operatori și funcții, atât în chei, cât și în valori. Acest lucru oferă unui atacator
posibilitatea de a efectua injecții SQL complexe:
Acest atac încheie condiția inițială cu 0)
, adaugă propriul SELECT
folosind UNION
pentru a obține date sensibile din tabelul users
și se încheie cu o interogare corectă din punct de vedere
sintactic folosind WHERE (1)
.
Lista albă a coloanelor
Pentru a lucra în siguranță cu numele coloanelor, aveți nevoie de un mecanism care să garanteze că utilizatorii pot interacționa numai cu coloanele permise și nu le pot adăuga pe cele proprii. Încercarea de a detecta și de a bloca numele de coloane periculoase (lista neagră) nu este fiabilă – un atacator poate găsi întotdeauna o nouă modalitate de a scrie un nume de coloană periculos pe care nu ați anticipat-o.
Prin urmare, este mult mai sigur să inversați logica și să definiți o listă explicită de coloane permise (whitelisting):
Identificatori dinamici
Pentru numele dinamice ale tabelelor și coloanelor, utilizați marcajul ?name
. Acest lucru asigură scăparea
corespunzătoare a identificatorilor în conformitate cu sintaxa bazei de date respective (de exemplu, utilizarea ghilimelelor în
MySQL):
Important: utilizați simbolul ?name
numai pentru valorile de încredere definite în codul aplicației. Pentru
valorile furnizate de utilizator, utilizați din nou o listă albă. În caz contrar,
riscați vulnerabilități de securitate: