Comment empêcher les hackers de pirater votre code Java : injections SQL et XSS à la loupe
\n\nImaginez : vous avez écrit une application web parfaite en Java. Belle interface, logique rapide, architecture propre. Vous la déployez sur le serveur, préparez un thé... et une heure plus tard, vous recevez un message indiquant que la base de données a été supprimée et que la page d'accueil arbore un audacieux ASCII-art. Une histoire familière ? Malheureusement, pour de nombreux développeurs, oui.
\n\nLes deux vulnérabilités les plus courantes et dangereuses des applications web — les injections SQL et le cross-site scripting (XSS) — privent chaque année de sommeil les administrateurs de milliers de sites. Et Java, malgré sa rigueur, ne fait pas exception. Mais bonne nouvelle : il est possible de s'en protéger. Et ce n'est même pas très compliqué.
\n\nDans cet article, nous allons voir comment les attaquants ciblent les applications Java, et surtout comment mettre en place un rempart solide avec des outils éprouvés et de bonnes habitudes de codage. Attachez vos ceintures : il y aura beaucoup de code, d'astuces et un minimum de blabla.
\n\nInjections SQL : quand l'utilisateur devient programmeur
\n\nQu'est-ce que c'est et pourquoi ça fonctionne ?
\n\nL'injection SQL est une technique d'attaque où un attaquant « injecte » du code SQL malveillant dans une requête via une saisie utilisateur. Si l'application concatène aveuglément des chaînes, l'attaquant peut accéder à des données sensibles, supprimer des tables ou même prendre le contrôle du serveur de base de données.
\n\nExemple classique de mauvais code en Java :
\n\nString userInput = request.getParameter("username");\nString query = "SELECT * FROM users WHERE username = '" + userInput + "'";\nStatement stmt = connection.createStatement();\nResultSet rs = stmt.executeQuery(query);\n\nQue se passe-t-il si l'utilisateur saisit : admin' OR '1'='1 ? La requête devient :
SELECT * FROM users WHERE username = 'admin' OR '1'='1'\n\nLa condition '1'='1' est toujours vraie. Félicitations : l'attaquant vient de se connecter en tant qu'administrateur, sans même connaître le mot de passe. Et s'il saisit '; DROP TABLE users; -- — c'est la catastrophe.
Comment se protéger : PreparedStatement, votre bouclier
\n\nRègle numéro un en sécurité des applications Java : ne jamais concaténer des données utilisateur avec des requêtes SQL. Utilisez des requêtes paramétrées via PreparedStatement.
Voici à quoi devrait ressembler un code sécurisé :
\n\nString userInput = request.getParameter("username");\nString query = "SELECT * FROM users WHERE username = ?";\nPreparedStatement pstmt = connection.prepareStatement(query);\npstmt.setString(1, userInput);\nResultSet rs = pstmt.executeQuery();\n\nQue s'est-il passé ici ? La base de données reçoit la requête et les données séparément. Même si userInput contient du code SQL malveillant, il sera traité comme une simple chaîne, et non comme une commande. PreparedStatement échappe automatiquement les caractères spéciaux. C'est la première et la plus importante ligne de défense.
Mesures supplémentaires : procédures stockées et validation
\n\nEn plus de PreparedStatement, il est recommandé d'utiliser :
- \n
- Les procédures stockées — l'appel d'une procédure via
CallableStatementsépare également le code des données. \n - Les listes blanches — si vous devez insérer un nom de table ou de colonne (ce qui est rare), ne le prenez jamais depuis la saisie utilisateur. Utilisez une énumération ou des constantes strictement définies. \n
- La validation des entrées — vérifiez qu'un email ressemble bien à un email, et qu'un nombre est bien un nombre. Mais rappelez-vous : la validation est une couche supplémentaire, pas un remplacement de
PreparedStatement. \n
Exemple de gestion sécurisée des noms de tables dynamiques :
\n\npublic enum TableName {\n USERS, PRODUCTS, ORDERS\n}\n\npublic void queryTable(TableName table) {\n String que