Logo

dev-resources.site

for different kinds of informations.

Preventing SQL Injection with Raw SQL and ORM in Golang

Published at
1/15/2025
Categories
webdev
go
programming
backend
Author
dzungnt98
Categories
4 categories in total
webdev
open
go
open
programming
open
backend
open
Author
9 person written this
dzungnt98
open
Preventing SQL Injection with Raw SQL and ORM in Golang

In modern development, secure coding is crucial. Golang applications can also be prone to SQL injection when interacting with databases, unless proper precautions are taken.

This article covers how to prevent SQL injection in Golang using raw SQL and ORM frameworks.


🛑 What is SQL Injection?

SQL Injection (SQLi) is a web security vulnerability that allows an attacker to INJECT malicious SQL code into the queries an application makes to its database.

Example of a vulnerable SQL query:

query := "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"
rows, err := db.Query(query)
Enter fullscreen mode Exit fullscreen mode

If username or password contains malicious input, attackers can manipulate the query logic.

SQL Injection

You can check out my another post on SQL injection to know more about it.


🔐 How to Prevent SQL Injection in Raw SQL

When writing raw SQL queries in Go, adhere to best practices for security.

1. Use Prepared Statements

Go’s database/sql package provides prepared statements that safely handle user input.

Vulnerable Example:

query := "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"
rows, err := db.Query(query) // Potential SQL injection
Enter fullscreen mode Exit fullscreen mode

With Prepared Statements:

query := "SELECT * FROM users WHERE username = ? AND password = ?"
rows, err := db.Query(query, username, password)

if err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

Prepared statements automatically escape user input to prevent injection.

2. Use Parameterized Queries

In Go, parameterized queries can be written using db.Query or db.Exec with placeholders:

query := "INSERT INTO products (name, price) VALUES (?, ?)"
_, err := db.Exec(query, productName, productPrice)

if err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

Avoid string concatenation or formatting with fmt.Sprintf for dynamic queries.

3. Use QueryRow for Single Row Queries

If fetching a single record, use QueryRow to avoid risks:

query := "SELECT id, name FROM users WHERE email = ?"

var id int
var name string
err := db.QueryRow(query, email).Scan(&id, &name)

if err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

4. Input Sanitization and Validation

Even when using prepared statements, input sanitization and validation remain crucial in preventing injection attacks and maintaining data integrity.

  • Sanitization: Cleans input data by removing unwanted characters to ensure it meets the application's expectations.

  • Validation: Ensures that input conforms to a specific format, type, or length before processing.

Example of Input Validation in Go:

func isValidUsername(username string) bool {
    re := regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
    return re.MatchString(username)
}

if len(username) > 50 || !isValidUsername(username) {
    log.Fatal("Invalid input")
}
Enter fullscreen mode Exit fullscreen mode

5. Use Stored Procedures

Stored procedures encapsulate query logic on the database side and limit direct input handling in code:

CREATE PROCEDURE AuthenticateUser(IN username VARCHAR(50), IN password VARCHAR(50))
BEGIN
    SELECT * FROM users WHERE username = username AND password = password;
END;
Enter fullscreen mode Exit fullscreen mode

Call stored procedures from Go using:

_, err := db.Exec("CALL AuthenticateUser(?, ?)", username, password)

if err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

🔄 Preventing SQL Injection with ORMs

Many Golang applications use ORM libraries such as GORM or XORM to simplify database interactions. While these tools offer built-in protection against SQL injection, you must follow best practices.

1. GORM

GORM is one of the most popular ORMs in Go.

Vulnerable Example (Dynamic Query Construction):

db.Raw("SELECT * FROM users WHERE name = '" + userName + "'").Scan(&user)
Enter fullscreen mode Exit fullscreen mode

This can lead to injection if userName contains malicious input.

Safe Example:

db.Raw("SELECT * FROM users WHERE name = ? AND email = ?", userName, email).Scan(&user)

Enter fullscreen mode Exit fullscreen mode

GORM’s Raw method supports parameterized queries.

Using Struct-Based Queries (safer default):

db.Where("email = ? AND status = ?", email, status).First(&user)
Enter fullscreen mode Exit fullscreen mode

Using GORM’s query methods like Where is the safer default and should be preferred for database interactions.

2. Avoid Raw Strings for Complex Queries

When using raw SQL queries for complex operations, use placeholders:

result := db.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, accountId)

if result.Error != nil {
    log.Println(result.Error)
}
Enter fullscreen mode Exit fullscreen mode

3. Use Struct Tags for Safe ORM Mapping

When mapping Go structs to database tables, use tags to define field names and constraints:

type User struct {
    ID       uint   `gorm:"primaryKey"`
    Name     string `gorm:"size:100"`
    Email    string `gorm:"uniqueIndex"`
    Password string
}
Enter fullscreen mode Exit fullscreen mode

This helps ensure safe ORM mappings by defining constraints, data types, and relationships directly within the Go struct.

⚠️ Common Mistakes to Avoid

1. Avoid Building Queries with String Concatenation

Always use placeholders or prepared statements instead of concatenating variables into queries.

2. Avoid ORM Functions that Bypass Safety Checks

Some ORM functions allow executing raw SQL with direct string input. Use parameterized alternatives whenever possible.

3. Do Not Trust User Input

Always carefully validate and sanitize inputs before processing.


🛡️ Conclusion

Golang provides powerful tools for handling database queries securely. By implementing best practices—such as leveraging prepared statements, parameterized queries, and ORM frameworks while also sanitizing and validating inputs — you create a robust defense against SQL injection vulnerabilities.

Follow me to stay updated with my future posts:

go Article's
30 articles in total
Favicon
A técnica dos dois ponteiros
Favicon
Preventing SQL Injection with Raw SQL and ORM in Golang
Favicon
🐹 Golang Integration with Kafka and Uber ZapLog 📨
Favicon
🌐 Building Golang RESTful API with Gin, MongoDB 🌱
Favicon
Golang e DSA
Favicon
Prevent Race Conditions Like a Pro with sync.Mutex in Go!
Favicon
tnfy.link - What's about ID?
Favicon
Developing a Simple RESTful API with Gin, ginvalidator, and validatorgo
Favicon
Desbravando Go: Capítulo 1 – Primeiros Passos na Linguagem
Favicon
Compile-Time Assertions in Go (Golang)
Favicon
Mastering GoFrame Logging: From Zero to Hero
Favicon
GoFr: An Opinionated Microservice Development Framework
Favicon
The Struggle of Finding a Free Excel to PDF Converter: My Journey and Solution
Favicon
Setting Up Your Go Environment
Favicon
External Merge Problem - Complete Guide for Gophers
Favicon
Mastering Go's encoding/json: Efficient Parsing Techniques for Optimal Performance
Favicon
Golang with Colly: Use Random Fake User-Agents When Scraping
Favicon
Versioning in Go Huma
Favicon
Go Basics: Syntax and Structure
Favicon
Interesting feedback on Fuego!
Favicon
Making Beautiful API Keys
Favicon
Building a Semantic Search Engine with OpenAI, Go, and PostgreSQL (pgvector)
Favicon
Go's Concurrency Decoded: Goroutine Scheduling
Favicon
Golang: Struct, Interface And Dependency Injection(DI)
Favicon
Desvendando Subprocessos: Criando um Bot de Música com Go
Favicon
go
Favicon
🚀 New Article Alert: Master sync.Pool in Golang! 🚀
Favicon
Week Seven Recap of #100DaysOfCode
Favicon
Ore: Advanced Dependency Injection Package for Go
Favicon
Golang vs C++: A Modern Alternative for High-Performance Applications

Featured ones: