Go contra hackers: proteção contra SQL Injection e XSS na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que até desenvolvedores Go caem nas armadilhas dos hackers?

\n\n

Go é famoso por sua velocidade, simplicidade e ferramentas de segurança integradas. Mas se consolar com a frase "eu programo em Go, então estou seguro" é uma ilusão perigosa. SQL Injection e ataques XSS não são relíquias do passado. Eles ainda derrubam sites e vazam bancos de dados diariamente, e Go não é exceção.

\n\n

O problema é que Go oferece ferramentas poderosas ao desenvolvedor, mas não as utiliza por você. Você pode acidentalmente concatenar uma consulta SQL usando fmt.Sprintf ou exibir um comentário de usuário sem escape — e um invasor terá acesso ao seu banco de dados ou roubará os cookies dos visitantes.

\n\n

Neste artigo, vamos abordar os dois tipos de ataque mais perigosos — SQL Injection e Cross-Site Scripting (XSS) — e mostrar como preveni-los usando Go nativo e bibliotecas populares. Você não receberá apenas teoria, mas sim modelos de código prontos que pode inserir no seu projeto ainda hoje.

\n\n

SQL Injection em Go: como ocorrem e como eliminá-los pela raiz

\n\n

Erro típico: concatenação de strings

\n\n

Imagine que você tem um endpoint para obter um usuário pelo ID. A forma mais ingênua (e perigosa) de escrever a consulta é assim:

\n\n
package main\n\nimport (\n    "database/sql"\n    "fmt"\n    "log"\n    _ "github.com/lib/pq"\n)\n\nfunc getUserByID(db *sql.DB, userID string) {\n    // PERIGOSO! Concatenação de strings\n    query := fmt.Sprintf("SELECT id, name, email FROM users WHERE id = '%s'", userID)\n    rows, err := db.Query(query)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer rows.Close()\n    // ... processamento\n}
\n\n

Se um invasor passar para userID a string 1' OR '1'='1, a consulta se torna:

\n\n
SELECT id, name, email FROM users WHERE id = '1' OR '1'='1'
\n\n

Pronto — ele obterá todos os usuários do banco de dados. E se ele digitar 1'; DROP TABLE users; --, você perderá a tabela.

\n\n

Solução: consultas parametrizadas (prepared statements)

\n\n

O driver Go para PostgreSQL, MySQL e SQLite suporta prepared statements. Eles separam o código SQL dos dados, e o driver escapa automaticamente os caracteres perigosos.

\n\n
func getUserByIDSafe(db *sql.DB, userID string) {\n    // SEGURO: consulta parametrizada\n    query := "SELECT id, name, email FROM users WHERE id = $1"\n    rows, err := db.Query(query, userID)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer rows.Close()\n    // ... processamento\n}
\n\n

Observe o $1 — é um placeholder para o primeiro argumento. No MySQL, usa-se o símbolo ?. Agora, mesmo que userID contenha 1' OR '1'='1, o driver interpretará isso como um valor string, e não como parte do código SQL.

\n\n

Trabalhando com o pacote sqlx

\n\n

A biblioteca github.com/jmoiron/sqlx torna o código ainda mais limpo. Ela suporta parâmetros nomeados e escaneamento automático para structs:

\n\n
import "github.com/jmoiron/sqlx"\n\ntype User struct {\n    ID    int    `db:"id"`\n    Name  string `db:"name"`\n    Email string `db:"email"`\n}\n\nfunc getUserByIDSqlx(db *sqlx.DB, userID string) (*User, error) {\n    user := &User{}\n    // Parâmetro nomeado :id\n    err := db.Get(user, "SELECT * FROM users WHERE id = :id", sqlx.Named("id", userID))\n    if err != nil {\n        return nil, err\n    }\n    return user, nil\n}
\n\n

Importante: mesmo se você usar uma ORM como GORM ou Ent, certifique-se de que ela esteja configurada para usar prepared statements. Algumas versões antigas de ORMs permitiam consultas "cruas".

\n\n

XSS em Go: quando seu site atira no próprio pé

\n\n

Como ocorre um ataque XSS

\n\n

XSS (Cross-Site Scripting) ocorre quando você insere conteúdo do usuário na página sem fazer o escape. Um at

Blogs

Book Recommendations