Sécurité d'un site web en PME : par où commencer sans RSSI ni budget
On ne vous vise pas. On vous trouve.
Personne ne se lève le matin avec l'idée de forcer le formulaire de réservation d'une boîte de douze personnes. Ce qui se passe est plus terne : des scanners balaient l'internet entier et tous les journaux de transparence des certificats à la recherche d'une faille connue dans une version connue. Votre site remonte dans ce balayage comme celui de tout le monde.
Deux chiffres publics méritent d'être gardés en tête. Dans son panorama de la cybermenace 2025 (p. 9), le CERT-FR indique que les TPE, PME et ETI représentent 48 % des victimes de rançongiciel qu'il a traitées en 2025, contre 37 % en 2024 — de loin la première catégorie. Et le rapport DBIR 2026 de Verizon situe une vulnérabilité logicielle à l'origine de 31 % des compromissions, en hausse de 20 % l'an dernier, désormais devant les identifiants volés.
Il y a une bonne nouvelle là-dedans : les portes d'entrée utilisées sont banales. Rien de ce qui suit dans la première moitié de cet article ne demande une équipe sécurité.
Un ordre de priorité qui tient
Triez selon ce que l'attaquant obtient pour le moindre effort, pas selon ce qui fait peur. Trois questions, dans cet ordre :
- Si cette brique tombe, est-ce que tout le reste tombe avec ? (Registrar, DNS, messagerie.)
- Un script peut-il le trouver sans rien savoir de vous ? (Versions anciennes, fichiers exposés, en-têtes absents.)
- Si ça arrive quand même, savez-vous revenir ? (Sauvegardes, journaux.)
Le WAF, les certifications et le commercial croisé sur un salon viennent après.
Une règle avant tout le reste : ce qui suit s'applique à un site dont vous êtes propriétaire, ou pour lequel vous détenez une autorisation écrite. Sonder l'application de quelqu'un d'autre sans son accord est un délit (article 323-1 du Code pénal). Et si le site tourne chez un hébergeur mutualisé ou sur une plateforme SaaS, vérifiez aussi leurs conditions : plusieurs exigent d'être prévenues avant un scan actif.
Niveau 0 — l'après-midi qui coûte zéro euro
Le MFA sur les comptes d'administration, en commençant par le registrar
Commencez par le bureau d'enregistrement du domaine et l'hébergeur DNS, pas par le CMS. Qui contrôle le DNS peut détourner votre messagerie, faire réémettre vos certificats TLS, puis déclencher une réinitialisation de mot de passe sur tous vos autres services. C'est le compte unique depuis lequel on peut vous prendre le reste.
Ensuite, dans l'ordre : console d'hébergement, messagerie d'entreprise, dépôt de code, CI/CD, prestataire de paiement, back-office.
Utilisez une application TOTP ou une clé matérielle. Évitez le SMS quand vous avez le choix : le SIM swapping est une technique documentée et courante, pas une hypothèse d'école. La fiche MFA de l'OWASP sert de référence si vous devez en convaincre quelqu'un. Profitez-en pour interroger Have I Been Pwned : la recherche par domaine demande d'abord de prouver que le domaine est bien à vous, et devient payante au-delà de 25 adresses, mais elle vous dira si des identifiants de vos utilisateurs circulent. Ceux qui fuitent d'un site sans rapport finissent souvent rejoués chez vous.
Couper les accès des partants
Procédez service par service, jamais personne par personne — sinon vous en oublierez un. Pour chacun : liste des utilisateurs, jetons d'API, clés SSH, applications OAuth, webhooks, boîtes partagées, et numéros de récupération pointant encore vers un ancien téléphone. L'oubli classique, c'est le compte partagé dont le mot de passe n'a jamais été renouvelé : un départ, et l'identifiant est dehors pour de bon.
Mettre à jour les dépendances, et trier sérieusement
Les commandes, selon l'écosystème :
npm audit— documentationpip-audit— PyPIcomposer audit— CLI Composerosv-scanner scan source -r .— OSV-Scanner, qui couvre la plupart des écosystèmes d'un coup ; sans-r, il ne descend pas dans les sous-répertoires
Activez les alertes Dependabot pour ne plus avoir à y penser.
Puis triez, parce que la sortie brute va vous affoler pour rien. Une CVE critique dans une dépendance de build n'a rien à voir avec une CVE moyenne dans la bibliothèque qui parse les fichiers envoyés par vos utilisateurs. Deux filtres suffisent : le code vulnérable est-il réellement atteignable depuis une entrée utilisateur, et la CVE figure-t-elle au catalogue KEV de la CISA ? Tout ce qui est dans cette liste est exploité en ce moment même — à corriger en premier, quel que soit le score.
Les en-têtes, exactement
C'est de la configuration, pas du code : une ligne dans nginx, Apache ou votre CDN.
| En-tête | Valeur | Ce que ça vous apporte |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Le navigateur refuse le HTTP en clair sur votre domaine pendant un an. Coupe l'interception par rétrogradation sur un Wi-Fi hostile. |
Content-Security-Policy | default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self' | Limite ce qu'un script injecté peut charger ou exfiltrer, empêche que vos pages soient chargées dans une iframe (clickjacking), et interdit qu'un formulaire injecté poste vos données ailleurs. |
X-Content-Type-Options | nosniff | Le navigateur cesse de deviner le type de contenu : un fichier envoyé et servi en texte ne sera pas exécuté comme du script. |
Referrer-Policy | strict-origin-when-cross-origin | Verrouille le comportement déjà par défaut sur Chrome, Firefox et Safari, y compris sur les navigateurs qui ne l'appliquent pas. Décisif si un jeton traîne un jour dans les paramètres d'une URL. |
Permissions-Policy | geolocation=(), camera=(), microphone=() | Refuse les capacités navigateur que vous n'utilisez pas, y compris aux contenus tiers embarqués. |
Set-Cookie (session) | Secure; HttpOnly; SameSite=Lax | Le cookie de session ne circule jamais en clair et reste invisible au JavaScript. Lax le bloque sur les POST inter-sites et les sous-requêtes, mais il reste envoyé sur une navigation de premier niveau en GET — passez à Strict si rien chez vous ne dépend d'un lien entrant qui arrive déjà connecté. |
Deux précisions. frame-ancestors 'none' remplace X-Frame-Options sur les navigateurs actuels : ne gardez X-Frame-Options: DENY en doublon que si vous prenez encore en charge des clients très anciens. Et pour X-XSS-Protection, la recommandation de l'OWASP Secure Headers Project est de le poser à X-XSS-Protection: 0 plutôt que de le retirer : l'absence d'en-tête laisse le filtre au comportement par défaut sur les navigateurs anciens, alors que la valeur 0 le désactive explicitement.
Troisième précision, la plus coûteuse à rater. includeSubDomains s'applique à tous vos sous-domaines, y compris ceux encore servis en HTTP, et un navigateur qui a mémorisé max-age=31536000 les refusera pendant un an sans que vous puissiez revenir en arrière à distance. Recensez vos sous-domaines d'abord, puis montez par paliers — max-age=300, puis 86400, puis un an — et n'ajoutez includeSubDomains qu'une fois que tout répond en HTTPS.
La CSP est celle qui casse des choses au premier essai. Déployez-la d'abord en Content-Security-Policy-Report-Only, regardez ce que la console remonte pendant une semaine, puis appliquez.
Vérifiez gratuitement : HTTP Observatory de MDN note l'ensemble, CSP Evaluator vous dit si votre politique bloque réellement quelque chose, SSL Labs ou testssl.sh couvre TLS, et hstspreload.org est l'étape suivante une fois HSTS stabilisé. Les certificats sont gratuits et automatisables via Let's Encrypt : plus aucune raison d'en laisser expirer un.
Une sauvegarde que vous avez vraiment restaurée
Une sauvegarde jamais restaurée est une hypothèse. Testez-la : restaurez sur une machine vierge, chronométrez, et vérifiez que la base et les fichiers déposés par les utilisateurs sont revenus. Deux propriétés comptent : les sauvegardes vivent sur un compte séparé avec des identifiants séparés, et elles sont immuables ou hors ligne. Les opérateurs de rançongiciel cherchent les identifiants de la tâche de sauvegarde précisément parce qu'ils sont rangés à côté du reste.
Pour aller plus loin sans dépenser un euro, le guide d'hygiène informatique de l'ANSSI et les fiches de cybermalveillance.gouv.fr sont écrits exactement pour ce niveau.
Niveau 1 — la semaine d'après
Séparez les comptes. On ne travaille pas au quotidien sous un compte d'administration. L'application ne se connecte pas à sa base en superutilisateur : un rôle qui ne peut pas faire DROP TABLE limite ce qu'une injection réussie permet d'obtenir.
Gardez les journaux, 90 jours minimum. Qui s'est connecté, depuis où, ce qui a changé. Sans eux, après un incident, vous ne pouvez pas répondre à la seule question qui compte — qu'est-ce qui est sorti ? — et c'est aussi celle que vous devrez documenter si vous devez notifier la CNIL, ce qui se fait sous 72 heures.
Supprimez ce qui traîne. Deux lignes de shell, à lancer contre votre propre site — remplacez SITE par votre domaine avant d'appuyer sur Entrée :
SITE="https://votre-domaine.fr"for p in /.git/config /.env /backup.sql /phpinfo.php /server-status /.DS_Store; do curl -s -o /dev/null -w "%{http_code} $p\n" "$SITE$p"; done
Tout ce qui n'est ni 404 ni 403 mérite cinq minutes. Un /.git/config en 200 signifie que tout votre historique de code, y compris les secrets commités en 2021, est téléchargeable.
Renouvelez les secrets qui ont été commités un jour. Supprimer la ligne ne sert à rien, elle reste dans l'historique. gitleaks les retrouve ; seul le renouvellement corrige.
Testez le contrôle d'accès à la main. C'est le point le plus rentable de la liste, et aucun scanner ne le fera pour vous. Créez deux comptes. Avec le compte A, repérez un identifiant dans une URL ou une réponse d'API — /api/factures/1042. Connectez-vous en B et demandez la même ressource avec la session de B : curl -H "Cookie: session=<session de B>" https://votre-domaine.fr/api/factures/1042.
Si B voit la facture de A, vous avez un défaut de contrôle d'accès au niveau objet — premier de l'OWASP API Security Top 10. Répétez sur chaque endpoint qui prend un id, un uuid, un slug ou un nom de fichier, et surtout sur les exports PDF et les téléchargements, généralement écrits après que les règles de permission ont été pensées. Un scanner ne trouve pas ça : il ignore que 1042 appartient à A.
Niveau 2 — les outils gratuits qu'on lance soi-même
ZAP explore et teste activement une application. Nuclei passe des milliers de gabarits de défauts connus très vite. WPScan est l'outil à utiliser sur WordPress. Lancez les scans actifs sur une recette, ou sur la production seulement avec une sauvegarde fraîche et hors heures ouvrées — un scanner actif soumet les formulaires.
Attendez-vous au bruit. Une sortie de scanner est une liste de candidats, pas de constats : chaque ligne doit être reproduite à la main avant de vouloir dire quoi que ce soit. C'est exactement ce qui sépare un export d'outil d'un rapport de sécurité digne de ce nom.
Le moment où un regard extérieur devient rentable
Trois choses que vous ne trouverez pas sur votre propre site, aussi compétent soyez-vous :
- La logique métier. Il n'existe aucune signature pour « ce parcours peut être court-circuité » — les exemples types sont détaillés dans l'article sur les prix.
- Les enchaînements. Un numéro de version qui fuite ici, un endpoint oublié là, une permission vérifiée sur la page mais pas sur l'API. Chacun anodin. Ensemble, une prise de contrôle de compte.
- Le biais d'auteur. On ne teste pas ce qu'on est certain d'avoir bien implémenté. Ce n'est pas un problème de niveau : c'est la raison d'être de la revue de code.
Déclencheurs concrets : vous détenez des données personnelles au-delà d'un email de contact, vous manipulez de l'argent, vous êtes en multi-tenant (chaque client voit ses données), vous venez de mettre en ligne une refonte ou une API publique, ou un client vous a envoyé un questionnaire sécurité par écrit.
Et une vraie raison d'attendre : payer un audit sur un site sans MFA et sans sauvegarde testée, c'est acheter un rapport dont vous pouvez déjà écrire la première page. Faites le niveau 0 d'abord.
La checklist
- [ ] MFA sur registrar, DNS, hébergement, messagerie, dépôt de code, CI/CD, paiement, back-office — TOTP ou clé matérielle
- [ ] Partants et anciens prestataires retirés de chaque service, jetons, clés SSH et webhooks compris
- [ ] Audit de dépendances lancé ; tout ce qui figure au catalogue KEV corrigé
- [ ] Alertes de dépendances automatiques activées
- [ ] Six en-têtes posés, vérifiés avec HTTP Observatory et CSP Evaluator
- [ ] TLS valide, renouvellement automatique, noté par SSL Labs
- [ ] Sauvegarde restaurée sur une machine vierge, chronométrée, fichiers inclus ; stockée sur un compte séparé, immuable ou hors ligne
- [ ]
.git,.env,.sql,phpinfoinaccessibles depuis le web - [ ] Secrets commités un jour : tous renouvelés
- [ ] Test d'échange d'identifiants entre deux comptes passé sur chaque endpoint concerné
- [ ] Journaux d'authentification et d'administration conservés 90 jours
- [ ] L'utilisateur base de données de l'application n'est pas superutilisateur
L'essentiel tient en un après-midi et une matinée de suivi. Cela retire les portes d'entrée que les scanners trouvent — celles que les balayages automatiques essaient en premier.
Si vous préférez qu'un tiers regarde, et que vous voulez savoir ce que coûte cette prestation ailleurs avant de décider, voici l'offre exacte.
C'est ce que vend iwantreport.dev : une application web et son API, testées sur l'OWASP Top 10, l'API Security Top 10, le CWE Top 25 et l'ASVS — un scanner en première passe, puis chaque résultat reproduit à la main avant d'entrer dans le rapport. Rapport écrit sous 48 h, un re-test inclus, 200 €, garantie satisfait ou remboursé 30 jours : il vous suffit d'en faire la demande par email dans les 30 jours suivant la livraison. Hors périmètre : le réseau interne, la revue de code source, le phishing et l'ingénierie sociale, les tests de charge ou de déni de service, et les applications mobiles.