Aller au contenu

SAST avec Semgrep

Analyser votre propre code source pour détecter les failles de sécurité avant qu'elles n'atteignent la production.


SCA vs SAST

Deux approches complementaires, pas interchangeables :

  • SCA (Software Composition Analysis) — scanne les dépendances (le code des autres)
  • SAST (Static Application Security Testing) — scanne votre code source (votre logique)
graph LR
    A["Votre code"] -->|"SAST (Semgrep)"| B["Failles dans votre logique"]
    C["Dependances"] -->|"SCA (Trivy/pip-audit)"| D["CVE connues"]

Complementaires, pas substituables

Un projet peut avoir zero CVE dans ses dépendances et être truffe d'injections SQL dans son propre code. Inversement, un code source impeccable peut embarquer une librairie vulnerable. Les deux scans sont nécessaires.


Pourquoi Semgrep

Semgrep se distingue des autres outils SAST par plusieurs caractéristiques :

  • Léger — pas besoin de serveur, un simple binaire CLI
  • Offline natif — fonctionne sans connexion internet une fois les règles telechargees
  • Règles YAML lisibles — chaque règle est un fichier YAML comprehensible par un humain
  • Pas de compilation — analyse le code source directement, sans build préalable
  • Multi-langage — Python, JavaScript, TypeScript, Java, Go, Ruby, C, et bien d'autres

Installation

pip install semgrep

Verifiez l'installation :

semgrep --version
brew install semgrep
docker run --rm -v "${PWD}:/src" returntocorp/semgrep semgrep --config auto /src

Télécharger les règles OWASP pour usage hors-ligne

Pour un environnement airgap ou simplement pour maîtriser les règles utilisées :

# Cloner le depot officiel de regles
git clone https://github.com/semgrep/semgrep-rules.git

# Puis pointer vers le dossier local lors du scan
semgrep --config ./semgrep-rules/python/ .

Environnement airgap

Copiez le dossier semgrep-rules/ sur la machine cible et lancez les scans avec --config /chemin/vers/semgrep-rules/. Aucune connexion internet n'est nécessaire une fois les règles en local.


Premier scan

Créer des fichiers volontairement vulnerables

Pour tester Semgrep, créez deux fichiers avec des failles classiques.

vulnerable.py — injection SQL :

import sqlite3

def get_user(user_id):
    conn = sqlite3.connect("app.db")
    cursor = conn.cursor()
    # DANGER : injection SQL
    cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
    return cursor.fetchone()

vulnerable.js — Cross-Site Scripting (XSS) :

function displayMessage(userInput) {
    // DANGER : XSS
    document.getElementById("output").innerHTML = userInput;
}

Lancer le scan

semgrep --config /chemin/vers/semgrep-rules/ .

Ou avec les règles en ligne :

semgrep --config "p/owasp-top-ten" .

Lire le rapport

Semgrep affiche pour chaque détection :

Élément Description
Rule ID Identifiant unique de la règle déclenchée (ex: python.lang.security.audit.sqli)
Severity Niveau de gravite : ERROR, WARNING, INFO
File:line Fichier et numéro de ligne concernes
Message Explication de la faille détectée
CWE Lien vers la faiblesse cataloguee (ex: CWE-89 pour l'injection SQL)

Code corrige

Python — requête parametree :

import sqlite3

def get_user(user_id):
    conn = sqlite3.connect("app.db")
    cursor = conn.cursor()
    # SECURISE : requete parametree
    cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
    return cursor.fetchone()

JavaScript — textContent au lieu de innerHTML :

function displayMessage(userInput) {
    // SECURISE : textContent echappe automatiquement le HTML
    document.getElementById("output").textContent = userInput;
}

Faux positifs

Comment les identifier

Un faux positif est une alerte qui ne correspond pas a une vraie faille exploitable. Cas courants :

  • Sanitisation en amont — l'entree utilisateur est déjà validee/echappee avant d'atteindre le code signale
  • Contexte non exploitable — le code flagge n'est jamais expose a des données utilisateur
  • Code de test — les fixtures de test contiennent volontairement des patterns dangereux

Suppression inline

Ajoutez un commentaire nosemgrep avec une justification :

# nosemgrep: python.lang.security.audit.sqli -- user_id est un entier valide par le schema
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")

Fichier .semgrepignore

Excluez les dossiers qui génèrent du bruit sans valeur :

node_modules/
tests/fixtures/
migrations/
*.min.js
vendor/

Ne jamais ignorer sans comprendre

Chaque suppression de finding doit être justifiee. Un nosemgrep sans commentaire est un signal d'alerte pour les reviewers. Si vous ne comprenez pas pourquoi Semgrep signale un pattern, investigez avant de le supprimer.


Règles custom

Anatomie d'une règle YAML

rules:
  - id: no-eval-python
    patterns:
      - pattern: eval(...)
    message: "eval() est dangereux  utiliser ast.literal_eval() pour les cas legitimes"
    severity: ERROR
    languages: [python]
    metadata:
      cwe: ["CWE-95"]

Chaque règle contient :

  • id — identifiant unique
  • patterns — le(s) pattern(s) de code a détecter
  • message — l'explication affichee au développeur
  • severityERROR, WARNING ou INFO
  • languages — langages concernes
  • metadata — informations supplémentaires (CWE, références)

Tester les règles

semgrep --test --config rules/

Cas d'usage

Les règles custom permettent d'interdire des patterns spécifiques a votre projet :

  • Interdire print() en production (utiliser le logger)
  • Forcer l'utilisation d'un client HTTP interne plutôt que requests directement
  • Détecter les secrets hardcodes dans le code source
  • Imposer des patterns de gestion d'erreurs spécifiques

Comparaison SonarQube vs Semgrep

Semgrep SonarQube
Focus Sécurité Qualité + sécurité
Exécution CLI, rapide Serveur, analyse profonde
Règles YAML lisible Internes, UI
Dashboard Non Oui
Historique Non Oui
Custom rules Facile (YAML) Possible (Java)
Idéal pour CI gate rapide Vue d'ensemble projet

En pratique

Les deux outils ne sont pas en compétition. Utilisez Semgrep comme gate rapide dans votre CI (quelques secondes) et SonarQube pour le suivi long terme de la qualité et de la dette technique.