Devi difenderti da SQL injection ogni volta che trasformi l'input dell'utente in codice. Ciò include nomi di tabelle e colonne provenienti da cataloghi di sistema o dall'input diretto dell'utente allo stesso modo. In questo modo previeni anche eccezioni banali con identificatori non standard. In pratica sono tre metodi integrati:
1. format()
1° interrogazione, igienizzato:
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()
richiede Postgres 9.1 o successivo. Usalo con il %I
identificatore di formato.
Il solo nome della tabella potrebbe essere ambiguo. Potrebbe essere necessario fornire il nome dello schema per evitare di modificare accidentalmente la tabella errata. Correlati:
- INSERT con nome tabella dinamica nella funzione trigger
- In che modo il percorso_ricerca influenza la risoluzione dell'identificatore e lo "schema corrente"
A parte:aggiunta di più colonne con un unico ALTER TABLE
il comando è più economico.
2. regclass
Puoi anche utilizzare un cast in una classe registrata (regclass
) per il caso speciale di esistente nomi di tabelle. Facoltativamente qualificato per lo schema. Questo non riesce immediatamente e senza problemi per i nomi di tabella che non sono validi e visibili all'utente chiamante. La prima query è stata disinfettata con un cast a 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$;
Chiama:
SELECT foo('table_name');
Oppure:
SELECT foo('my_schema.table_name'::regclass);
A parte:considera di usare solo text
invece di varchar(20)
.
3. quote_ident()
La seconda query sanificata:
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$;
Per concatenazioni/interpolazioni multiple, format()
è più pulito...
Risposte correlate:
- Nome tabella come parametro di funzione PostgreSQL
- Funzioni Postgres vs query preparate
Maiuscole/minuscole!
Tieni presente che gli identificatori senza virgolette non cast in minuscolo qui. Quando viene utilizzato come identificatore in SQL [Postgres esegue automaticamente il cast in minuscolo][7]. Ma qui passiamo stringhe per SQL dinamico. Quando è stato eseguito l'escape come dimostrato, gli identificatori di maiuscole e minuscole CaMel (come UserS
) saranno conservati virgolette ("UserS"
), proprio come altri nomi non standard come "name with space"
"SELECT"
ecc. Quindi, i nomi fanno distinzione tra maiuscole e minuscole in questo contesto.
Il mio consiglio permanente è di utilizzare esclusivamente identificatori legali minuscoli e di non preoccuparsene mai.
A parte:le virgolette singole sono per i valori, le virgolette doppie sono per gli identificatori. Vedi:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS