Avant JWT Attack Toolkit, avant OSINT Platform, avant tout le reste, j'ai écrit un script Python de 200 lignes qui vérifie les headers de sécurité d'un site web. C'est simple, c'est basique, et c'est le projet qui m'a appris le plus sur la sécurité web. Voici le code commenté et ce que j'en ai tiré.
L'idée de départ
En lisant un article sur les headers de sécurité HTTP, j'ai réalisé que la plupart des sites que je visitais n'avaient pas les headers recommandés. Pas de Content-Security-Policy, pas de Strict-Transport-Security, pas de X-Content-Type-Options. J'ai voulu vérifier ça automatiquement.
Ce que le script vérifie
Le scanner teste 8 headers de sécurité essentiels et attribue une note à chacun :
- Strict-Transport-Security (HSTS) : force le navigateur à utiliser HTTPS. Sans ce header, un attaquant peut intercepter la première requête HTTP et faire un downgrade attack.
- Content-Security-Policy (CSP) : contrôle quelles ressources le navigateur peut charger. C'est la meilleure protection contre les XSS.
- X-Content-Type-Options : empêche le navigateur de deviner le type MIME d'une ressource. Sans ce header, un fichier .txt peut être interprété comme du JavaScript.
- X-Frame-Options : empêche l'inclusion du site dans une iframe. Protection contre le clickjacking.
- Referrer-Policy : contrôle quelles informations sont envoyées dans le header Referer lors de la navigation.
- Permissions-Policy : contrôle l'accès aux APIs du navigateur (caméra, micro, géolocalisation).
- X-XSS-Protection : active le filtre XSS intégré du navigateur. Déprécié mais encore utile pour les vieux navigateurs.
- Cache-Control : contrôle la mise en cache des réponses. Important pour les pages avec des données sensibles.
Le code
import requests
import sys
HEADERS_CHECK = {
'Strict-Transport-Security': {
'required': True,
'description': 'Force HTTPS',
'recommendation': "Ajouter: Strict-Transport-Security: max-age=31536000; includeSubDomains"
},
'Content-Security-Policy': {
'required': True,
'description': 'Contrôle les ressources chargées',
'recommendation': "Définir une politique CSP restrictive"
},
# ... 6 autres headers
}
def scan(url):
response = requests.get(url, timeout=10)
results = []
for header, config in HEADERS_CHECK.items():
present = header.lower() in {k.lower(): v for k, v in response.headers.items()}
results.append({
'header': header,
'present': present,
'value': response.headers.get(header, 'ABSENT'),
'recommendation': config['recommendation'] if not present else 'OK'
})
return resultsLe script fait un GET sur l'URL, récupère les headers de la réponse, et vérifie la présence de chaque header de sécurité. Pour chaque header absent, il affiche une recommandation avec la valeur à ajouter.
Ce que j'ai appris en le codant
1. Les headers ne suffisent pas
Un site peut avoir tous les headers de sécurité et être quand même vulnérable. CSP mal configuré (unsafe-inline, unsafe-eval) est pire que pas de CSP du tout parce que ça donne un faux sentiment de sécurité. Le scanner vérifie la présence des headers, mais pas leur qualité — c'est une limitation que j'ai corrigée dans la v2.
2. Les redirections compliquent tout
Beaucoup de sites redirigent HTTP vers HTTPS. Le header HSTS n'est pertinent que sur la réponse HTTPS finale, pas sur la redirection. J'ai dû ajouter un paramètre allow_redirects=True et vérifier les headers de la réponse finale, pas de la première.
3. Les CDN ajoutent leurs propres headers
Cloudflare, Akamai et Fastly ajoutent des headers de sécurité automatiquement. Le scanner peut donner un faux positif si le header est ajouté par le CDN et pas par l'application. J'ai ajouté une détection de CDN pour contextualiser les résultats.
La v2 : analyse de la qualité
La v2 du scanner ne vérifie pas seulement la présence des headers mais aussi leur qualité. Pour CSP, il parse la politique et vérifie l'absence de unsafe-inline et unsafe-eval. Pour HSTS, il vérifie que le max-age est supérieur à 6 mois. Pour Referrer-Policy, il vérifie que la valeur n'est pas unsafe-url.
Les résultats sur 100 sites
J'ai scanné les 100 sites les plus visités en France. Les résultats étaient surprenants : 73% avaient HSTS, mais seulement 34% avaient une CSP. 89% avaient X-Content-Type-Options (souvent ajouté par le CDN). Seulement 12% avaient une Permissions-Policy. Et 8 sites n'avaient aucun header de sécurité.
Ce que ce projet m'a apporté
Ce script de 200 lignes m'a appris plus sur la sécurité web que n'importe quel cours en ligne. En codant la vérification de chaque header, j'ai dû comprendre à quoi il sert, quelles attaques il prévient, et comment le configurer correctement. C'est cette approche — apprendre en construisant — qui m'a mené à créer des outils de plus en plus complexes.
Le code est sur GitHub. Il n'est pas parfait, il n'est pas optimisé, mais il fonctionne et il m'a tout appris. Si tu débutes en sécurité, je te recommande de coder ton propre scanner plutôt que d'utiliser un outil existant. Le process d'apprentissage est dans le code, pas dans le résultat.
200 lignes de Python, 8 headers vérifiés, et une passion pour la sécurité web qui ne m'a plus quitté.