blob: ae830718be1f3ef2ba1c93d90db9d4f0e9498af6 [file] [log] [blame] [view]
<!--{
"Title": "Avoiding SQL injection risk"
}-->
You can avoid an SQL injection risk by providing SQL parameter values as `sql`
package function arguments. Many functions in the `sql` package provide
parameters for the SQL statement and for values to be used in that statement's
parameters (others provide a parameter for a prepared statement and parameters).
Code in the following example uses the `?` symbol as a placeholder for the
`id` parameter, which is provided as a function argument:
```
// Correct format for executing an SQL statement with parameters.
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)
```
`sql` package functions that perform database operations create prepared
statements from the arguments you supply. At run time, the `sql` package turns
the SQL statement into a prepared statement and sends it along with the
parameter, which is separate.
**Note:** Parameter placeholders vary depending on the DBMS and driver
you're using. For example, [pq driver](https://pkg.go.dev/github.com/lib/pq)
for Postgres accepts a placeholder form such as `$1` instead of `?`.
You might be tempted to use a function from the `fmt` package to assemble the
SQL statement as a string with parameters included – like this:
```
// SECURITY RISK!
rows, err := db.Query(fmt.Sprintf("SELECT * FROM user WHERE id = %s", id))
```
This is not secure! When you do this, Go assembles the entire SQL statement,
replacing the `%s` format verb with the parameter value, before sending the
full statement to the DBMS. This poses an
[SQL injection](https://en.wikipedia.org/wiki/SQL_injection) risk because the
code's caller could send an unexpected SQL snippet as the `id` argument. That
snippet could complete the SQL statement in unpredictable ways that are
dangerous to your application.
For example, by passing a certain `%s` value, you might end up with something
like the following, which could return all user records in your database:
```
SELECT * FROM user WHERE id = 1 OR 1=1;
```