DEV Community

rohit20001221
rohit20001221

Posted on

SQL queries in golang text/template

I initially considered using Go's text/template package to improve productivity when developing backend APIs by dynamically generating SQL queries. However, I discovered that this approach introduces a significant security risk—SQL injection—if not handled correctly.

Example of a Vulnerable SQL Query Using text/template

package main

import (
    "os"
    "text/template"
)

const queryTemplate = `SELECT * FROM users WHERE username = '{{.Username}}';`

func main() {
    tmpl, err := template.New("sql").Parse(queryTemplate)
    if err != nil {
        panic(err)
    }

    data := map[string]string{
        "Username": "admin' OR '1'='1", // Malicious input
    }

    tmpl.Execute(os.Stdout, data)
}
Enter fullscreen mode Exit fullscreen mode

Output:

SELECT * FROM users WHERE username = 'admin' OR '1'='1';
Enter fullscreen mode Exit fullscreen mode

Why is this Vulnerable?

Since the query is built using string interpolation, an attacker can manipulate the input ("admin' OR '1'='1") to bypass authentication or retrieve unauthorized data. If executed, this query would return all users instead of just the intended one.

A Secure Approach

To address this issue, I have developed a utility package that enables secure and dynamic SQL query generation using Go templates while ensuring protection against SQL injection.

Installation
You can install the package using:

go get github.com/rabbit-backend/template

Using the Execute Method for Safe Query Generation

The Execute method transforms SQL queries into parameterized queries, making them safe from SQL injection.

package main

import (
    "fmt"

    engine "github.com/rabbit-backend/template"
)

func main() {
    query, args := engine.Execute(
        "test/app.sql",
        map[string]map[string]string{
            "args": {"user": "admin' OR '1'='1"},
        },
    )

    fmt.Println(query, args)
}
Enter fullscreen mode Exit fullscreen mode

SQL Template (test/app.sql)

SELECT * FROM users WHERE username = {{.args.user | __sql_arg__}};
Enter fullscreen mode Exit fullscreen mode

output:

SELECT * FROM users WHERE username = $1  ["admin' OR '1'='1'"]
Enter fullscreen mode Exit fullscreen mode

How This Works

Unlike raw string substitution, the Execute method sanitizes the SQL by converting it into a parameterized query. The query and arguments can then be passed to sql/db for safe execution against your database, preventing SQL injection attacks.

you can find the source code of the package at
https://github.com/rabbit-backend/template

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more