SQL-injektio on yksinkertainen hyökkäysvektori, joka on edelleen hyvin yleinen. Syynä tähän on se, ettei tyhmälle ole päivitystä. Miksi sanot näin, otetaan esimerkiksi JAVA havainnollistamaan:
Oletetaan, että tällainen taulukko on olemassa tietokannassa:
Sitten käytä JDBC:n toimintataulukkoa:
Yllä mainittua koodia käyttävät usein jotkut kehittäjät. Kuvittele tilanne, jossa saapuva userId-parametri on "3; pudotustaulukon käyttäjä; Suoritettu SQL-lause on seuraava:
Kun tietokanta on käännetty ja suoritettu, käyttäjätaulu poistetaan. Voilà, yksinkertainen SQL-injektiohyökkäys astuu voimaan! Tämä johtuu siitä, että yllä oleva koodi ei täytä ohjelmointispesifikaatioita.
Kun ohjelmoimme määrittelyn mukaisesti, SQL-injektiota ei ole. Tämä pätee myösEnsimmäinen tapa välttää SQL-injektiota: valmiiksi käännetyt lauseet, koodi on seuraava:
Miksi SQL-injektiota ei ole yllä olevassa koodissa? Koska esikäännettyä lausetta käytetään, valmiiksi käännetty lause asettaa "valitse nimi käyttäjältä missä id= ?" Lause on käännetty etukäteen niin, että se tarvitsee korvata vain saapuvilla parametreilla suorituksen yhteydessä? Paikkamerkit ovat ok. Ensimmäisessä ei-yhteensopivassa tapauksessa ohjelma kirjoittaa SQL-lauseen ja kääntää sen käyttäjän välittämällä sisällöllä, mikä on juuri ongelma.
Valmiiksi käännettyjen lauseiden lisäksi on olemassa toinen vaihtoehtoKeinoja välttää SQL-injektiohyökkäykset: Tallennetut proseduurit。 Tallennettu proseduuri on joukko SQL-lauseita, jotka suorittavat tietyn tehtävän, käännetään ja tallennetaan tietokantaan, ja käyttäjä voi suorittaa sen kutsumalla tallennettua proseduuria ja antamalla parametrin (jos tallennetussa proseduurissa on parametreja), mikä myös välttää SQL-injektiohyökkäykset
Vastaava tallennettu menettely yllä olevassa koodissa on seuraava:
Tietenkin käyttäjät voivat myös tarkistaa merkkien tarkistusta frontendissä, mikä on myös tapa välttää SQL-injektiota: esimerkiksi yllä olevassa userId-parametrissa käyttäjä tarkistaa puolipisteen ja virhe näkyy. Kuitenkin kaikkein perustavanlaatuisin syy on se, että SQL-injektiohyökkäyksiä on olemassa, koska sovellukset eivät käytä vähimpiä oikeuksia tietokantoja käyttäessään. Näyttää siltä, että kaikki ovat käyttäneet juuritiliä päästäkseen tietokantaan.
Miten MyBatis siis välttää SQL-injektiohyökkäykset? Tai otetaan yllä oleva taulukon käyttäjä esimerkkinä: Oletetaan, että mapper-tiedosto on:
Vastaavat java-tiedostot ovat:
Näet, että syöteparametri on userId, tyyppi String, kun syötämme userId="34; pudotustaulukon käyttäjä; Tämän jälkeen painettu lausunto kuuluu:
Riippumatta syötetystä käyttäjätunnuksesta, hänen SQL-lauseensa on tällainen. Tämä johtuu siitä, että mybatis käyttää esikäännettyjä lauseita taustalla olevassa toteutuksessa. Kun tietokanta suorittaa kyseisen lauseen, se käyttää suoraan valmiiksi käännettyä lausetta ja korvaa paikkamerkin siirtyvällä userId:llä? Mene vain juoksemaan. Pitäisikö ensin vaihtaa paikkamerkkiä? Käännösprosessi toteutetaan, joten SQL-injektiolla ei ole tilaa selviytyä.
Miten MyBatis siis tekee SQL-esikäännöksen? Itse asiassa PreparedStatement-luokkaa käytetään kehyksen alareunassa. PreparedStaement-luokka ei ainoastaan vältä SQL-injektiota, vaan myös säästää (N-1) käännösaikaa, kun sama SQL-lause suoritetaan N kertaa, mikä parantaa tehokkuutta.
Jos muutat yllä olevan lauseen muotoon:
Kun syötämme userId="34; pudotustaulukon käyttäjä; Tämän jälkeen painettu lausunto kuuluu:
Tällä hetkellä mybatis ei käytä valmiiksi käännettyjä lauseita, vaan se yhdistää ensin merkkijonot ja suorittaa sitten käännöksen, mikä on juuri se, miten SQL-injektio vaikuttaa.
Siksi, kun kirjoitat mybatis-kartoituslauseita, yritä käyttää muotoa "#{xxx}". Jos sinun täytyy käyttää parametreja kuten "${xxx}", sinun täytyy suodattaa ne manuaalisesti estääksesi SQL-injektiohyökkäykset.
|