Pladsholdere ('?'
) kan kun bruges til at indsætte dynamiske, escapede værdier for filterparametre (f.eks. i WHERE
del), hvor dataværdier skal vises, ikke for SQL-nøgleord, identifikatorer osv. Du kan ikke bruge den til dynamisk at angive ORDER BY
ELLER GRUPPER EFTER
værdier.
Du kan dog stadig gøre det, for eksempel kan du bruge fmt.Sprintf()
for at samle den dynamiske forespørgselstekst sådan her:
ordCol := "title"
qtext := fmt.Sprintf("SELECT * FROM Apps ORDER BY %s DESC", ordCol)
rows, err := db.Query(qtext)
Ting at huske på:
Gør du det, bliver du nødt til manuelt at forsvare vs SQL-injektion, f.eks. hvis værdien af kolonnenavnet kommer fra brugeren, kan du ikke acceptere nogen værdi og bare indsætte den direkte i forespørgslen, ellers vil brugeren være i stand til at gøre alle slags dårlige ting. Trivielt bør du kun acceptere bogstaver i det engelske alfabet + cifre + understregning ('_'
).
Uden at forsøge at give en komplet, omfattende checker eller escape-funktion, kan du bruge dette enkle regexp, som kun accepterer engelske bogstaver, cifre og '_'
:
valid := regexp.MustCompile("^[A-Za-z0-9_]+$")
if !valid.MatchString(ordCol) {
// invalid column name, do not proceed in order to prevent SQL injection
}
Eksempler (prøv det på Go Playground ):
fmt.Println(valid.MatchString("title")) // true
fmt.Println(valid.MatchString("another_col_2")) // true
fmt.Println(valid.MatchString("it's a trap!")) // false
fmt.Println(valid.MatchString("(trap)")) // false
fmt.Println(valid.MatchString("also*trap")) // false