SpringSentinel

Spring Boot ha rivoluzionato il modo in cui sviluppiamo applicazioni in Java: autoconfigurazione, starter pack e un ecosistema sterminato ci permettono di andare in produzione in tempi record. Ma questa velocità ha un prezzo: è incredibilmente facile introdurre anti-pattern di performance, esporre informazioni riservate o creare colli di bottiglia nel database senza accorgersene.

È qui che entra in gioco Spring Sentinel, un plugin Maven open source progettato specificamente per l’ecosistema Spring. A differenza dei linter generici, Sentinel “comprende” le annotazioni di Spring e Hibernate, bloccando i problemi prima ancora che raggiungano la tua pipeline CI/CD.

Di seguito il repository github: https://github.com/pagano-antonio/SpringSentinel

In questa guida esploreremo come configurare e sfruttare al massimo tutte le funzionalità di Spring Sentinel, dall’installazione base fino alla governance enterprise.

1. Installazione e Primo Avvio

Integrare Spring Sentinel nel proprio progetto è semplicissimo. Basta aggiungere il plugin al file pom.xml. Di default, il plugin si aggancia alla fase verify di Maven.

<plugin>

     <groupId>io.github.pagano-antonio</groupId>

    <artifactId>SpringSentinel</artifactId>

    <version>1.1.12</version>

    <executions>

        <execution>

            <phase>verify</phase> 

            <goals>

                <goal>audit</goal>

            </goals>

        </execution>

    </executions>

    <configuration>

        <profile>strict</profile> 

        <maxDependencies>7</maxDependencies> 

        <secretPattern>.*(password|secret|apikey|token).*</secretPattern> 

    </configuration>

</plugin>

Una volta installato, ci sono due modi per lanciare SpringSentinel, a seconda delle proprie necessità:

Modo 1: Il controllo rapido in locale (Esecuzione Diretta) Se stai scrivendo codice e vuoi fare una scansione istantanea senza dover lanciare test o compilare l’intero progetto, usa il comando diretto del plugin:

mvn spring-sentinel:audit

Modo 2: Il controllo globale (Lifecycle Maven) Per eseguire l’intero ciclo di vita del progetto (compilazione, test, pacchettizzazione) e includere l’analisi statica alla fine (es. per una pipeline CI/CD), bisogna lanciare la build completa:

mvn clean verify

Dato che è agganciato alla fase verify nel pom.xml, Maven eseguirà l’audit in automatico poco prima di concludere la build.

In entrambi i casi, se il codice contiene violazioni, Sentinel interromperà la build, se configurato, e genererà due tipi report nella cartella target/spring-sentinel-reports

report.html Una dashboard chiara e intuitiva per identificare rapidamente i problemi.

report.json: Dati strutturati progettati per pipeline CI/CD, analisi automatizzate o dashboard personalizzate.

2. Il "Build Breaker" (Secure by Default)

Spring Sentinel adotta un approccio Secure by Default. Se trova un errore critico (come una password in chiaro o un endpoint Actuator esposto), la build di Maven fallisce con un BUILD FAILURE. Questo lo rende un “Security Gate” perfetto per la tua CI/CD.

Se si sta introducendo il plugin in un progetto legacy con molti difetti e si vuole solo generare il report senza bloccare la compilazione, si può disattivare questa funzione nel pom.xml:

<configuration>

    <failOnError>false</failOnError>

</configuration>

3. Key Audit Checks

Quello che segue è una breve introduzione su cosa viene controllato. Per vedere tutto più dettagliatamente via nel paragrafo 9.

JPA e DB: rileva query N+1, fetching EAGER e stato OSIV.

Sicurezza delle transazioni: identifica I/O bloccanti (REST, sleep) all’interno di @Transactional.

Architettura: rileva Field Injection (@Autowired) e creazione manuale di thread.

Sicurezza: esegue la scansione per individuare segreti hardcoded (password, chiavi API).

Caching: identifica configurazioni TTL mancanti.

4. I Profili "Pronti all'Uso"

Esiste la possibilita di configurare le singole regole (l’elenco completo è nel paragrafo7). Se on hai tempo per configurare le singole regole Spring Sentinel offre tre profili predefiniti con severità crescente:

  1. security-only: Controlla solo vulnerabilità non negoziabili (segreti hardcoded, CORS permissivi, endpoint Actuator non protetti).
  2. standard (scelta consigliata): Eredita la sicurezza e aggiunge controlli su performance e architettura (es. N+1 query, chiamate bloccanti nelle transazioni, uso scorretto di Lombok).
  3. strict (default): Eredita lo standard ma impone regole ferree anche sul design delle API REST (kebab-case, versionamento) e limiti rigidi sulle dipendenze delle classi.

