OWASP Top 10 — Vulnérabilités critiques applicatives
Résumé des 10 catégories de vulnérabilités web les plus dangereuses (OWASP 2021) avec les patterns de prévention spécifiques à Java / Spring Boot.
Tableau résumé
| # | Vulnérabilité | Gravité | Pattern de prévention principal |
|---|---|---|---|
| B1 | Injection SQL | Critique | PreparedStatement + bind parameters ; éviter la concaténation de chaînes |
| B2 | Défaillance de contrôle d’accès | Critique | SpEL avec @PreAuthorize ; règles ACL explicites |
| B3 | Injection de code (XSS, SPI) | Critique | HtmlUtils.htmlEscape() ; validation stricte des entrées |
| B4 | Désérialisation sécuritaire | Critique | Désactiver jdk.serialization ; utiliser JsonTypeInfo avec types autorisés |
| B5 | Vulnérabilité de configuration | Haute | Binding rigoureux (@ConfigurationProperties) ; SEC-2024-4 |
| B6 | Identification et authentification défaillantes | Haute | Spring Security + @PreAuthorize ; MFA pour les actions sensibles |
| B7 | Faille dans les composants | Haute | Audit mvn dependency:analyze ; jeunes versions de librairies |
| B8 | Expositions de données sensibles | Haute | Chiffrement AES-256 au repos ; masquage en logique métier |
| B9 | Journalisation et surveillance insuffisante | Moyenne | Logging contextualisé ; détection de patterns d’attaque |
| B10 | Intégrité du code manquante | Moyenne | Signature de binaires ; pipeline CI/CD avec vérification de provenance |
Remarque : Pour la configuration HTTPS et les headers de sécurité (CSP, CORS, HSTS), voir Headers HTTP sécurisés.
B1 — Injection SQL
Le problème
Un attaquant insère du code SQL arbitraire via un paramètre utilisateur.
Pattern Spring Boot
// ❌ MAUVAIS CONTRÔLEUR
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Requête brute — vulnérable si pas de bind paramètre
@Query("SELECT u FROM User u WHERE u.email = :email AND u.status = :status")
List<User> findByEmailAndStatus(@Param("email") String email,
@Param("status") String status);
}
// ✅ TOUT PASSER PAR DES BIND PARAMETERS
@RestController
public class UserController {
@GetMapping("/users/search")
public List<User> search(@RequestParam String email,
@RequestParam String status) {
return userRepository.findByEmailAndStatus(email, status);
}
}Règles
- Toujours utiliser
@Paramavec@Query— jamais de+pour concaténer des chaînes dans une requête JPQL/native. - Privilégier les méthodes Spring Data
findBy...quand possible. - Pour les requêtes natives, utiliser
entityManager.createNativeQuery(...)avec des paramètres positionnels.
B2 — Contrôle d’accès défaillant
Le problème
Un utilisateur accède à des ressources ou des fonctions sans autorisation.
Pattern Spring Security
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll()
)
.csrf(csrf -> csrf.disable()); // À réactiver pour les formulaires
return http.build();
}
}
@Service
public class OrderService {
@PreAuthorize("#userId == authentication.principal.id")
public Order getOrder(Long orderId, Long userId) {
// L'utilisateur ne peut lire que SES propres commandes
return orderRepository.findById(orderId)
.orElseThrow(() -> new NotFoundException("Commande introuvable"));
}
}B3 — Injection de code
Le problème
Exécution de code arbitraire via l’injection de scripts (XSS) ou de classes Java (SPI).
Pattern de prévention XSS
import org.springframework.util.HtmlUtils;
@RestController
public class CommentController {
@PostMapping("/comments")
public String createComment(@RequestBody String rawComment) {
// Échappement HTML systématique
String safeComment = HtmlUtils.htmlEscape(rawComment);
return commentRepository.save(safeComment).toString();
}
}Règles
- Utiliser
HtmlUtils.htmlEscape()pour échapper toutes les entrées affichées dans une réponse HTML. - Ne jamais accepter de HTML brut dans les champs texte.
B4 — Désérialisation sécuritaire
Le problème
Désérialisation de données malveillantes entraînant RCE, DoS ou élévation de privilèges.
Pattern Spring Boot
@RestController
@RequestMapping("/api/data")
public class DataService {
// ✅ Utiliser Jackson avec un type explicite et validation stricte
@PostMapping("/import")
public Result importData(@RequestBody MySafeDto payload) {
return service.process(payload);
}
// ❌ Jamais de readValue(Object.class) ou de Map non typé
// avec une entrée utilisateur brute.
}Règles
- Éviter
ObjectMapper.readValue(input, Object.class)sur une entrée utilisateur. - Privilégier les DTO typés pour le binding JSON.
- Si
jdk.serializationest nécessaire, utiliser une whitelist de classes autorisées.
B5 — Vulnérabilité de configuration
Le problème
Mauvaise configuration exposant l’application à des attaques (ex. SEC-2024-4 : @ConfigurationProperties avec liaison laxiste).
Pattern de prévention
// ❌ Bind laxiste — des champs non attendus sont ignorés silencieusement
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
// Si le JSON contient "unknownField", il est ignoré sans avertissement
}
// ✅ Bind strict — toute propriété inattendue provoque une erreur
@ConfigurationProperties(prefix = "app")
@Data
public class StrictAppProperties {
private String name;
@PostConstruct
public void validate() {
if (name == null || name.isBlank()) {
throw new IllegalStateException("app.name est requis");
}
}
}Règles
- Activer
spring.config.importpour charger les configurations de manière explicite. - Vérifier les versions de Spring Security contre les CVE connues (SEC-2024-4, etc.).
B6 — Identification et authentification défaillantes
Le problème
Vol de mots de passe, de tokens, ou abuse de mécanismes de récupération.
Pattern Spring Security
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.failureUrl("/login?error=true")
)
.sessionManagement(session -> session
.maximumSessions(1) // Une session par utilisateur
);
return http.build();
}
}Règles
- Exiger une authentification forte pour les actions sensibles (changement de mot de passe, accès admin).
- Configurer
maximumSessions(1)pour empêcher le partage de sessions. - Imposer des politiques de mots de passe robustes côté serveur.
B7 — Vulnérabilités dans les composants
Le problème
Utilisation de bibliothèques tierces connues pour être vulnérables.
Audit avec Maven
# Vérifier les dépendances obsolètes ou vulnérables
mvn dependency:analyze
# Liste des dépendances avec versions connues vulnérables
mvn org.owasp:dependency-check-maven:checkRègles
- Maintenir les versions de librairies à jour (surtout
spring-boot-starter-security,jackson,log4j). - Intégrer un scan de vulnérabilités dans le pipeline CI/CD (
mvn org.owasp:dependency-check-maven:check). - Ne jamais ignorer un CVE sans justification documentée.
B8 — Expositions de données sensibles
Le problème
Exposition de données de santé, financières ou d’identification dans les logs, les réponses API, ou les erreurs.
Pattern de masquage
@Service
public class UserService {
public UserDto getUser(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Utilisateur introuvable"));
// Masquer les données sensibles avant le retour
return new UserDto(
user.getId(),
user.getEmail(),
maskPhone(user.getPhone()),
null // passwordHash — jamais dans la réponse
);
}
private String maskPhone(String phone) {
if (phone == null) return null;
return phone.replaceAll("(?<=....).*", "****");
}
}Règles
- Ne jamais logger de PII (données personnelles).
- Chiffrer les données sensibles au repos (AES-256).
- Masquer systématiquement les champs sensibles dans les DTO.
B9 — Journalisation et surveillance insuffisante
Le problème
Absence de visibilité sur les attaques en cours ou passées.
Pattern Spring Boot
@RestController
public class ApiController {
private static final Logger log = LoggerFactory.getLogger(ApiController.class);
@PostMapping("/api/transfer")
public Result transfer(@RequestBody TransferRequest req) {
log.info("Transfert initié : from={}, to={}, amount={}",
req.getFrom(), req.getTo(), req.getAmount());
try {
service.transfer(req);
log.info("Transfert effectué avec succès");
return Result.success();
} catch (Exception e) {
log.error("Échec du transfert : {}, cause={}", req, e.getMessage());
return Result.error("Échec du transfert");
}
}
}Règles
- Logger les événements de sécurité (échecs d’authentification, modifications d’autorisation).
- Ne jamais logger de secrets ou de données sensibles.
- Structurer les logs (JSON) pour faciliter le parsing par des SIEM.
B10 — Intégrité du code manquante
Le problème
Code non vérifié pouvant introduire des vulnérabilités ou du code malveillant.
Règles
- Signer les binaires produits en production.
- Utiliser un pipeline CI/CD avec vérification de provenance (cosign, in-toto).
- Auditer les imports Maven avant d’ajouter une dépendance.
Checklist de sécurité applicative
- Toutes les requêtes utilisent des bind parameters (B1)
- Les contrôleurs appliquent
@PreAuthorizesur les méthodes sensibles (B2) - Les entrées utilisateur sont échappées avec
HtmlUtils.htmlEscape()(B3) - Aucun
readValue(Object.class)sur une entrée brute (B4) - Les
@ConfigurationPropertiessont validés correctement (B5) - L’authentification est renforcée pour les actions critiques (B6)
- Les dépendances sont auditées automatiquement en CI (B7)
- Les données sensibles sont masquées dans les DTO (B8)
- Les événements de sécurité sont loggés (B9)
- Le code est signé et vérifié en production (B10)
Pages associées
- Authentification API — Tokens JWT, OAuth2, sessions
- Headers HTTP sécurisés — CSP, CORS, HSTS
- Gestion des secrets — Rotation, chiffrement
- CLI Security — Génération de secrets en ligne de commande