Injectarea SQL este un vector simplu de atac care este încă foarte comun astăzi. Motivul pentru asta nu este altul decât lipsa unui patch pentru stupid. De ce spui asta, să luăm JAVA ca exemplu pentru a ilustra:
Să presupunem că există un astfel de tabel în baza de date:
Apoi folosește tabelul de acțiuni JDBC:
Codul de mai sus este adesea folosit de unii dezvoltatori. Imaginează-ți o situație în care parametrul utilizatorIdului de intrare este "3; utilizator de drop table; Instrucțiunea SQL executată este următoarea:
După ce baza de date este compilată și executată, tabelul utilizatorului este șters. Voila, un atac simplu de injecție SQL își face efectul! Acest lucru se datorează faptului că codul de mai sus nu corespunde specificațiilor de programare.
Când programăm conform specificației, injecția SQL este inexistentă. Același lucru este valabilPrima modalitate de a evita injectarea SQL: instrucțiuni precompilate, codul este următorul:
De ce nu există injecția SQL în codul de mai sus? Deoarece se folosește instrucțiunea precompilată, aceasta va seta "select name from user where id= ?" Instrucțiunea este compilată dinainte astfel încât trebuie înlocuită doar cu parametrii de intrare când este executată? Înlocuitorii sunt în regulă. Pentru primul caz neconform, programul va scrie o instrucțiune SQL și apoi o va compila cu conținutul transmis de utilizator, ceea ce este exact problema.
Pe lângă utilizarea instrucțiunilor precompilate, există o a doua opțiuneModalități de a evita atacurile prin injecție SQL: Proceduri stocate。 O procedură stocată este un set de instrucțiuni SQL care îndeplinesc o funcție specifică, compilate și stocate într-o bază de date, iar utilizatorul o poate executa apelând o procedură stocată și oferind un parametru (dacă procedura stocată are parametri), ceea ce poate evita atacurile de injecție SQL
Procedura stocată corespunzătoare în codul de mai sus este următoarea:
Desigur, utilizatorii pot face și verificarea caracterelor pe frontend, ceea ce este o modalitate de a evita injectarea SQL: de exemplu, pentru parametrul userId de mai sus, utilizatorul va verifica un punct și virgulă și va fi afișată o eroare. Totuși, cel mai fundamental motiv este că există atacuri de injecție SQL deoarece aplicațiile nu folosesc privilegiul minim atunci când accesează baze de date. Se pare că toată lumea a folosit contul rădăcină pentru a accesa baza de date.
Deci, cum evită MyBatis atacurile prin injecție SQL? Sau luați ca exemplu utilizatorul tabelului de mai sus: Să presupunem că fișierul mapper este:
Fișierele Java corespunzătoare sunt:
Poți vedea că parametrul de intrare este userId de tip String, când introducem userId="34; utilizator de drop table; După aceea, declarația tipărită spune:
Indiferent de ID-ul de utilizator introdus, instrucțiunea lui sql este așa. Acest lucru se datorează faptului că mybatis folosește instrucțiuni precompilate în implementarea de bază. Când baza de date execută acea instrucțiune, folosește direct instrucțiunea precompilată și apoi înlocuiește placeholder-ul cu userId-ul care trece prin trecut? Doar fugi. Să înlocuiesc mai întâi locurile provizorii? Procesul de compilare este realizat, astfel încât nu există loc pentru ca injecția SQL să supraviețuiască.
Deci, cum face MyBatis precompilarea SQL? De fapt, clasa PreparedStatement este folosită la baza cadrului. Clasa PreparedStaement nu doar că evită injecția SQL, dar economisește și (N-1) timp de compilare atunci când aceeași instrucțiune SQL este executată de n ori, îmbunătățind astfel eficiența.
Dacă schimbi afirmația de mai sus la:
Când introducem userId="34; utilizator de drop table; După aceea, declarația tipărită spune:
În acest moment, mybatis nu folosește instrucțiuni precompilate, ci va îmbina mai întâi șiruri și apoi va efectua compilarea, exact așa cum intră în aplicare injecția SQL.
Prin urmare, atunci când scrii instrucțiuni de mapare mybatis, încearcă să folosești formatul "#{xxx}". Dacă trebuie să folosești parametri precum "${xxx}", trebuie să-i filtrezi manual pentru a preveni atacurile de injecție SQL.
|