Platshållare ('?'
) kan endast användas för att infoga dynamiska, escaped värden för filterparametrar (t.ex. i WHERE
del), där datavärden ska visas, inte för SQL-nyckelord, identifierare etc. Du kan inte använda den för att dynamiskt specificera ORDER BY
ELLER GRUPPERA EFTER
värden.
Du kan ändå göra det, till exempel kan du använda fmt.Sprintf()
för att sammanställa den dynamiska frågetexten så här:
ordCol := "title"
qtext := fmt.Sprintf("SELECT * FROM Apps ORDER BY %s DESC", ordCol)
rows, err := db.Query(qtext)
Saker att tänka på:
Om du gör det måste du manuellt försvara vs SQL-injektion, t.ex. om värdet på kolumnnamnet kommer från användaren kan du inte acceptera något värde och bara infoga det direkt i frågan, annars kommer användaren att kunna göra alla möjliga dåliga saker. Trivialt bör du bara acceptera bokstäver i det engelska alfabetet + siffror + understreck ('_'
).
Utan att försöka tillhandahålla en komplett, omfattande kontroll eller escape-funktion kan du använda detta enkla regexp som endast accepterar engelska bokstäver, siffror och '_'
:
valid := regexp.MustCompile("^[A-Za-z0-9_]+$")
if !valid.MatchString(ordCol) {
// invalid column name, do not proceed in order to prevent SQL injection
}
Exempel (prova 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