Symbole zastępcze ('?'
) może służyć tylko do wstawiania dynamicznych wartości ze znakami specjalnymi dla parametrów filtra (np. w GDZIE
części), gdzie powinny pojawić się wartości danych, a nie dla słów kluczowych SQL, identyfikatorów itp. Nie można go użyć do dynamicznego określenia ORDER BY
LUB GRUPUJ WG
wartości.
Nadal możesz to zrobić, na przykład możesz użyć fmt.Sprintf()
aby złożyć dynamiczny tekst zapytania w następujący sposób:
ordCol := "title"
qtext := fmt.Sprintf("SELECT * FROM Apps ORDER BY %s DESC", ordCol)
rows, err := db.Query(qtext)
O czym należy pamiętać:
W ten sposób będziesz musiał ręcznie bronić się przed wstrzyknięciem SQL, np. jeśli wartość nazwy kolumny pochodzi od użytkownika, nie możesz zaakceptować żadnej wartości i po prostu wstawić ją bezpośrednio do zapytania, w przeciwnym razie użytkownik będzie mógł robić wszelkiego rodzaju złe rzeczy. Banalnie powinieneś akceptować tylko litery alfabetu angielskiego + cyfry + podkreślenie ('_'
).
Bez próby zapewnienia kompletnego, wszechstronnego sprawdzania lub funkcji ucieczki, możesz użyć tego prostego wyrażenia regularnego, które akceptuje tylko angielskie litery, cyfry i '_'
:
valid := regexp.MustCompile("^[A-Za-z0-9_]+$")
if !valid.MatchString(ordCol) {
// invalid column name, do not proceed in order to prevent SQL injection
}
Przykłady (wypróbuj na 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