4. Автоматическое обнаружение SQLi в CI/CD
Автоматическое обнаружение SQL Injection в CI/CD
Этот модуль научит вас настраивать полный конвейер автоматического обнаружения SQL-инъекций в Go-проектах — от pre-commit хуков на машине разработчика до мониторинга аномалий в production. Go-экосистема имеет зрелый набор инструментов безопасности: gosec, Semgrep с Go-правилами, govulncheck и golangci-lint — все они интегрируются в CI/CD за минуты.
Обзор инструментов
| Категория | Инструмент | Что делает | Когда применять |
|---|---|---|---|
| SAST | gosec | Статический анализ Go-кода, правила G201/G202 для SQLi | Pre-commit, CI |
| SAST | Semgrep | Pattern-matching правила, taint analysis для Go | Pre-commit, CI |
| SAST | staticcheck | Общий статический анализатор Go (косвенное обнаружение) | CI |
| SAST | golangci-lint | Meta-линтер, объединяет gosec + staticcheck + десятки других | Pre-commit, CI |
| DAST | sqlmap | Автоматический поиск SQLi в работающем приложении | QA/Staging |
| DAST | OWASP ZAP | Полноценный прокси-сканер веб-приложений | QA/Staging |
| SCA | govulncheck | Поиск уязвимых Go-зависимостей по базе vuln.go.dev | CI, мониторинг |
| SCA | Trivy | Сканирование контейнерных образов и зависимостей | CI, мониторинг |
1. SAST: gosec
gosec — стандартный инструмент статического анализа безопасности для Go. Для SQL-инъекций он использует два ключевых правила: G201 (SQL-запрос, сконструированный из пользовательского ввода) и G202 (SQL-запрос, сконструированный через fmt.Sprintf).
Установка и запуск
# Установка
go install github.com/securego/gosec/v2/cmd/gosec@latest
# Сканирование всего проекта
gosec ./...
# Только правила SQL-инъекций
gosec -include=G201,G202 ./...
# JSON-вывод для CI/CD
gosec -fmt=json -out=gosec-report.json ./...
# Вывод в формате SARIF (для GitHub Security tab)
gosec -fmt=sarif -out=gosec-report.sarif ./...
Что обнаруживают G201 и G202
gosec анализирует вызовы database/sql и ищет конкатенацию или форматирование строк в SQL-запросах:
// G201 — обнаружит: конкатенация строки в SQL-запросе
query := "SELECT * FROM users WHERE username = '" + username + "'"
rows, err := db.Query(query)
// G202 — обнаружит: fmt.Sprintf в SQL-запросе
query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", userID)
rows, err := db.Query(query)
// G202 — обнаружит: fmt.Sprintf с %v
query := fmt.Sprintf("DELETE FROM orders WHERE id = %v", orderID)
db.Exec(query)
// Безопасно — gosec НЕ будет жаловаться
rows, err := db.Query("SELECT * FROM users WHERE username = ?", username)
rows, err := db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1", userID)
Пример вывода gosec
[/internal/handlers/handlers.go:45] - G201 (CWE-89): SQL string formatting
(Confidence: HIGH, Severity: MEDIUM)
> query := "SELECT id, username, role FROM users WHERE username = '" + username + "' AND password = '" + password + "'"
[/internal/handlers/handlers.go:78] - G202 (CWE-89): SQL string concatenation
(Confidence: HIGH, Severity: MEDIUM)
> query := fmt.Sprintf("SELECT * FROM products WHERE category = '%s'", category)
Что gosec НЕ обнаруживает
gosec работает на уровне AST (abstract syntax tree) и не выполняет межпроцедурный анализ потока данных:
// gosec НЕ увидит: значение приходит из другой функции
func getQuery(input string) string {
return "SELECT * FROM users WHERE name = '" + input + "'"
}
func handler(w http.ResponseWriter, r *http.Request) {
q := getQuery(r.URL.Query().Get("name"))
db.Query(q) // gosec не отследит taint через вызов функции
}
// gosec НЕ увидит: Second-Order SQLi (данные из БД в другой запрос)
var savedName string
db.QueryRow("SELECT name FROM cache WHERE id = 1").Scan(&savedName)
db.Query("SELECT * FROM users WHERE name = '" + savedName + "'")
// gosec НЕ увидит: использование ORM с raw-запросом
db.Raw("SELECT * FROM users WHERE name = '" + name + "'").Scan(&users)
Подавление ложных срабатываний
Если gosec даёт ложноположительное (например, статическая строка), используйте аннотацию:
// Статическая строка, не содержит пользовательского ввода
query := "SELECT * FROM config WHERE key = 'app_version'" // #nosec G201
rows, err := db.Query(query)
Важно: никогда не используйте #nosec без комментария, объясняющего почему это безопасно. В code review отсутствие объяснения — красный флаг.
2. SAST: Semgrep
Semgrep обеспечивает более глубокий анализ, чем gosec, благодаря поддержке taint analysis (в Pro-версии) и гибким YAML-правилам. Для Go он имеет обширную библиотеку готовых правил.
Установка и запуск
# Установка
pip install semgrep
# или через brew
brew install semgrep
# Go-специфичные правила безопасности
semgrep --config "p/golang" ./...
# Только SQL-инъекции
semgrep --config "p/golang" --include="*.go" ./internal/
# С авто-набором правил (OWASP Top 10)
semgrep --config auto ./...
Готовые правила для SQL-инъекций в Go
| Rule ID | Что ищет |
|---|---|
go.lang.security.audit.sqli.tainted-sql-string |
Конкатенация строк в SQL с данными из http.Request |
go.lang.security.audit.sqli.string-formatted-query |
fmt.Sprintf в SQL-запросах |
go.lang.security.audit.database-sql-string-formatting |
Форматирование строк в database/sql вызовах |
go.gorilla.security.audit.sqli-taint |
SQLi через Gorilla Mux переменные |
go.gin.security.audit.sqli-taint |
SQLi через Gin context параметры |
Пользовательское правило для Go
Создайте файл .semgrep.yml в корне проекта:
rules:
- id: go-sqli-sprintf
patterns:
- pattern: |
$DB.$METHOD(fmt.Sprintf("...", ...))
- metavariable-regex:
metavariable: $METHOD
regex: (Query|QueryRow|QueryContext|Exec|ExecContext|Prepare)
message: >
SQL injection: fmt.Sprintf используется для построения SQL-запроса
в $DB.$METHOD(). Используйте параметризованные запросы:
db.Query("SELECT * FROM t WHERE id = ?", id)
severity: ERROR
languages: [go]
metadata:
cwe: "CWE-89"
owasp: "A03:2021 - Injection"
confidence: HIGH
- id: go-sqli-concatenation
patterns:
- pattern: |
$DB.$METHOD("..." + $VAR + "...")
- metavariable-regex:
metavariable: $METHOD
regex: (Query|QueryRow|QueryContext|Exec|ExecContext|Prepare)
message: >
SQL injection: конкатенация строк в $DB.$METHOD().
Используйте параметризованные запросы.
severity: ERROR
languages: [go]
metadata:
cwe: "CWE-89"
- id: go-sqli-strings-replace
patterns:
- pattern: |
$QUERY = strings.Replace($TEMPLATE, "...", $INPUT, ...)
...
$DB.$METHOD($QUERY, ...)
message: >
SQL injection: strings.Replace используется для подстановки
значений в SQL-запрос. Используйте параметризованные запросы.
severity: ERROR
languages: [go]
metadata:
cwe: "CWE-89"
Пример вывода Semgrep
internal/handlers/handlers.go
severity:error rule:go-sqli-sprintf
SQL injection: fmt.Sprintf используется для построения SQL-запроса
в db.Query(). Используйте параметризованные запросы.
45│ rows, err := db.Query(fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", name))
Semgrep vs gosec для SQLi
| Критерий | gosec | Semgrep |
|---|---|---|
| Правила SQLi | G201, G202 (2 правила) | 10+ готовых правил |
| Кастомные правила | Нет (только встроенные) | Да (YAML) |
| Taint analysis | Нет | Да (Pro) |
| Межпроцедурный анализ | Нет | Частично (Pro) |
| Second-Order SQLi | Нет | Частично (Pro) |
| Скорость | Очень быстрый (~2 сек) | Быстрый (~5-10 сек) |
| Ложноположительные | Больше | Меньше |
| Цена | Бесплатный | Community бесплатно, Pro платный |
| Интеграция с Go | Нативная (Go AST) | Через tree-sitter |
Рекомендация: используйте оба инструмента. gosec как быстрый первый фильтр (встроен в golangci-lint), Semgrep для глубокого анализа с кастомными правилами.
3. SAST: golangci-lint
golangci-lint — мета-линтер для Go, объединяющий десятки линтеров в один инструмент. Для обнаружения SQL-инъекций включите gosec и sqlclosecheck:
# .golangci.yml
linters:
enable:
- gosec # SQL-инъекции (G201, G202) + другие security правила
- sqlclosecheck # Незакрытые sql.Rows (утечки ресурсов)
- rowserrcheck # Непроверенные ошибки sql.Rows.Err()
- bodyclose # Незакрытые HTTP response body
linters-settings:
gosec:
includes:
- G201 # SQL query string formatting
- G202 # SQL query string concatenation
severity: high
confidence: medium
issues:
exclude-rules:
- path: _test\.go
linters:
- gosec # Тесты могут содержать небезопасный код для проверки
Запуск:
# Установка
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Запуск с конфигурацией
golangci-lint run ./...
# Только security линтеры
golangci-lint run --enable-only gosec,sqlclosecheck ./...
4. DAST: sqlmap
sqlmap — инструмент для автоматического поиска и эксплуатации SQL-инъекций в работающем приложении. В отличие от SAST, sqlmap находит уязвимости, которые не видны в коде (Second-Order, Blind SQLi, нюансы конкретной СУБД).
Базовое использование
# Установка
pip install sqlmap
# Тестирование GET-параметра
sqlmap -u "http://localhost:8080/api/search?q=test" --batch --level=3
# Тестирование POST-формы (login)
sqlmap -u "http://localhost:8080/login" \
--data="username=admin&password=test" \
--batch --level=3 --risk=2
# Тестирование с cookie (авторизованная зона)
sqlmap -u "http://localhost:8080/api/users?id=1" \
--cookie="session_token=abc123" \
--batch --level=5 --risk=3
# Указание СУБД для ускорения (Go-лабы используют SQLite)
sqlmap -u "http://localhost:8080/catalog?q=test" \
--dbms=sqlite --batch --level=3
Ключевые параметры для Go-приложений
| Параметр | Назначение |
|---|---|
--batch |
Авто-ответы на все вопросы (для CI/CD) |
--level=1-5 |
Глубина тестирования (3 — хороший баланс) |
--risk=1-3 |
Агрессивность (2 — безопасно для staging) |
--dbms=sqlite |
Go-лабы используют SQLite — ускоряет сканирование |
--technique=BEUST |
Boolean, Error, Union, Stacked, Time-based |
--forms |
Автоматически найти формы на странице |
--crawl=3 |
Обход сайта до глубины 3 |
--tamper=space2comment |
Обход WAF (замена пробелов на комментарии) |
--output-dir=./reports |
Директория для отчётов |
Скрипт для CI/CD
#!/bin/bash
# scripts/dast-sqlmap.sh — проверка что SQLi не найдены
TARGET="http://staging:8080"
REPORT_DIR="/tmp/sqlmap-report"
FOUND_VULN=0
# Тестируем все известные эндпоинты
ENDPOINTS=(
"/login --data=username=test&password=test"
"/api/search?q=test"
"/api/users?id=1 --cookie=session_token=$SESSION"
)
for ep in "${ENDPOINTS[@]}"; do
sqlmap -u "${TARGET}${ep}" \
--batch --level=3 --risk=2 --dbms=sqlite \
--output-dir="$REPORT_DIR" 2>&1 | tee /tmp/sqlmap-output.txt
if grep -q "is vulnerable" /tmp/sqlmap-output.txt; then
echo "FAIL: SQL injection found at ${ep}!"
FOUND_VULN=1
fi
done
if [ $FOUND_VULN -eq 1 ]; then
echo "DAST FAILED: SQL injection vulnerabilities detected"
exit 1
fi
echo "DAST PASSED: No SQL injection found"
5. DAST: OWASP ZAP
OWASP ZAP — полноценный прокси-сканер, который находит не только SQLi, но и XSS, CSRF, broken access control и другие уязвимости. Для Go-приложений он работает как чёрный ящик — сканирует HTTP-эндпоинты без знания исходного кода.
Автоматическое сканирование в Docker
# Baseline scan (пассивный, ~2 мин) — находит очевидные проблемы
docker run --rm --network host ghcr.io/zaproxy/zaproxy:stable \
zap-baseline.py -t http://localhost:8080 -r zap-baseline.html
# Full scan (активный, ~15-30 мин) — включает SQLi-тесты
docker run --rm --network host ghcr.io/zaproxy/zaproxy:stable \
zap-full-scan.py -t http://localhost:8080 -r zap-full.html
# API scan (для REST API)
docker run --rm --network host ghcr.io/zaproxy/zaproxy:stable \
zap-api-scan.py -t http://localhost:8080/openapi.json \
-f openapi -r zap-api.html
ZAP SQL Injection правила
| Rule ID | Название | Описание |
|---|---|---|
| 40018 | SQL Injection | Базовый тест (error-based) |
| 40019 | SQL Injection (MySQL) | MySQL-специфичные пейлоады |
| 40020 | SQL Injection (Hypersonic) | HyperSQL пейлоады |
| 40021 | SQL Injection (Oracle) | Oracle-специфичные |
| 40022 | SQL Injection (PostgreSQL) | PostgreSQL-специфичные |
| 40024 | SQL Injection (SQLite) | SQLite-специфичные (актуально для Go-лаб) |
| 90018 | Advanced SQL Injection | Blind + time-based |
Настройка правил для Go + SQLite
# .zap-rules.tsv — настройка правил для Go-проекта
# Формат: rule_id action parameter
40018 FAIL # SQL Injection — фейлить pipeline
40024 FAIL # SQLite Injection — фейлить pipeline
90018 FAIL # Advanced SQL Injection — фейлить pipeline
40019 IGNORE # MySQL — не актуально для SQLite
40021 IGNORE # Oracle — не актуально для SQLite
6. SCA: govulncheck и Trivy
SQL-инъекции могут быть не только в вашем коде, но и в ORM-библиотеках и драйверах СУБД. govulncheck проверяет Go-зависимости по официальной базе vuln.go.dev.
govulncheck
# Установка
go install golang.org/x/vuln/cmd/govulncheck@latest
# Проверка зависимостей
govulncheck ./...
# JSON-вывод для CI
govulncheck -json ./... > govulncheck-report.json
# Пример вывода
# Vulnerability #1: GO-2023-1571
# A request smuggling vulnerability exists in the
# net/http package when using MaxBytesHandler.
# Found in: net/http@go1.20.1
# Fixed in: net/http@go1.20.3
Trivy
# Сканирование Go-модуля
trivy fs --scanners vuln .
# Сканирование Docker-образа
trivy image myapp:latest
# Только critical и high
trivy image --severity CRITICAL,HIGH myapp:latest
# JSON для CI
trivy image --format json --output trivy-report.json myapp:latest
Какие CVE искать
Для Go-приложений с SQL наиболее релевантны уязвимости в:
| Пакет | Тип уязвимости | Пример CVE |
|---|---|---|
github.com/mattn/go-sqlite3 |
Buffer overflow, SQL injection | CVE-2022-35737 |
github.com/go-sql-driver/mysql |
Auth bypass, injection | CVE-2022-27664 |
github.com/lib/pq |
SQL injection в параметрах | Проверяйте vuln.go.dev |
gorm.io/gorm |
Raw SQL injection | Проверяйте vuln.go.dev |
net/http |
Request smuggling (косвенно) | GO-2023-1571 |
7. Pre-commit хуки
Makefile targets
# Makefile — security-related targets
.PHONY: security security-sast security-dast security-sca
# Все проверки безопасности
security: security-sast security-sca
# SAST: gosec + Semgrep
security-sast:
@echo "=== Running gosec (G201, G202 — SQL Injection) ==="
gosec -include=G201,G202 -fmt=json -out=reports/gosec.json ./...
@echo "=== Running Semgrep ==="
semgrep --config .semgrep.yml --config "p/golang" --json -o reports/semgrep.json ./...
# SCA: govulncheck + Trivy
security-sca:
@echo "=== Running govulncheck ==="
govulncheck ./...
@echo "=== Running Trivy ==="
trivy fs --scanners vuln --exit-code 1 --severity CRITICAL,HIGH .
# DAST: sqlmap + ZAP (требует запущенное приложение)
security-dast:
@echo "=== Running sqlmap ==="
bash scripts/dast-sqlmap.sh
@echo "=== Running ZAP ==="
docker run --rm --network host ghcr.io/zaproxy/zaproxy:stable \
zap-full-scan.py -t http://localhost:8080 -r reports/zap.html
# Quick check (для pre-commit)
security-quick:
gosec -include=G201,G202 -quiet ./...
govulncheck ./...
Pre-commit конфигурация
# .pre-commit-config.yaml
repos:
- repo: https://github.com/securego/gosec
rev: v2.21.4
hooks:
- id: gosec
args: ['-include=G201,G202', '-quiet', './...']
- repo: https://github.com/golangci/golangci-lint
rev: v1.62.2
hooks:
- id: golangci-lint
args: ['--enable-only=gosec,sqlclosecheck,rowserrcheck']
- repo: https://github.com/semgrep/semgrep
rev: v1.108.0
hooks:
- id: semgrep
args: ['--config', '.semgrep.yml', '--error']
types: [go]
Установка:
pip install pre-commit
pre-commit install
# Теперь при git commit автоматически запустятся gosec и Semgrep
8. CI/CD Pipeline
GitHub Actions
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
sast:
name: SAST Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: gosec — SQL Injection Rules
uses: securego/gosec@master
with:
args: '-include=G201,G202 -fmt=sarif -out=gosec.sarif ./...'
- name: Upload gosec SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: gosec.sarif
- name: Semgrep — Go Security Rules
uses: semgrep/semgrep-action@v1
with:
config: >-
p/golang
.semgrep.yml
- name: golangci-lint — Security Linters
uses: golangci/golangci-lint-action@v6
with:
args: --enable-only=gosec,sqlclosecheck,rowserrcheck
sca:
name: Dependency Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Trivy — Filesystem Scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
exit-code: '1'
dast:
name: DAST Scan
runs-on: ubuntu-latest
needs: [sast]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Build and Start Application
run: |
go build -o app ./cmd/main.go
LAB_ADMIN_PASS=test LAB_FLAG=flag{test} ./app &
sleep 5
- name: OWASP ZAP — Full Scan
uses: zaproxy/action-full-scan@v0.12.0
with:
target: 'http://localhost:8080'
rules_file_name: '.zap-rules.tsv'
allow_issue_writing: false
- name: sqlmap — SQL Injection Scan
run: |
pip install sqlmap
sqlmap -u "http://localhost:8080/login" \
--data="username=admin&password=test" \
--batch --level=3 --risk=2 --dbms=sqlite \
--output-dir=/tmp/sqlmap 2>&1 | tee /tmp/sqlmap.log
if grep -q "is vulnerable" /tmp/sqlmap.log; then
echo "::error::SQL injection vulnerability found!"
exit 1
fi
container:
name: Container Scan
runs-on: ubuntu-latest
needs: [sast]
steps:
- uses: actions/checkout@v4
- name: Build Docker Image
run: docker build -t app:${{ github.sha }} .
- name: Trivy — Image Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'app:${{ github.sha }}'
severity: 'CRITICAL,HIGH'
exit-code: '1'
GitLab CI
# .gitlab-ci.yml
stages:
- sast
- sca
- build
- dast
gosec:
stage: sast
image: securego/gosec:latest
script:
- gosec -include=G201,G202 -fmt=json -out=gosec-report.json ./...
artifacts:
reports:
sast: gosec-report.json
semgrep:
stage: sast
image: semgrep/semgrep:latest
script:
- semgrep --config p/golang --config .semgrep.yml --json -o semgrep-report.json ./...
artifacts:
reports:
sast: semgrep-report.json
govulncheck:
stage: sca
image: golang:1.23
script:
- go install golang.org/x/vuln/cmd/govulncheck@latest
- govulncheck -json ./... > govulncheck-report.json
artifacts:
paths:
- govulncheck-report.json
trivy:
stage: sca
image: aquasec/trivy:latest
script:
- trivy fs --scanners vuln --severity CRITICAL,HIGH --exit-code 1 .
zap:
stage: dast
image: ghcr.io/zaproxy/zaproxy:stable
services:
- name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
alias: app
script:
- zap-full-scan.py -t http://app:8080 -r zap-report.html -I
artifacts:
paths:
- zap-report.html
9. Мониторинг в Production
SAST и DAST обнаруживают уязвимости до деплоя. Но если уязвимость прошла все проверки (zero-day, логическая ошибка, Second-Order SQLi), нужен мониторинг в production.
WAF: ModSecurity с Core Rule Set
# nginx.conf с ModSecurity
load_module modules/ngx_http_modsecurity_module.so;
server {
modsecurity on;
modsecurity_rules_file /etc/modsecurity/main.conf;
location / {
proxy_pass http://go-app:8080;
}
}
# modsecurity.conf — правила для SQLi
# CRS (Core Rule Set) включает ~50 правил для SQLi
SecRuleEngine On
# Правило 942100 — обнаружение SQL-инъекций через libinjection
# Правило 942110 — обнаружение SQL-инъекций (keyword detection)
# Правило 942120 — обнаружение SQL-операторов (UNION, SELECT, etc.)
# Правило 942150 — обнаружение SQL-функций (CONCAT, CHAR, etc.)
# Кастомное правило для SQLite (Go-лабы)
SecRule ARGS "@rx (?i)(sqlite_version|sqlite_master|randomblob)" \
"id:100001,\
phase:2,\
block,\
log,\
msg:'SQLite-specific injection attempt',\
severity:'CRITICAL'"
Логирование SQL-ошибок в Go
// middleware/sql_monitor.go
package middleware
import (
"log/slog"
"net/http"
"strings"
)
// SQLErrorPatterns — паттерны, указывающие на попытку SQL-инъекции
var sqlErrorPatterns = []string{
"syntax error",
"SQLITE_ERROR",
"unrecognized token",
"near \"UNION\"",
"near \"SELECT\"",
"near \"OR\"",
"no such column",
"ambiguous column name",
}
func SQLInjectionMonitor(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Проверяем параметры запроса на подозрительные паттерны
for key, values := range r.URL.Query() {
for _, v := range values {
if containsSQLPattern(v) {
slog.Warn("Suspicious SQL pattern in request",
"param", key,
"value", v,
"ip", r.RemoteAddr,
"path", r.URL.Path,
"user_agent", r.UserAgent(),
)
}
}
}
next.ServeHTTP(w, r)
})
}
func containsSQLPattern(s string) bool {
lower := strings.ToLower(s)
patterns := []string{
"union select", "' or '1'='1", "'; drop table",
"1=1", "' or 1=1", "sleep(", "benchmark(",
"sqlite_version", "information_schema",
}
for _, p := range patterns {
if strings.Contains(lower, p) {
return true
}
}
return false
}
Alerting: Prometheus + Grafana
// metrics/security.go
package metrics
import "github.com/prometheus/client_golang/prometheus"
var (
SQLInjectionAttempts = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "security_sqli_attempts_total",
Help: "Number of suspected SQL injection attempts",
},
[]string{"endpoint", "source_ip"},
)
SQLErrorsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "security_sql_errors_total",
Help: "Number of SQL errors (potential injection indicator)",
},
[]string{"endpoint", "error_type"},
)
)
# prometheus/alerts.yml
groups:
- name: sql_injection
rules:
- alert: HighSQLInjectionRate
expr: rate(security_sqli_attempts_total[5m]) > 10
for: 2m
labels:
severity: critical
annotations:
summary: "High rate of SQL injection attempts"
description: "{{ $labels.endpoint }} receiving {{ $value }} SQLi attempts/sec"
- alert: SQLErrorSpike
expr: rate(security_sql_errors_total[5m]) > 5
for: 1m
labels:
severity: warning
annotations:
summary: "Spike in SQL errors"
description: "Possible SQL injection probing at {{ $labels.endpoint }}"
10. Сравнительная таблица инструментов
| Инструмент | Категория | SQLi Coverage | False Positive Rate | Скорость | Цена |
|---|---|---|---|---|---|
| gosec (G201/G202) | SAST | Средний — прямая конкатенация/sprintf | Низкий | Очень быстрый (~2с) | Бесплатный |
| Semgrep | SAST | Высокий — паттерны + taint (Pro) | Очень низкий | Быстрый (~10с) | Community бесплатно |
| golangci-lint | SAST | Средний (через gosec) | Низкий | Быстрый (~5с) | Бесплатный |
| sqlmap | DAST | Очень высокий — все типы SQLi | Минимальный | Медленный (~5-30мин) | Бесплатный |
| OWASP ZAP | DAST | Высокий — error/blind/time-based | Низкий | Медленный (~15-30мин) | Бесплатный |
| govulncheck | SCA | Зависимости Go | Нет (точный) | Быстрый (~3с) | Бесплатный |
| Trivy | SCA | Зависимости + образы | Низкий | Быстрый (~10с) | Бесплатный |
| ModSecurity CRS | WAF | Runtime — все типы | Средний | Реалтайм | Бесплатный |
Что каждый инструмент пропускает
| Слепая зона | Какой инструмент пропускает | Кто ловит |
|---|---|---|
| Second-Order SQLi | gosec, Semgrep Community | sqlmap, ZAP, Semgrep Pro |
| Межпроцедурный taint | gosec | Semgrep Pro |
| Blind SQLi (time-based) | Все SAST | sqlmap, ZAP |
| SQLi через ORM raw queries | gosec (частично) | Semgrep с кастомными правилами |
| Zero-day в зависимостях | govulncheck (до обновления БД) | WAF, мониторинг |
| Логические SQLi (бизнес-логика) | Все автоматические | Code review, пентест |
11. Чеклист эшелонированной защиты
Полная стратегия обнаружения SQL-инъекций в Go-проекте:
┌─────────────────────────────────────────────────────────┐
│ IDE (разработка) │
│ └─ gopls + gosec integration + Semgrep LSP │
├─────────────────────────────────────────────────────────┤
│ Pre-commit (локально) │
│ └─ gosec G201/G202 + Semgrep .semgrep.yml │
├─────────────────────────────────────────────────────────┤
│ CI/CD — SAST (каждый push) │
│ └─ golangci-lint (gosec) + Semgrep + govulncheck │
├─────────────────────────────────────────────────────────┤
│ CI/CD — DAST (staging) │
│ └─ sqlmap (level=3) + OWASP ZAP full scan │
├─────────────────────────────────────────────────────────┤
│ CI/CD — SCA (каждый push) │
│ └─ govulncheck + Trivy image scan │
├─────────────────────────────────────────────────────────┤
│ Production — WAF │
│ └─ ModSecurity CRS + кастомные SQLite-правила │
├─────────────────────────────────────────────────────────┤
│ Production — Мониторинг │
│ └─ SQL error logging + Prometheus alerts + slog │
└─────────────────────────────────────────────────────────┘
Финальный чеклист
- gosec G201/G202 включены в golangci-lint и CI pipeline
- Semgrep с Go-правилами и кастомными
.semgrep.ymlзапускается на каждый PR - govulncheck проверяет зависимости на известные CVE
- Trivy сканирует Docker-образы перед деплоем
- sqlmap тестирует все эндпоинты с пользовательским вводом на staging
- OWASP ZAP выполняет full scan на staging перед release
- WAF (ModSecurity) с CRS защищает production
- SQL-ошибки логируются через
slogи мониторятся в Prometheus/Grafana - Pre-commit хуки установлены у всех разработчиков
-
#nosecаннотации проходят обязательный code review - SARIF-отчёты загружаются в GitHub Security tab для отслеживания трендов
- Регулярный пентест (раз в квартал) проверяет то, что автоматика не поймает
Дополнительные материалы
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.