Skip to Content
SecurityOWASP Top 10

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
B1Injection SQLCritiquePreparedStatement + bind parameters ; éviter la concaténation de chaînes
B2Défaillance de contrôle d’accèsCritiqueSpEL avec @PreAuthorize ; règles ACL explicites
B3Injection de code (XSS, SPI)CritiqueHtmlUtils.htmlEscape() ; validation stricte des entrées
B4Désérialisation sécuritaireCritiqueDésactiver jdk.serialization ; utiliser JsonTypeInfo avec types autorisés
B5Vulnérabilité de configurationHauteBinding rigoureux (@ConfigurationProperties) ; SEC-2024-4
B6Identification et authentification défaillantesHauteSpring Security + @PreAuthorize ; MFA pour les actions sensibles
B7Faille dans les composantsHauteAudit mvn dependency:analyze ; jeunes versions de librairies
B8Expositions de données sensiblesHauteChiffrement AES-256 au repos ; masquage en logique métier
B9Journalisation et surveillance insuffisanteMoyenneLogging contextualisé ; détection de patterns d’attaque
B10Intégrité du code manquanteMoyenneSignature 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 @Param avec @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.serialization est 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.import pour 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:check

Rè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 @PreAuthorize sur 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 @ConfigurationProperties sont 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