Nel paragrafo 9 vedi le singole regole per ogni profilo. Per cambiare profilo, usa la configurazione del POM:

<configuration>

    <profile>standard</profile>

</configuration>

in profile si specifica il profilo che si vuole usare.

4. Tuning Rapido dal POM

Se si vuoi mantenere un profilo predefinito, si possono modificare alcune proprietà direttamente dal pom.xml senza creare file esterni.

Ad esempio, per aumentare il limite di dipendenze prima che un componente venga segnalato come “Fat Component” o per personalizzare la Regex che cerca i segreti:

<configuration>

    <maxDependencies>10</maxDependencies

    <secretPattern>.*(password|secret|apikey|token|aws_key).*</secretPattern

</configuration>

5. Custom Governance e Path Filtering (Livello Enterprise)

Se si lavora in un team strutturato, spesso si ha  bisogno di adattare le regole in modo chirurgico, magari ignorando intere cartelle di codice legacy. Spring Sentinel permette di definire un file XML di configurazione personalizzato. Nel proprio pom.xml dichiara il file:

<configuration>

    <profile>my-company-profile</profile>

    <customRules>${project.basedir}/custom-sentinel-rules.xml</customRules>

</configuration>

Crea il file custom-sentinel-rules.xml nella root del progetto. Ecco un esempio di come si può includere, escludere e applicare filtri Regex sui percorsi:

<?xml version=”1.0″ encoding=”UTF-8″?>

<spring-sentinel>

    <profiles>

        <profile id=“my-company-profile” extends=“standard”>

            <name>Profilo Aziendale Custom</name>

            <exclude rule=“ARCH-002” />

            <include rule=“REST-004” />

            <override rule=“ARCH-003” param=“excludePaths” value=“.*(/legacy/|/old/).*” />

 

            <override rule=“REST-001” param=“includePaths” value=“.*/controller/.*” />

            <override rule=“ARCH-003” param=“maxDependencies” value=“12” />

        </profile>

    </profiles>

</spring-sentinel>

dove le varie regole (rule) vengono spiegati nel paragrafo 9. Questa flessibilità permette di introdurre standard di qualità gradualmente, senza paralizzare lo sviluppo.

