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
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 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;