func TestSQLInjectionPrevention(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("An error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()
tests := []struct {
name string
user string
bb func(user string) *builq.Builder
prepare func(mock sqlmock.Sqlmock, user string)
}{
{
name: "FmtSprintf Injection",
user: "'; DROP TABLE users; --",
bb: func(user string) *builq.Builder {
return builq.New()("SELECT * FROM users WHERE username = '%s'", user)
},
prepare: func(mock sqlmock.Sqlmock, user string) {
mock.ExpectQuery("SELECT \\* FROM users WHERE username = '.*; DROP TABLE users; --'").
WillReturnRows(sqlmock.NewRows([]string{"id", "username"}))
},
},
{
name: "TableName Injection",
user: "admin",
bb: func(user string) *builq.Builder {
tableName := "users; DROP TABLE sensitive_data; --"
return builq.New()("SELECT * FROM %s WHERE username = '%s'", tableName, user)
},
prepare: func(mock sqlmock.Sqlmock, user string) {
mock.ExpectQuery(".+ DROP TABLE sensitive_data;.+").
WillReturnRows(sqlmock.NewRows([]string{"id", "username"}))
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tc.prepare(mock, tc.user)
query, args, err := tc.bb(tc.user).Build()
if err != nil {
t.Fatalf("could not build query: %v", err)
}
spew.Dump(query)
_, err = db.Query(query, args...)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
t.Errorf("Unexpected error: %v", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("There were unfulfilled expectations: %s", err)
}
})
}
}