SQL-injeksjon er en enkel angrepsvektor som fortsatt er svært vanlig i dag. Grunnen til dette er ingen annen enn ingen patch for stupid. Hvorfor sier du dette, la oss ta JAVA som et eksempel for å illustrere:
Anta at en slik tabell finnes i databasen:
Bruk deretter JDBCs handlingstabell:
Koden ovenfor brukes ofte av noen utviklere. Tenk deg en situasjon der parameteren for innkommende userId er "3; bruker av droppbordet; SQL-setningen som utføres er som følger:
Etter at databasen er kompilert og kjørt, slettes brukertabellen. Voila, et enkelt SQL-injeksjonsangrep trer i kraft! Dette skyldes at koden ovenfor ikke samsvarer med programmeringsspesifikasjonene.
Når vi programmerer etter spesifikasjonen, er SQL-injeksjon ikke-eksisterende. Dette er også tilfelleDen første måten å unngå SQL-injeksjon på: forhåndskompilerte setninger, koden er som følger:
Hvorfor finnes ikke SQL-injeksjon i koden ovenfor? Fordi den forhåndskompilerte setningen brukes, vil den forhåndskompilerte setningen sette "velg navn fra bruker der id= ?" Setningen er kompilert på forhånd slik at den bare trenger å erstattes med de innkommende parameterne når den kjøres? Plassholdere er greit. For det første ikke-kompatible tilfellet vil programmet skrive en SQL-setning og deretter kompilere den med innholdet som brukeren sender inn, og det er nettopp problemet.
I tillegg til å bruke forhåndskompilerte setninger, finnes det et annet alternativMåter å unngå SQL-injeksjonsangrep på: Lagrede prosedyrer。 En lagret prosedyre er et sett med SQL-setninger som utfører en spesifikk funksjon, kompilert og lagret i en database, og brukeren kan utføre den ved å kalle en lagret prosedyre og gi en parameter (hvis den lagrede prosedyren har parametere), som også kan unngå SQL-injeksjonsangrep
Den tilsvarende lagrede prosedyren i koden ovenfor er som følger:
Selvfølgelig kan brukere også gjøre tegnsjekk på frontend, noe som også er en måte å unngå SQL-injeksjon på: for eksempel, for parameteren userId ovenfor, vil brukeren sjekke for semikolon og en feil vises. Den mest grunnleggende grunnen er imidlertid at SQL-injeksjonsangrep eksisterer fordi apper ikke bruker least privilege når de får tilgang til databaser. Det virker som om alle har brukt root-kontoen for å få tilgang til databasen.
Så hvordan unngår MyBatis SQL-injeksjonsangrep? Eller ta bordbrukeren ovenfor som eksempel: La oss si at mapper-filen er:
De tilsvarende Java-filene er:
Du kan se at inputparameteren er userId av typen String, når vi sender inn userId="34; bruker av droppbordet; Etter det lyder den trykte uttalelsen:
Uansett hvilken bruker-ID som er skrevet inn, er SQL-setningen hans slik. Dette skyldes at mybatis bruker forhåndskompilerte setninger i den underliggende implementasjonen. Når databasen utfører den setningen, bruker den direkte den forhåndskompilerte setningen og erstatter deretter plassholderen med den passerende userId? Bare løp. Erstatte plassholdere først? Kompilasjonsprosessen gjennomføres, så det er ikke rom for SQL-injeksjon å overleve.
Så hvordan gjør MyBatis SQL-prekompilering? Faktisk brukes PreparedStatement-klassen nederst i rammeverket. PreparedStaement-klassen unngår ikke bare SQL-injeksjon, men sparer også (N-1) kompileringstid når samme SQL-setning kjøres N ganger, noe som forbedrer effektiviteten.
Hvis du endrer ovenstående påstand til:
Når vi skriver inn userId="34; bruker av droppbordet; Etter det lyder den trykte uttalelsen:
På dette tidspunktet bruker ikke mybatis forhåndskompilerte setninger, det vil først sy strenger sammen og deretter utføre kompilering, noe som er akkurat slik SQL-injeksjon trer i kraft.
Derfor, når du skriver mybatis-mapping-setninger, prøv å bruke formatet "#{xxx}". Hvis du må bruke parametere som «${xxx}», må du manuelt filtrere dem for å forhindre SQL-injeksjonsangrep.
|