6. Soppressione Puntuale (L'Eccezione alla Regola)

A volte una regola va infranta per validi motivi architetturali. Invece di disattivare la regola per tutto il progetto, si può usare l’annotazione standard di Java @SuppressWarnings per istruire Sentinel a ignorare un errore su una specifica classe, metodo o campo. Basta usare il prefisso sentinel: seguito dall’ID della regola:

import org.springframework.web.bind.annotation.RestController;

 

@RestController

@SuppressWarnings(“sentinel:PERF-003”) // Ignora le chiamate bloccanti qui

public class LegacyController {

 

    @Transactional

    public void faiQualcosaDiLento() {

        // Sentinel non farà fallire la build per questo RestTemplate

        restTemplate.getForObject(“http://api.vecchia.it”, String.class); 

    }

}

Puoi anche spegnere tutti i controlli su una classe disastrosa con @SuppressWarnings(“sentinel:all”).

7. Regole

Questo elenco descrive in dettaglio ogni controllo eseguito dal motore di analisi statica, gli ID delle regole associati (utilizzati per la configurazione del profilo XML) e la logica di rilevamento sottostante.

Prestazioni e database

Questi controlli si concentrano sull’ottimizzazione delle interazioni con il database e sulla prevenzione dell’esaurimento delle risorse.

PERF-001 (JPA Eager Fetching): analizza le entità JPA alla ricerca di FetchType.EAGER. Il suo scopo è prevenire il caricamento non necessario di grafi di oggetti complessi, che causa un significativo sovraccarico di memoria e un degrado delle prestazioni.

PERF-002 (Potenziale di query N+1): identifica i getter delle collezioni chiamati all’interno di cicli (for, forEach), una causa comune di problemi di prestazioni del database.

PERF-003 (Chiamate bloccanti nelle transazioni): rileva chiamate di I/O o di rete bloccanti (ad esempio, RestTemplate, Thread.sleep) all’interno dei metodi @Transactional per prevenire l’esaurimento del pool di connessioni.

PERF-004 (Configurazione TTL della cache): Verifica che i metodi annotati con @Cacheable abbiano un Time-To-Live (TTL) corrispondente definito nelle proprietà dell’applicazione per evitare dati obsoleti.

Sicurezza

Focalizzato sulla protezione dei dati sensibili e sulla garanzia di configurazioni sicure degli endpoint.

SEC-001 (Scanner di segreti hardcoded): Controlla i campi e le proprietà delle classi alla ricerca di nomi di variabili che corrispondano a pattern sensibili (ad esempio, password, apikey, token) che non utilizzano segnaposto per variabili d’ambiente.

SEC-002 (Policy CORS non sicura): Segnala l’uso del carattere jolly “*” nelle annotazioni @CrossOrigin, che rappresenta un rischio significativo per la sicurezza delle API in produzione.

SEC-003 (Repository esposti): Avvisa se spring-boot-starter-data-rest è incluso, poiché espone automaticamente i repository senza configurazioni di sicurezza esplicite.

Architettura e sicurezza dei thread

Regole per garantire che il codice segua le best practice di Spring Framework e sia sicuro per l’esecuzione multi-thread.

ARCH-001 (Sicurezza dei thread Singleton): Rileva lo stato mutabile nei bean Singleton (compatibile con Lombok).

ARCH-002 (Anti-pattern di iniezione di campo): Segnala l’uso di @Autowired sui campi privati, incoraggiando l’iniezione tramite costruttore per una migliore testabilità e immutabilità.

ARCH-003 (Rilevamento di componenti sovradimensionati): Monitora il numero di dipendenze in una singola classe. Se supera il limite configurato, suggerisce di effettuare un refactoring in servizi più piccoli e focalizzati.

ARCH-004 (Istanziazione manuale dei bean): Rileva l’uso della parola chiave new per le classi che dovrebbero essere gestite dal contesto Spring (servizi, repository, componenti).

ARCH-005 (Segnale di iniezione pigra): Identifica l’utilizzo combinato di @Lazy e @Autowired, spesso usati come soluzione alternativa per le dipendenze circolari.

RES-001 (Creazione manuale di thread): Rileva la creazione manuale di thread (new Thread()), suggerendo l’utilizzo di task @Async gestiti.

Governance delle API REST

Garantisce che le API siano coerenti, versionate e conformi ai principi standard di progettazione RESTful.

REST-001 (Applicazione della convenzione Kebab-case negli URL): Garantisce che gli URL degli endpoint seguano la convenzione kebab-case (ad esempio, /user-profiles) anziché camelCase o snake_case.

REST-002 (Verifica della versione delle API): Avvisa se a un endpoint manca un prefisso di versione (ad esempio, /v1/), essenziale per la manutenzione a lungo termine delle API.

REST-003 (Pluralizzazione delle risorse): suggerisce di utilizzare nomi al plurale per le risorse REST (ad esempio, /users invece di /user) per seguire gli standard di progettazione REST.

REST-004 (ResponseEntity mancante): incoraggia la restituzione di ResponseEntity nei Controller per gestire e comunicare correttamente i codici di stato HTTP.

Manutenzione di build e progetto

verifica lo stato generale del progetto Maven e la conformità alle versioni stabili.

MAINT-001 (Verifica della versione di Spring Boot): avvisa se il progetto utilizza ancora Spring Boot 2.x e consiglia l’aggiornamento alla versione 3.x per la compatibilità con Jakarta EE.

MAINT-002 (Plugin di produzione mancanti): verifica la presenza del plugin spring-boot-maven-plugin, necessario per la creazione di pacchetti di artefatti eseguibili.

MAINT-003 (Best practice per i repository): garantisce che le interfacce di accesso ai dati siano correttamente annotate con @Repository per una corretta traduzione delle eccezioni.

Conclusione

Spring Sentinel trasforma l’esperienza e le “best practice” della community in regole automatizzate. Che tu voglia usarlo “out-of-the-box” per una scansione di sicurezza rapida, o configurarlo meticolosamente per la governance di una grande azienda, Sentinel è lo scudo di cui la tua pipeline aveva bisogno.

Genera il tuo primo report oggi stesso e scopri cosa si nasconde nel tuo codice!