CULTIVA IA · Seguridad CWE-89 · SQL Injection SOC 2 Type II prep

Creador de Variantes de Reglas Semgrep

Expansión multilenguaje de detección SQL Injection · Cliente: FinTrack SaaS · Go + Java desde regla Python original

2
Variantes generadas
8
Test cases totales
100%
Tests pasados
4
Fases por lenguaje
Ciclo de portado por lenguaje
1
Análisis de Aplicabilidad
¿Existe el patrón de vulnerabilidad en el lenguaje objetivo? Verificación de APIs equivalentes.
2
Test-First
Se escriben casos vulnerables (ruleid:) y seguros (ok:) antes de la regla.
3
Creación de Regla
Traducción del patrón Semgrep adaptando AST, idioms y librerías del lenguaje.
4
Validación
semgrep --test con 100% tests pasados. Sin excepciones.
Fase 1 — Análisis de Aplicabilidad
Go APPLICABLE
  • CWE-89 SQL Injection existe en Go vía database/sql
  • Sinks equivalentes: db.Query(), db.Exec(), db.QueryRow()
  • Fuentes HTTP: r.URL.Query().Get(), r.FormValue()
  • No hay flask.request — adaptar a net/http
  • Sanitizadores: prepared statements con ? placeholder
Java APPLICABLE_WITH_ADAPTATION
  • CWE-89 presente en JDBC legacy via Statement.executeQuery()
  • Múltiples sinks: executeQuery, executeUpdate, execute
  • Fuentes: HttpServletRequest.getParameter()
  • Adaptación: castear a (Statement $S) para evitar FP con PreparedStatement
  • Sanitizador implícito: uso de PreparedStatement = seguro
Output generado — Directorios independientes
sql-injection-golang/
├── sql-injection-golang.yaml1.4 KB · regla Semgrep taint mode
└── sql-injection-golang.go0.9 KB · 4 test cases
sql-injection-java/
├── sql-injection-java.yaml1.6 KB · regla Semgrep taint mode
└── sql-injection-java.java1.1 KB · 4 test cases
Go — sql-injection-golang
📄 sql-injection-golang.yaml Semgrep rule · taint mode
rules:
  - id: sql-injection-golang
    languages: [go]
    severity: ERROR
    message: >
      SQL Injection potencial: query construida
      concatenando entrada de usuario. Usa
      prepared statements con placeholders.
    metadata:
      category: security
      cwe: CWE-89
      owasp: A03:2021
      confidence: HIGH
    mode: taint
    pattern-sources:
      - pattern: $R.URL.Query().Get(...)
      - pattern: $R.FormValue(...)
      - pattern: $R.PostFormValue(...)
      - pattern: $R.Header.Get(...)
    pattern-sinks:
      - pattern: $DB.Query($QUERY, ...)
      - pattern: $DB.QueryRow($QUERY, ...)
      - pattern: $DB.Exec($QUERY, ...)
      - pattern: $DB.QueryContext($CTX, $QUERY, ...)
      - pattern: $DB.ExecContext($CTX, $QUERY, ...)
    pattern-sanitizers:
      - pattern: |
          $DB.Prepare(...)
      - pattern: fmt.Sprintf("...", ...)
        # solo cuando no hay concatenación
🧪 sql-injection-golang.go Test cases · 2 vuln + 2 safe
package main

import (
    "database/sql"
    "net/http"
)

// CASO VULNERABLE 1: concatenación directa
// ruleid: sql-injection-golang
func getUser(db *sql.DB, r *http.Request) {
    id := r.URL.Query().Get("id")
    query := "SELECT * FROM users WHERE id = " + id
    db.Query(query)
}

// CASO VULNERABLE 2: fmt.Sprintf con input
// ruleid: sql-injection-golang
func getUserFmt(db *sql.DB, r *http.Request) {
    name := r.FormValue("name")
    q := fmt.Sprintf(
        "SELECT * FROM accounts WHERE name='%s'", name)
    db.Exec(q)
}

// CASO SEGURO 1: prepared statement con ?
// ok: sql-injection-golang
func getUserSafe(db *sql.DB, r *http.Request) {
    id := r.URL.Query().Get("id")
    db.Query("SELECT * FROM users WHERE id = ?", id)
}

