Skip to main content

Insecure Use of SQL Queries

Fixing Insecure Use of SQL Queries

About SQL Injection (SQLi)

What is SQL injection (SQLi)?

SQL injection (SQLi) is a type of security vulnerability that allows attackers to exploit an application's interaction with a SQL database.

This occurs when an application fails to properly sanitize user input and includes untrusted data in an SQL query, allowing attackers to inject malicious code or modify the intended behavior of the query.

SQL injection can affect various types of applications that interact with SQL databases, such as web applications, content management systems, and e-commerce platforms.

Attackers can use various techniques, such as crafted queries or filter values, to inject malicious code or entities into the application.

Check out this video for a high-level explanation:

What is the impact of SQL injections?

SQL injection can lead to various security threats and risks, such as:

  • Information disclosure: SQL injection can expose sensitive information, such as user data, login credentials, or other types of confidential information, to unauthorized parties.
  • Unauthorized access: SQL injection can allow attackers to gain unauthorized access to databases, perform unauthorized actions, or modify data.
  • Denial-of-service: SQL injection can cause denial-of-service (DoS) attacks by injecting malicious queries or values that consume system resources, such as CPU or memory, leading to system crashes or slowdowns.
  • Arbitrary code execution: SQL injection can execute arbitrary code on the database server by injecting malicious queries or values that exploit vulnerabilities in the application or the underlying operating system.

SQL injections are very common and have been the cause of many high-profile breaches.

How to prevent SQL injections?

To prevent SQL injection, it is important to follow security best practices and implement appropriate security measures, such as:

  • Use parameterized queries: Use parameterized queries and other secure coding practices to ensure that user input is properly sanitized and not used to construct SQL queries directly.
  • Use input validation: Validate user input to ensure that it is safe and does not contain malicious code or characters that can be used for injection attacks.
  • Limit user access: Limit user access to databases to authorized users and restrict access to sensitive information and actions.
  • Use secure coding practices: Follow secure coding practices, such as code reviews, vulnerability scanning and testing, and threat modeling, to ensure that the source code is free of vulnerabilities and that SQL injection vulnerabilities are addressed.
  • Use a web application firewall: Use a web application firewall (WAF) that can help prevent SQL injection by filtering and blocking malicious traffic.

References

Taxonomies

Explanation & Prevention

Training

Fixing Insecure Use of SQL Queries (lang)

This rule detects user-controlled data being formatted into a SQL query in a way that leads to SQL injection.

Rule-specific references:

Option A: Using db.Query with Parameterized Queries

A parameterized query looks much like a normal query. However, instead of using string formatting or concatenation to assemble the query, you use a placeholder instead.

For example, the following pattern is vulnerable:

db.Query("SELECT * FROM table WHERE id = " + id)

It should be replaced with a parameterized SQL query:

db.Query("SELECT * FROM table WHERE id = ?", id)
  1. Go through the issues that GuardRails has identified

  2. Locate the vulnerable pattern (example below):

    func handler(db *db.DB) func(w http.ResponseWriter, req *http.Request) {
    return func(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")
    result1, err := db.Query("SELECT * FROM table WHERE id = " + id)
    if err != nil {
    panic(err)https://pkg.go.dev/database/sql
    }

    query := fmt.Sprintf("SELECT * FROM table2 WHERE id = %v", id)
    result2, err := db.Query(query)
    if err != nil {
    panic(err)
    }
    }
    }
  3. Replace the vulnerable pattern with a parameterized SQL query (example below):

    func handler(db *db.DB) func(w http.ResponseWriter, req *http.Request) {
    return func(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")
    result, err := db.Query("SELECT * FROM table WHERE id = ?", id)
    if err != nil {
    panic(err)
    }

    result2, err = db.Query("SELECT * FROM table2 WHERE id = ?", id)
    if err != nil {
    panic(err)
    }
    }
    }
  4. Test it

  5. Ship it 🚢 and relax 🌴

Fixing Insecure Use of SQL Queries (go-pg)

This rule detects user-controlled data being passed to a go-pg SQL query in a way that leads to SQL injection.

Rule-specific references:

Option A: Use parameterized queries (go-pg)

A parametrized query looks much like a normal query. However, instead of using string formatting or concatenation to assemble the query, you use a placeholder instead.

  1. Go through the issues that GuardRails identified in the PR/MR.

  2. Locate the vulnerable patterns (example below)

    var db *pg.DB

    func handler(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")

    book := new(Book)
    err = db.Model(book).
    Column("title", "text").
    Where("id = " + id).
    Select()
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    student := new(Student)
    err = db.Model(student).
    Column("name", "class").
    Where(fmt.Sprintf("id = %v", id)).
    Select()
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    data := Lesson{
    student: student
    book: book
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(data)
    }
  3. Replace the vulnerable pattern with a parameterized SQL query (example below):

    var db *pg.DB

    func handler(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")

    book := new(Book)
    err = db.Model(book).
    Column("title", "text").
    Where("id = ?", id).
    Select()
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    student := new(Student)
    err = db.Model(student).
    Column("name", "class").
    Where("id = ?", id).
    Select()
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    data := Lesson{
    student: student
    book: book
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(data)
    }
  4. Test it

  5. Ship it 🚢 and relax 🌴

Fixing Insecure Use of SQL Queries (pgx)

This rule detects user-controlled data being passed to a pgx SQL query in a way that leads to SQL injection.

Rule-specific references:

Option A: Use parameterized queries (pgx)

A parametrized query looks much like a normal query. However, instead of using methods such as string formatting, or concatenation to assemble the query, you use a placeholder instead.

  1. Go through the issues that GuardRails identified in the PR/MR.

  2. Locate the vulnerable pattern (example below):

    var conn *pgx.Conn

    func handler(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")

    var name string
    var weight int64
    err = conn.QueryRow(context.Background(), "SELECT name, weight FROM widgets WHERE id=" + id).Scan(&name, &weight)
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    var type string
    var count int64
    err = conn.QueryRow(context.Background(), fmt.Sprintf("SELECT type, count FROM widgets WHERE id=%v", id)).Scan(&type, &count)
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }
    }
  3. Replace the vulnerable pattern with a parameterized SQL query (example below):

    var conn *pgx.Conn

    func handler(w http.ResponseWriter, req *http.Request) {
    id := req.URL.Query().Get("id")

    var name string
    var weight int64
    err = conn.QueryRow(context.Background(), "SELECT name, weight FROM widgets WHERE id=?", id).Scan(&name, &weight)
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }

    var type string
    var count int64
    err = conn.QueryRow(context.Background(), "SELECT type, count FROM widgets WHERE id=$1", id).Scan(&type, &count)
    if err != nil {
    http.Error(w, fmt.Sprintf("QueryRow failed: %v\n", err), http.StatusInternalServerError)
    return
    }
    }
  4. Test it

  5. Ship it 🚢 and relax 🌴