Prevenire le vulnerabilità di sicurezza è più facile che correggerle. Una falla di SQL injection individuata durante una revisione del codice richiede solo pochi minuti per essere corretta. La stessa falla, scoperta dopo una violazione, richiede settimane di intervento, indagini normative e interventi correttivi, oltre al costo dei dati eventualmente sottratti nel frattempo. L'analisi statica del codice è la disciplina che permette di individuare questi problemi prima dell'esecuzione del codice, esaminando la struttura del codice sorgente, il flusso di dati e i pattern rispetto a firme di vulnerabilità note. Applicata in modo sistematico, trasforma la sicurezza da una pratica reattiva in una caratteristica intrinseca del processo di sviluppo.
La OWASP Top 10 è il catalogo autorevole dei rischi più critici per la sicurezza delle applicazioni web, aggiornato dall'Open Web Application Security Project sulla base di dati reali sulle vulnerabilità riscontrate in migliaia di applicazioni. Ogni elemento della lista è rilevabile, in misura variabile, dagli strumenti di analisi statica. Questa guida associa ciascuna categoria OWASP a ciò che l'analisi statica può individuare, mostra il modello di codice vulnerabile e il suo equivalente sicuro e spiega quali strumenti applicano ciascuna tecnica.
Trova l'iniezione prima che lo facciano gli aggressori
SMART TS XL Traccia le vulnerabilità dalle API JavaScript, attraverso i servizi Java, fino ai backend COBOL.
Maggiori InformazioniChe cos'è il test statico di sicurezza delle applicazioni (SAST)?
Il test statico di sicurezza delle applicazioni (SAST) analizza il codice sorgente, il bytecode o il binario senza eseguire il programma. L'analisi esamina il flusso dei dati all'interno dell'applicazione, le operazioni sensibili alla sicurezza che tali dati raggiungono e se un qualsiasi percorso da un input esterno (input dell'utente, parametri HTTP, contenuto di file, variabili d'ambiente) conduca a un'operazione pericolosa (query di database, comando di sistema, output HTML, funzione crittografica) senza un'adeguata validazione o sanificazione.
SAST rappresenta un livello all'interno di un programma completo di sicurezza delle applicazioni. Per comprenderne il ruolo, è necessario confrontarlo con le alternative:
| Approccio | Quando funziona | Cosa scopre | Cosa manca |
|---|---|---|---|
| SAST (statico) | Prima dell'esecuzione, sul codice sorgente | Vulnerabilità a livello di codice, schemi di iniezione, uso improprio della crittografia, segreti hardcoded | Vulnerabilità che si verificano solo in fase di esecuzione, problemi di configurazione durante la distribuzione |
| DAST (Dinamico) | Contro un'applicazione in esecuzione | Comportamento in fase di esecuzione, vulnerabilità di autenticazione, problemi di configurazione del server | Pattern a livello di codice non attivati durante i test |
| SCA (Analisi della composizione del software) | Sui manifesti di dipendenza | Vulnerabilità CVE note nelle librerie di terze parti | Vulnerabilità del codice personalizzato |
| IAST (Interattivo) | Durante l'esecuzione del test con la strumentazione | Flussi di dati in fase di esecuzione con elevata precisione | Richiede l'esecuzione dell'applicazione, feedback più lento |
SAST fornisce un feedback tempestivo, in quanto viene eseguito su codice non ancora distribuito, nella pipeline CI/CD o persino nell'IDE, prima ancora che la vulnerabilità raggiunga un ambiente di test. Questa tempestività rappresenta il suo principale vantaggio in termini di sicurezza.
Quali tipi di minacce può essere mitigato dall'analisi statica del codice?
Questa è una delle domande più ricercate su SAST. La risposta diretta:
L'analisi statica del codice può mitigare le minacce che si manifestano nei modelli del codice sorgente : vulnerabilità di injection (SQL, command, XSS), uso improprio della crittografia, credenziali hardcoded, implementazioni di autenticazione non sicure, controlli di accesso difettosi nella logica del codice e falle nell'integrità dei dati. Non può mitigare le minacce che derivano dalla configurazione in fase di esecuzione, dalla topologia di rete o dalla configurazione dell'infrastruttura; queste richiedono DAST, penetration testing o scansioni di sicurezza dell'infrastruttura.
Analisi statica vs. analisi dinamica per la copertura OWASP
L'analisi dinamica (DAST) e l'analisi statica (SAST) individuano sottoinsiemi diversi di vulnerabilità OWASP. Nessuna delle due copre l'intero spettro delle vulnerabilità. La OWASP Web Security Testing Guide (WSTG) è il framework metodologico per i test dinamici; gli strumenti SAST come CodeQL, Semgrep e SonarQube si concentrano sul codice sorgente.
| Categoria Top 10 di OWASP | Copertura SAST | Copertura DAST |
|---|---|---|
| Controllo degli accessi interrotti | Lacune logiche nel codice parziali | Buono, test del comportamento in fase di esecuzione |
| Errori crittografici | Rilevamento algoritmico robusto | Debole, difficile da osservare dall'esterno |
| Iniezione | Analisi forte e incisiva | Test del carico utile rigorosi e attivi |
| Design insicuro | Rilevamento parziale di modelli | Debole, richiede conoscenze di progettazione |
| Configurazione errata della sicurezza | Parziale, configurazione nel codice | Test rigorosi in ambiente reale |
| Componenti vulnerabili | Debole, SCA è meglio | Debole, SCA è meglio |
| Errori di autenticazione | Credenziali parziali e codificate in modo rigido, schemi deboli | Test rigorosi di sessione e autenticazione |
| Errori di integrità dei dati | Modelli di deserializzazione parziali | Debole, difficile da rilevare dall'esterno |
| Errori di registrazione | Dichiarazioni di log parziali o mancanti | Assenza debole e difficile da osservare |
| SSRF | Forte, contaminazione della chiamata HTTP | Test di richiesta forte e attivo |
In conclusione: SAST e DAST sono complementari. Per una copertura OWASP ottimale, è consigliabile eseguirli entrambi. Per i team con budget limitato che partono da zero, è preferibile iniziare con SAST, in quanto offre il feedback più rapido da parte degli sviluppatori e la copertura di iniezione più ampia.
OWASP Top 10: Cosa rileva l'analisi statica e come
A01, Controllo accessi non funzionante
La mancanza di un adeguato controllo degli accessi è il principale rischio OWASP. L'analisi statica si concentra sulle manifestazioni a livello di codice: controlli di autorizzazione mancanti su funzioni ed endpoint, riferimenti a oggetti che espongono ID interni senza convalida e assegnazioni di ruoli hardcoded che aggirano le strutture di autorizzazione previste.
Cosa rileva l'analisi statica: Metodi che gestiscono operazioni sensibili senza un corrispondente controllo di autorizzazione; riferimenti diretti agli oggetti in cui l'ID dell'oggetto proviene dall'input dell'utente senza convalida dell'accesso; schemi di navigazione forzata in cui viene verificato lo stato di autenticazione ma non la proprietà dell'oggetto.
Giava
// Vulnerable: no ownership check -- any authenticated user can access any order
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
return orderRepository.findById(orderId).orElseThrow();
}
// Secure: verify the order belongs to the requesting user
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId,
@AuthenticationPrincipal UserDetails user) {
Order order = orderRepository.findById(orderId).orElseThrow();
if (!order.getOwnerId().equals(user.getUserId())) {
throw new AccessDeniedException("Order does not belong to requesting user");
}
return order;
}
Cosa non può rilevare l'analisi statica: errori di controllo degli accessi in fase di esecuzione, in cui la logica è corretta ma i dati utilizzati per prendere la decisione sono compromessi. Per questi casi sono necessari DAST e penetration testing.
A02, Guasti crittografici
Le vulnerabilità crittografiche sono rilevabili in modo affidabile tramite analisi statica, poiché gli schemi vulnerabili, come MD5, SHA-1, DES, modalità ECB e chiavi hardcoded, sono identificabili lessicalmente nel codice sorgente.
python
# Vulnerable: MD5 for password hashing (broken algorithm)
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()
# Vulnerable: hardcoded encryption key
KEY = b"mysecretkey12345"
cipher = AES.new(KEY, AES.MODE_ECB) # ECB mode also vulnerable
# Secure: bcrypt for passwords, environment-sourced keys
import bcrypt, os
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
# Secure: AES-GCM with environment-sourced key
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = os.environ["ENCRYPTION_KEY"].encode()
aesgcm = AESGCM(key)
Regole di analisi statica flag: MD5/SHA-1 per scopi sensibili alla sicurezza, modalità DES/3DES/RC4/ECB, chiavi crittografiche e segreti hardcoded, HTTP invece di HTTPS per la trasmissione di dati sensibili e verifica del certificato disabilitata (verify=False nelle richieste Python, setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER) (in Java).
A03, Iniezione
Iniezione, SQL, comandi del sistema operativo, LDAP, XSS, iniezione di template: questa è la categoria in cui l'analisi della contaminazione interprocedurale fornisce il suo valore più diretto. La vulnerabilità richiede il tracciamento di input non attendibili dalla loro origine, attraverso le chiamate di funzione, fino a un punto di destinazione pericoloso.
javascript
// Vulnerable: direct string interpolation in SQL (SQL injection)
app.get('/users', async (req, res) => {
const name = req.query.name;
const result = await db.query(`SELECT * FROM users WHERE name = '${name}'`);
res.json(result.rows);
});
// Secure: parameterized query
app.get('/users', async (req, res) => {
const name = req.query.name;
const result = await db.query('SELECT * FROM users WHERE name = $1', [name]);
res.json(result.rows);
});
php
// Vulnerable: unescaped output (XSS)
echo "Welcome, " . $_GET['username'];
// Secure: context-appropriate escaping
echo "Welcome, " . htmlspecialchars($_GET['username'], ENT_QUOTES, 'UTF-8');
nitido
// Vulnerable: command injection in C#
var process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c " + userInput;
process.Start();
// Secure: avoid shell interpretation, validate and whitelist inputs
var allowedCommands = new HashSet<string> { "report", "export" };
if (!allowedCommands.Contains(userInput))
throw new ArgumentException("Invalid command");
Strumenti che eseguono l'analisi di contaminazione interprocedurale per l'iniezione: CodeQL (il più preciso), Semgrep con modalità di contaminazione, Snyk Code, SonarQube con regole di sicurezza.
A04, Progettazione non sicura
La progettazione insicura è la categoria OWASP più difficile da analizzare staticamente perché riguarda decisioni architetturali piuttosto che modelli di codice. L'analisi statica può segnalare i seguenti sintomi:
Logica di limitazione della frequenza mancante sugli endpoint di autenticazione, assenza di blocco dell'account dopo tentativi falliti, logica aziendale che salta le fasi di validazione e funzioni che eseguono operazioni privilegiate senza registrazione degli eventi di controllo. Questi problemi sono rilevabili come pattern mancanti, un'analisi statica che segnala ciò che manca anziché ciò che è presente.
Alcuni strumenti SAST supportano regole personalizzate che possono codificare i requisiti di progettazione della sicurezza organizzativa: ogni metodo del controller deve chiamare una funzione di autorizzazione, ogni scrittura nel database deve essere preceduta dalla convalida dell'input, ogni chiamata API esterna deve utilizzare un timeout. Queste regole personalizzate convertono i requisiti di progettazione in vincoli di codice applicabili.
A05, Errata configurazione della sicurezza
Le configurazioni di sicurezza errate nel codice includono: funzionalità di sicurezza disabilitate, intestazioni CORS permissive, intestazioni di risposta di sicurezza mancanti, modalità di debug abilitata in produzione e messaggi di errore dettagliati che espongono le tracce dello stack.
python
# Vulnerable: Flask debug mode enables interactive debugger in production
app = Flask(__name__)
app.run(debug=True) # exposes console access if error occurs
# Vulnerable: overly permissive CORS
from flask_cors import CORS
CORS(app, origins="*") # allows any origin
# Secure: environment-controlled debug, restricted CORS
import os
debug_mode = os.environ.get("FLASK_DEBUG", "false").lower() == "true"
CORS(app, origins=os.environ.get("ALLOWED_ORIGINS", "").split(","))
app.run(debug=debug_mode)
Flag delle regole di analisi statica: modalità di debug impostata su True nel codice sorgente, origini CORS jolly, intestazioni di sicurezza mancanti nelle configurazioni di risposta HTTP, verifica del certificato SSL disabilitata e credenziali predefinite nei file di configurazione.
A06, Componenti vulnerabili e obsoleti
Questa categoria viene affrontata principalmente dall'analisi della composizione del software (SCA) piuttosto che dal tradizionale SAST. Scansioni SCA package.json, pom.xml, requirements.txte manifestazioni simili contro i database delle vulnerabilità (National Vulnerability Database, GitHub Advisory Database).
SAST contribuisce identificando l'utilizzo di API obsolete, le chiamate a funzioni di libreria che sono state superate a causa di falle di sicurezza o l'uso diretto di modelli vulnerabili che persino le librerie più aggiornate non raccomandano più.
Strumenti specifici per A06: npm audit, pip-audit, snyk test, OWASP Dependency-Check, GitHub Dependabot e Mend (precedentemente WhiteSource).
A07, Errori di identificazione e autenticazione
L'analisi statica rileva gli anti-pattern di autenticazione a livello di codice: password hardcoded, convalida debole delle password, token di sessione generati con casualità non crittografica, invalidazione della sessione mancante al logout e implementazioni JWT che accettano il none algoritmo.
javascript
// Vulnerable: JWT accepting 'none' algorithm -- allows signature bypass
const decoded = jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });
// Vulnerable: hardcoded admin credentials
if (username === 'admin' && password === 'admin123') {
grantAccess();
}
// Secure: algorithm whitelist, no hardcoded credentials
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'] // explicit allowlist only
});
nitido
// Vulnerable: weak random for session token generation in C#
var sessionToken = new Random().Next().ToString();
// Secure: cryptographically secure random
using var rng = RandomNumberGenerator.Create();
var bytes = new byte[32];
rng.GetBytes(bytes);
var sessionToken = Convert.ToBase64String(bytes);
A08, Guasti relativi all'integrità del software e dei dati
Questa categoria comprende la deserializzazione non sicura e gli aggiornamenti software non verificati. L'analisi statica rileva: Java ObjectInputStream Deserializzazione dei dati da fonti non attendibili, Python pickle.loads() sui dati esterni, PHP unserialize() con input controllato dall'utente e parser YAML che utilizzano caricatori non sicuri.
python
# Vulnerable: pickle deserialization of untrusted data
import pickle
data = pickle.loads(request.data) # arbitrary code execution risk
# Vulnerable: unsafe YAML loader
import yaml
config = yaml.load(user_input) # yaml.load without Loader is unsafe
# Secure: safe alternatives
import json
data = json.loads(request.data) # JSON cannot execute code
import yaml
config = yaml.safe_load(user_input) # safe_load disables arbitrary object creation
A09, Errori di registrazione e monitoraggio della sicurezza
I malfunzionamenti nella registrazione degli eventi sono rilevabili tramite analisi statica come pattern assenti: operazioni sensibili, eventi di autenticazione, decisioni di controllo degli accessi, modifiche dei dati, che vengono eseguite senza le relative istruzioni di log. Le regole di analisi statica possono richiedere che determinate chiamate di funzione si verifichino sempre in concomitanza con le chiamate al log di audit.
Cosa segnala l'analisi statica: la registrazione di password o token (anche la registrazione di dati sensibili costituisce una vulnerabilità), i gestori di eccezioni che ignorano silenziosamente gli errori senza registrarli e i blocchi catch che registrano il messaggio di eccezione non elaborato (che potrebbe contenere dati sensibili).
Giava
// Vulnerable: swallowed exception, no logging
try {
authenticateUser(username, password);
} catch (Exception e) {
// silent failure -- no log, no audit trail
}
// Vulnerable: logging sensitive data
log.info("User logged in with password: " + password);
// Secure: log the event, not the credential
try {
authenticateUser(username, password);
auditLog.info("Authentication success for user: {}", username);
} catch (AuthenticationException e) {
auditLog.warn("Authentication failure for user: {}", username);
throw e; // do not swallow
}
A10, Falsificazione di richieste lato server (SSRF)
La vulnerabilità SSRF rappresenta un valido caso di analisi delle tracce interprocedurali. La vulnerabilità richiede il tracciamento dell'input controllato dall'utente fino alla richiesta HTTP, spesso attraverso molteplici chiamate di funzione. Uno strumento che analizza solo le singole funzioni non è in grado di rilevare la vulnerabilità SSRF quando la costruzione dell'URL e la chiamata HTTP avvengono in funzioni diverse.
python
# Vulnerable: user-controlled URL in HTTP request (SSRF)
import requests
def fetch_resource(url):
return requests.get(url).content # no validation
def api_endpoint(request):
target = request.json().get("url") # attacker controls this
return fetch_resource(target) # SSRF across function boundary
# Secure: allowlist validation before making the request
from urllib.parse import urlparse
ALLOWED_HOSTS = {"api.internal.example.com", "cdn.example.com"}
def fetch_resource(url: str) -> bytes:
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_HOSTS:
raise ValueError(f"URL host not allowed: {parsed.hostname}")
return requests.get(url, timeout=5).content
Strumenti di analisi statica del codice per la sicurezza OWASP
La tabella seguente associa i principali strumenti SAST alle categorie OWASP a cui rispondono in modo più efficace:
| Chiavetta | Lingue principali | Punti di forza di OWASP | Approccio |
|---|---|---|---|
| CodiceQL | Java, JS/TS, Python, C/C++, Go, Ruby | Iniezione A03, A10 SSRF (contaminazione profonda) | Analisi semantica interprocedurale |
| Segrep | 30+ lingue | A03, A02, A07 (modalità basata su modelli + modalità di contaminazione) | Corrispondenza di modelli + contaminazione superficiale |
| Codice Snyk | Java, JS/TS, Python, C# | A03, A07, A08 | Analisi della contaminazione basata sull'apprendimento automatico |
| soundQube | 30+ lingue | A02, A03, A05, A07, A09 | Basato su regole + flusso di dati |
| Check Marx | 30+ lingue | Copertura completa di OWASP | Contaminazione interprocedurale |
| VeraCode | Java, .NET, JS, PHP | Copertura completa di OWASP | Analisi del bytecode e della contaminazione |
| OWASP ZAP | Indipendente dalla lingua | A01, A05, A07 (tempo di esecuzione) | DAST, test dinamico |
| SMART TS XL | COBOL, JCL, Java, Python, RPG, SQL | Contaminazione interlinguistica, rischio di dipendenza | Struttura interlinguistica + contaminazione |
Come SMART TS XL Affronta la sicurezza nei codebase aziendali
I programmi di sicurezza aziendale si trovano ad affrontare una sfida che gli strumenti SAST monolingue non sono in grado di risolvere: la superficie di attacco si estende su più linguaggi. Un'applicazione web può accettare input dall'utente in JavaScript, elaborarli in Java e passarli attraverso una coda di messaggi a un programma COBOL che esegue query SQL su un database DB2. La vulnerabilità di injection esiste attraverso quattro linguaggi diversi. Nessuno scanner per un singolo linguaggio è in grado di individuare l'intero percorso di contaminazione.
SMART TS XL'S analisi statica del codice copre simultaneamente ogni linguaggio in questa catena. Quando l'input non attendibile fluisce da un gestore API JavaScript attraverso un servizio Java in un programma COBOL che costruisce una query SQL dinamica, SMART TS XL traccia quel percorso attraverso l'intero grafo delle chiamate tra linguaggi diversi, lo stesso tracciamento delle tracce interprocedurali che CodeQL applica in Java, applicato a Java, COBOL e SQL insieme.
La funzionalità di mappatura delle dipendenze dell'applicazione fornisce una visione rilevante per la sicurezza di quali componenti del sistema interagiscono con input esterni, quali accedono a operazioni privilegiate e qual è l'effettiva superficie di attacco completa del sistema. Questa visione architetturale della sicurezza è il fondamento per la modellazione delle minacce: non è possibile modellare le minacce contro un sistema di cui non si comprende la struttura.
La funzionalità di analisi dell'impatto è fondamentale per i programmi di correzione della sicurezza: quando viene rilevata una vulnerabilità in un componente, l'analisi dell'impatto identifica tutti gli altri componenti che dipendono da quello vulnerabile, definendo con precisione l'ambito dell'intervento di correzione prima di apportare qualsiasi modifica al codice. Per grandi codebase legacy in cui un programma COBOL con una falla di sicurezza è incluso da centinaia di altri programmi, conoscere l'intera portata dell'intervento di correzione prima di iniziare fa la differenza tra una correzione gestita e un incidente a cascata.
Per le organizzazioni che gestiscono modernizzazione dell'eredità Nei programmi, l'analisi della sicurezza del codice sorgente preesistente è un prerequisito, non un ripensamento. La migrazione di programmi COBOL vulnerabili a Java produce programmi Java vulnerabili. SMART TS XLL'analisi di sicurezza garantisce che le vulnerabilità vengano identificate e risolte nell'ambito del processo di modernizzazione, e non scoperte nel sistema migrato.
Integrazione di SAST nel ciclo di vita dello sviluppo
L'analisi statica della sicurezza offre il massimo valore quando viene eseguita nel momento decisionale, ovvero durante la fase di scrittura e revisione del codice, e non dopo la sua implementazione.
Nell'IDE: SonarLint, le estensioni IDE di Snyk e l'estensione CodeQL per VS Code evidenziano le vulnerabilità direttamente nel codice mentre gli sviluppatori lo scrivono. Un flag di SQL injection che appare nel momento in cui uno sviluppatore digita il pattern vulnerabile richiede solo pochi secondi per essere corretto.
Nelle pull request: SAST, integrato in GitHub Actions, GitLab CI o Jenkins, viene eseguito su ogni pull request e pubblica i risultati come commenti di revisione del codice inline. Lo sviluppatore visualizza il risultato nel suo contesto, insieme al codice che lo ha generato.
Come controllo di qualità: il modello di controllo di qualità di SonarQube blocca le fusioni quando vengono introdotti nuovi punti critici di sicurezza. Questo fa sì che la sicurezza non sia una fase di revisione facoltativa, ma un requisito strutturale del processo di fusione.
A cadenza programmata: l'analisi interprocedurale approfondita, CodeQL, Checkmarx, set completi di regole Semgrep, è in genere troppo lenta per l'esecuzione a ogni commit, ma viene eseguita ogni notte o settimanalmente sul ramo principale, individuando vulnerabilità che richiedono un'analisi completa del grafo delle chiamate per essere rilevate.
L'approccio a livelli, le regole rapide basate su modelli nell'IDE e sui commit, l'analisi approfondita delle vulnerabilità sulle pull request e negli aggiornamenti notturni, offrono sia l'immediatezza di cui gli sviluppatori hanno bisogno, sia la completezza richiesta dai programmi di sicurezza.