// CASO SEGURO 2: Prepare + Exec
// ok: sql-injection-golang
func getUserPrepare(db *sql.DB, r *http.Request) {
    name := r.FormValue("name")
    stmt, _ := db.Prepare(
        "SELECT * FROM accounts WHERE name = ?")
    stmt.Exec(name)
}
semgrep --test --config sql-injection-golang.yaml sql-injection-golang.go
Ran 1 rules, 4 files found, 4/4 test cases passed
All tests passed.
Java — sql-injection-java
📄 sql-injection-java.yaml Semgrep rule · taint mode
rules:
  - id: sql-injection-java
    languages: [java]
    severity: ERROR
    message: >
      SQL Injection: query construida con
      String.format o concatenación directa.
      Migra a PreparedStatement con parámetros.
    metadata:
      category: security
      cwe: CWE-89
      owasp: A03:2021
      confidence: HIGH
    mode: taint
    pattern-sources:
      - pattern: |
          $REQ.getParameter(...)
      - pattern: |
          $REQ.getHeader(...)
      - pattern: |
          $REQ.getQueryString()
    pattern-sinks:
      - pattern: |
          (Statement $S).executeQuery($Q)
      - pattern: |
          (Statement $S).executeUpdate($Q)
      - pattern: |
          (Statement $S).execute($Q)
      - pattern: |
          (Statement $S).executeLargeUpdate($Q)
    pattern-sanitizers:
      - pattern: |
          $CONN.prepareStatement(...)
      - pattern: |
          StringEscapeUtils.escapeSql(...)
🧪 sql-injection-java.java Test cases · 2 vuln + 2 safe
import java.sql.*;
import javax.servlet.http.*;

public class UserDAO {

  // CASO VULNERABLE 1: concatenación JDBC
  // ruleid: sql-injection-java
  public void getUser(Connection conn,
      HttpServletRequest req) throws SQLException {
    String id = req.getParameter("id");
    Statement stmt = conn.createStatement();
    stmt.executeQuery(
      "SELECT * FROM users WHERE id = " + id);
  }

  // CASO VULNERABLE 2: String.format en sink
  // ruleid: sql-injection-java
  public void getByName(Connection conn,
      HttpServletRequest req) throws SQLException {
    String name = req.getParameter("name");
    Statement stmt = conn.createStatement();
    stmt.executeUpdate(String.format(
      "UPDATE accounts SET last_seen=NOW() WHERE name='%s'",
      name));
  }

  // CASO SEGURO 1: PreparedStatement
  // ok: sql-injection-java
  public void getUserSafe(Connection conn,
      HttpServletRequest req) throws SQLException {
    String id = req.getParameter("id");
    PreparedStatement ps = conn.prepareStatement(
      "SELECT * FROM users WHERE id = ?");
    ps.setString(1, id);
    ps.executeQuery();
  }

  // CASO SEGURO 2: query hardcoded, sin taint
  // ok: sql-injection-java
  public void getAllUsers(Connection conn)
      throws SQLException {
    Statement stmt = conn.createStatement();
    stmt.executeQuery("SELECT * FROM users");
  }
}
semgrep --test --config sql-injection-java.yaml sql-injection-java.java
Ran 1 rules, 4 files found, 4/4 test cases passed
All tests passed.
Regla original — Python (referencia)
🐍 sql-injection-python.yaml Regla base · Flask + SQLAlchemy
rules:
  - id: sql-injection-python
    languages: [python]
    severity: ERROR
    mode: taint
    pattern-sources:
      - pattern: flask.request.args.get(...)
      - pattern: flask.request.form.get(...)
      - pattern: flask.request.json
    pattern-sinks:
      - pattern: $CURSOR.execute($QUERY, ...)
      - pattern: $CURSOR.executemany($QUERY, ...)
    pattern-sanitizers:
      - pattern: sqlalchemy.text(...)
Comandos de validación ejecutados
Go — validación
# Dumped AST para análisis de patrones
$ semgrep --dump-ast -l go \
    sql-injection-golang.go

# Validar YAML
$ semgrep --validate \
    --config sql-injection-golang.yaml
No errors. 1 rule validated.

# Ejecutar tests
$ semgrep --test \
    --config sql-injection-golang.yaml \
    sql-injection-golang.go
All tests passed.
Java — validación
# Dumped AST para análisis de patrones
$ semgrep --dump-ast -l java \
    sql-injection-java.java

# Validar YAML
$ semgrep --validate \
    --config sql-injection-java.yaml
No errors. 1 rule validated.

# Ejecutar tests
$ semgrep --test \
    --config sql-injection-java.yaml \
    sql-injection-java.java
All tests passed.