Du skal forsvare dig mod SQL-injektion hver gang du omdanner brugerinput til kode. Det inkluderer tabel- og kolonnenavne, der kommer fra systemkataloger eller fra direkte brugerinput. På denne måde forhindrer du også trivielle undtagelser med ikke-standardiserede identifikatorer. Der er grundlæggende tre indbyggede metoder:
1. format()
1. forespørgsel, renset:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('
ALTER TABLE %I ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)', _t);
END
$func$;
format()
kræver Postgres 9.1 eller nyere. Brug den med %I
formatspecifikation.
Alene tabelnavnet kan være tvetydigt. Du skal muligvis angive skemanavnet for at undgå at ændre den forkerte tabel ved et uheld. Relateret:
- INSERT med dynamisk tabelnavn i triggerfunktion
- Hvordan påvirker søgestien identifikationsopløsning og det "aktuelle skema"
Til side:Tilføjelse af flere kolonner med en enkelt ALTER TABLE
kommandoen er billigere.
2. regclass
Du kan også bruge en cast til en registreret klasse (regclass
) for det særlige tilfælde eksisterende tabelnavne. Eventuelt skema-kvalificeret. Dette mislykkes øjeblikkeligt og elegant for tabelnavne, der ikke er gyldige og synlige for den kaldende bruger. Den første forespørgsel blev renset med en cast til regclass
:
CREATE OR REPLACE FUNCTION foo(_t regclass)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)';
END
$func$;
Ring til:
SELECT foo('table_name');
Eller:
SELECT foo('my_schema.table_name'::regclass);
Til side:Overvej kun at bruge text
i stedet for varchar(20)
.
3. quote_ident()
Den 2. forespørgsel renset:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'UPDATE ' || _t -- sanitized with regclass
|| ' SET ' || quote_ident(_c) || ' = ''This is a test''';
END
$func$;
For flere sammenkædninger/interpolationer, format()
er renere ...
Relaterede svar:
- Tabelnavn som en PostgreSQL-funktionsparameter
- Postgres-funktioner kontra forberedte forespørgsler
Der skelnes mellem store og små bogstaver!
Vær opmærksom på, at identifikatorer uden anførsel ikke er støbt til små bogstaver her. Når det bruges som identifikator i SQL [Postgres kaster automatisk til små bogstaver][7]. Men her passerer vi strenge til dynamisk SQL. Når escaped som vist, CaMel-case identifikatorer (som UserS
) vil blive bevaret ved dobbeltcitering ("UserS"
), ligesom andre ikke-standardnavne som "name with space"
"SELECT"
osv. Derfor skelnes der mellem store og små bogstaver i navne i denne sammenhæng.
Mit stående råd er udelukkende at bruge lovlige små bogstaver og aldrig bekymre dig om det.
Bortset fra:Enkelte anførselstegn er for værdier, dobbelte anførselstegn er for identifikatorer. Se:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS