SQLFix Blog
Parametrerede forespørgsler vs genereret SQL
En model, der skriver en korrekt udseende forespørgsel, har ikke løst injektionsproblemet. Sikkerheds Eigenschaften, der er vigtig, findes i, hvordan forespørgslen møder data, og det er jobbet for parametrerede forespørgsler med forberedte udsagn. Genereret tekst er et udgangspunkt for gennemgang; det er ikke en erstatning for grænsen, som forberedte udsagn påtvinger mellem kode og data.
Hvad en forberedt erklæring faktisk gør
Når driveren modtager en anmodning om at forberede, sender den SQL-teksten til serveren. Serveren parser teksten, opbygger en kørselsplan og gemmer denne plan. Senere, når programmet kalder execute, sender driveren kun parameter-værdierne. Serveren anvender den gemte plan på disse værdier uden at gen-parsere SQL-teksten. Fordi værdierne aldrig bliver en del af erklæringsstrengen, behandles en payload som ' OR 1=1-- som en bogstavelig værdi, ikke som en del af kommandoen.
Jeg har set dette virke i MySQL 5.0, PostgreSQL 8.0, SQL Server 2005 og Oracle 9i. Hvert mainstream-sprog tilbyder en binding-API: JDBC's PreparedStatement, Pythons cursor.execute med placeholders, Go's database/sql.Query og Nodes mysql2 pool.execute. Modellen kan udgive formen SELECT * FROM orders WHERE customer_id = ? AND status = ? ; den omgivende kode leverer de to værdier på kørselstidspunktet.
Hvis du ser citatet inde i erklæringsTeksten, bruger du ikke en sand forberedt erklæring; du udfører sandsynligvis client-side streng-interpolation, hvilket ikke giver injektions sikkerhed.
Hvorfor gennemgået SQL stadig har brug for parametre
Menneskelig gennemgang kan bekræfte, at forespørgselsens form matcher den ønskede forretningsregel. Den kan spotte manglende joins, forkerte kolonnenavne eller ineffektive filtre. Dog kommer de værdier, der flyder ind i disse placeringer, stadig fra eksterne kilder: webformulare, API-nytlastninger, meddelelseskøer eller legacy-filer. Disse kilder er ikke under udviklerens direkte kontrol i øjeblikket for udførelse.
OWASP's SQL Injection Forebyggelsesliste angiver tydeligt: „Forsvarsvalg 1: Forberedte erklæringer (parametrerede forespørgsler)“. Listen nævner ikke „menneskelig godkendelse“ som en erstatning. Godkendelse omhandler logisk korrekthed; parametrering omhandler tillidsgrænsen mellem kode og data. At droppe enten af dem efterlader den anden utilbundsgående.
Selv om den menneskelige gennemgåer så en fornuftig INSERT-erklæring, skete injiceringen på værdibindningstrinnet, som gennemgangen ikke dækkede.
På denne måde forbliver gennemgåerens arbejde værdifuldt, og udførelsestrinnet beholder sin sikkerhedsgaranti.
Lagrede procedurer er ikke automatisk sikkerhed
Mange teams antager, at flytning af logik til en lagret procedure eliminerer injectionsrisikoen. Den antagelse fejler, når proceduren selv opbygger dynamisk SQL.
Overvej en procedure skrevet i T‑SQL:
CREATE PROCEDURE GetOrders @Customer NVARCHAR(50) AS BEGIN DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM Orders WHERE Customer = ''' + @Customer + ''''; EXEC sp_executesql @sql; END Hvis @Customer indeholder '); DROP TABLE Orders;-- , bliver den resulterende streng en gyldig batch, der sletter tabellen. Procedurewrapperen beskyttede ikke dataene; konkatinationen inde i proceduren gjorde.
Samme mønster viser sig i PL/SQL med EXECUTE IMMEDIATE, i PostgreSQL med EXECUTE format og i MySQL med PREPARE/EXECUTE opbygget fra en variabel.
Efter omskrivningen skal proceduren køres med en værdi, der indeholder et citationstegn, og verificere, at fejlen er en datatypemismatch og ikke en syntaksfejl.
Hold generering og udførelse adskilt som separate lag
Den sikreste arkitektur behandler AI-modellen som en forslagsmotor, ikke som en dataadgangskomponent. Modellen udgiver en kandidatforespørgselsskabelon. En menneskelig eller automatiseret politikport anmelder denne skabelon for korrekthed, overholdelse og ydeevne. Først efter godkendelse tager applikationskoden skabelonen, forbereder den med driveren og binder de realtidsparametre.
Fordi modellen aldrig ser en live-forbindelse, kan den ikke manipuleres til at afsløre skemadetaljer gennem fejlmeddelelser. Fordi udførelseslaget aldrig stoler på rå streng, kan en kompromitteret model ikke forårsage injektion.
Denne proces holder modellens output i anmeldelsesløkken og garanterer, at udførelsestrinet kun bruger parametrerede udsagn.
Hvad dette ikke er
Jeg ønsker at være tydelig omkring begrænsningerne for den tilgang, der er beskrevet ovenfor. Den garanterer ikke, at hver enkelt mulig fejl vil blive fanget. Den lover ikke 100 % beskyttelse mod alle typer af svagheder. Den hævder ikke at eliminere behovet for andre forsvarsmekanismer såsom inputvalidering, outputkodning eller databasemed least-privilege-konti.
Hvad metoden gør, er:
Hvis du udelukkende afhænger af modellens output og springer review eller parameterbindingstrinet over, mister du beskyttelsen. Hvis du tillader, at executionslaget koncatenerer værdier efter forberedelse, genindfører du risikoen. Teknikken er en komponent i en forsvar-i-dybde-strategi, ikke en enkeltstående mirakelkugle.
Eksempel på virkeligt arbejdsgangsflow
Forestil dig et SaaS-produkt, der giver chefer mulighed for at eksportere en liste over forfaldne fakturaer. Produktet bruger SQLForm til at udarbejde forespørgslen.
Denne spor viser, hvordan generationssteget forbliver uafhængigt af udførelsessteget, og hvordan parametergrænsen blokerer injektion, selv når brugeren forsøger at smugle SQL ind i et felt, som modellen aldrig ser.
Almindelige fælder og hvordan vi undgår dem
Selv med en solid design kan hold af og til falde tilbage i vaner, der svækker beskyttelsen. Nedenfor er hyppige fejl, jeg har observeret, og de konkrete skridt, vi tager for at holde systemet sikkert.
Nogle udviklere bygger SELECT * FROM tags WHERE tag IN (?,?,?) ved først at oprette en streng med det rigtige antal placeringer, og derefter konkatenerer værdierne direkte ind i SQL før forberedelse. Dette ophæver formålet, fordi værdierne bliver en del af erklæringsTeksten.
En erklæring, der er forberedt til SELECT * FROM ordrer WHERE status =?, udføres senere med en værdi, der faktisk indeholder en hel ny SELECT-erklæring, og som afhænger af, at chaufføren behandler værdien som data. Selvom værdien er sikkert citeret, kan applikationslogikken være forkert, fordi udvikleren antog, at erklæringen kunne håndtere enhver SQL.
Interne dashboards omgår af og til den menneskelige gennemgangsporte, fordi holdet antager, at data er betroet. Senere bliver en servicekonto kompromitteret og begynder at føde ondsindede payloads ind i dashboardet.
Til fejlfinding logger hold af og til de præcise parameter-værdier. Hvis disse logs bliver eksponeret, kan de lække følsomme data, såsom adgangskoder eller personligt identificerbare oplysninger.
En ORM kan tilbyde en metode, der synes at acceptere parametre, men under overfladen opbygger den en streng og kalder ExecuteNonQuery på en rå SQL-streng.
Ved at holde øje med disse fælder og anvende de tilsvarende reparationer, forbliver adskillelsen mellem generation og udførelse stærk, og parametergrænsen fortsætter med at udføre det arbejde, det var designede til.
Referencer
https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
https://cwe.mitre.org/data/definitions/798.html
https://cwe.mitre.org/data/definitions/89
Ofte stillede spørgsmål
Nej. Indsættelse af værdier afhænger af, hvordan værdierne opfylder forespørgslen, og ikke af, om forespørgslen er logisk korrekt. Parametrerede forespørgsler holder værdierne adskilt fra kommandotekst uanset værdiernes indhold.
Ikke automatisk. En procedure, der konkatenerer input og udfører den med EXECUTE IMMEDIATE, kan stadig indsætte. Sikkerheden kommer fra parameterbinding inden for proceduren.
Et ORM er kun sikkert, når du bruger dets parametrerede interface. At bygge en streng og sende den til ORM genindfører indsættelse. Grænsen mellem kode og data skal stadig påløses.
Nej. Hold generation og udførelse adskilt: modellen udarbejder, en port åbner, og applikationskoden binder parametre på køretidspunktet. Modellen skal aldrig være udførelsesvejen.
Prøv produktet: SQLForm
2026-09-16 · kun primære kilder · ingen fabrikerede trafikmålinger
Relaterede artikler
Naturligt sprog til SQL: sikkerhedstjek, der har betydning
Udforsk det fulde AI micro-SaaS emne matrix →
Beskytter en korrekt forespørgsel mod SQL-injektion?
Nej. Injektion afhænger af, hvordan værdierne opfylder forespørgslen, og ikke af, om forespørgslen er logisk korrekt. Parametrerede forespørgsler holder værdier adskilt fra kommandotekst uanset værdiernes indhold.
Er gemte procedurer sikre som standard?
Ikke automatisk. En procedure, der konkatenerer input og udfører den med EXECUTE IMMEDIATE, kan stadig injicere. Sikkerhed kommer fra parameterbinding inden for proceduren.
Kan en ORM erstatte parametrerede forespørgsler?
En ORM er kun sikker, når du bruger dens parametrerede interface. At bygge en streng og overføre den til ORM genindfører injektion. Grænsen mellem kode og data skal stadig gennemtvinges.
Skal en model nogensinde indeholde databaseforbindelsen?
Nej. Hold generering og udførelse adskilt: modellen udarbejder, en port åbner, og applikationskoden binder parametre på køretidspunktet. Modellen skal aldrig være udførelsesvejen.
Kun til beslutningsstøtte. Er ikke en erstatning for DBA-gennemgang eller produktionsbelastningstest. Ingen ydeevnegarantier.