U moet zich verdedigen tegen SQL-injectie telkens wanneer u gebruikersinvoer in code omzet. Dat geldt ook voor tabel- en kolomnamen die afkomstig zijn uit systeemcatalogi of uit directe gebruikersinvoer. Zo voorkom je ook triviale uitzonderingen met niet-standaard identifiers. Er zijn in principe drie ingebouwde methoden:
1. format()
1e vraag, opgeschoond:
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()
vereist Postgre 9.1 of hoger. Gebruik het met de %I
formaatspecificatie.
Alleen de tabelnaam kan dubbelzinnig zijn. Mogelijk moet u de schemanaam opgeven om te voorkomen dat u per ongeluk de verkeerde tabel wijzigt. Gerelateerd:
- INSERT met dynamische tabelnaam in triggerfunctie
- Hoe beïnvloedt het zoekpad de resolutie van de ID en het "huidige schema"
Terzijde:het toevoegen van meerdere kolommen met een enkele ALTER TABLE
commando is goedkoper.
2. regclass
Je kunt ook een cast gebruiken voor een geregistreerde klas (regclass
) voor het speciale geval van bestaande tafel namen. Optioneel schema-gekwalificeerd. Dit mislukt onmiddellijk en netjes voor tabelnamen die niet geldig en zichtbaar zijn voor de aanroepende gebruiker. De eerste vraag is opgeschoond met een cast naar 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$;
Bel:
SELECT foo('table_name');
Of:
SELECT foo('my_schema.table_name'::regclass);
Terzijde:overweeg om alleen text
te gebruiken in plaats van varchar(20)
.
3. quote_ident()
De 2e vraag opgeschoond:
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$;
Voor meerdere aaneenschakelingen / interpolaties, format()
is schoner ...
Gerelateerde antwoorden:
- Tabelnaam als een PostgreSQL-functieparameter
- Postgres-functies versus voorbereide zoekopdrachten
Hoofdlettergevoelig!
Houd er rekening mee dat ID's zonder aanhalingstekens niet . zijn hier in kleine letters gegoten. Bij gebruik als identifier in SQL [Postgres cast automatisch naar kleine letters][7]. Maar hier passeren we strings voor dynamische SQL. Wanneer ontsnapt, zoals aangetoond, CaMel-case-ID's (zoals UserS
) worden bewaard door dubbele aanhalingstekens ("UserS"
), net als andere niet-standaard namen zoals "name with space"
"SELECT"
enz. Daarom zijn namen in deze context hoofdlettergevoelig.
Mijn vaste advies is om uitsluitend juridische identificatiecodes in kleine letters te gebruiken en u daar nooit zorgen over te maken.
Terzijde:enkele aanhalingstekens zijn voor waarden, dubbele aanhalingstekens zijn voor identifiers. Zie:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS