Ce guide explique, pas à pas, comment durcir IIS pour héberger un service OCSP (Microsoft Online Responder) tout en évitant les faux‑positifs d’audit autour du « Global .NET Trust Level » et du filtrage des extensions, et en appliquant des réglages de sécurité concrets et reproductibles.
Vue d’ensemble de la question
Votre équipe exploite un Online Responder (OCSP) publié via IIS et doit satisfaire des exigences de durcissement. Deux points d’audit reviennent systématiquement : le trust level .NET et l’interdiction des extensions de fichier non listées. Voici la formulation typique :
Point de contrôle | Question soulevée |
---|---|
Configurer le niveau de confiance global .NET | Le service OCSP utilise‑t‑il le runtime .NET ? Si oui, quel trust level appliquer ? |
Interdire les extensions de fichier non listées | Quelles extensions de fichier doivent être autorisées pour que l’OCSP fonctionne ? |
Réponse et solution
- OCSP n’utilise pas ASP.NET
- Le composant qui traite les requêtes est une extension ISAPI native : ocspisapi.dll (installée avec le rôle Active Directory Certificate Services > Online Responder). Il s’agit de code natif hébergé par IIS via IsapiModule, pas d’une application ASP.NET.
- Conséquence directe : le paramètre Global .NET Trust Level n’a aucun effet sur l’OCSP. Vous pouvez conserver la valeur par défaut (Full) ou désactiver le pipeline .NET si aucune autre application du même site ne l’utilise.
- La seule dépendance IIS indispensable est la mappage de gestionnaire pointant vers ocspisapi.dll pour le chemin
/ocsp
(ou/ocsp/*
) et marquée Allowed.
- Gestion des extensions de fichier (Request Filtering)
- Les URL OCSP sont de la forme :
https://ocsp.domaine.tld/ocsp
: elles sont sans extension. - Si l’option Allow unlisted file name extensions est définie à false, IIS retourne HTTP 404.7 (Denied by request filtering configuration) pour ces requêtes sans extension.
- Deux options robustes pour concilier sécurité et fonctionnement :
<table> <thead> <tr> <th>Approche</th> <th>Configuration</th> <th>Remarques</th> </tr> </thead> <tbody> <tr> <td>Laisser « Allow unlisted » <strong>true</strong> uniquement sur l’application OCSP</td> <td>Au niveau de l’application <code>/ocsp</code>, définir <code><fileExtensions allowUnlisted="true"></code></td> <td>Réduit l’impact à la seule surface OCSP. Conserver <em>false</em> ailleurs si souhaité.</td> </tr> <tr> <td>Interdire globalement et autoriser l’« extension » vide</td> <td>Définir <code>allowUnlisted="false"</code> et ajouter <code>fileExtension="."</code> avec <code>allowed="true"</code></td> <td>Évite toute autre extension. Fonctionne également sous un site strictement verrouillé.</td> </tr> </tbody> </table> <p>Exemple de bloc <em>web.config</em> ciblé sur <code>/ocsp</code> :</p> <pre><code><configuration>
<!-- Option B : sinon, interdire globalement et autoriser l'extension vide --> <!-- <fileExtensions allowUnlisted="false"> <add fileExtension="." allowed="true" /> </fileExtensions> --> <!-- Requêtes OCSP petites : plafonner la taille pour réduire le risque DoS --> <requestLimits maxAllowedContentLength="65536" /> <!-- 64 Ko suffisent largement --> <!-- Verbes nécessaires uniquement --> <verbs> <add verb="GET" allowed="true" /> <add verb="POST" allowed="true" /> <add verb="*" allowed="false" /> </verbs> </requestFiltering> </security>
<p><strong>Aucune autre extension</strong> (<code>.asp</code>, <code>.aspx</code>, <code>.dll</code>, etc.) n’est requise par l’Online Responder.</p>
- Les URL OCSP sont de la forme :
- Mesures de sécurité complémentaires utiles Action recommandée Bénéfice Limiter les méthodes HTTP à GET et POST via Request Filtering Réduit la surface d’attaque (PUT, DELETE, PROPFIND inutiles) Forcer HTTPS, n’autoriser que TLS 1.2/1.3, suites fortes Intégrité et confidentialité des échanges OCSP Restreindre l’accès IP au répertoire virtuel
/ocsp
(liste blanche) Filtre les requêtes non légitimes internes/externes Surveiller les logs IIS (%SystemDrive%\inetpub\logs\LogFiles
) et le journal AD CS Online Responder Détection proactive d’erreurs, pics de charge et abus Maintenir à jour le rôle Online Responder et son serveur Windows Corrections de vulnérabilités et de bogues (ex. correctifs liés aux requêtes multi‑certificats)
Pourquoi .NET Trust Level ne s’applique pas ici
Le Global .NET Trust Level contrôle les permissions de code des applications ASP.NET exécutées dans le CLR. L’Online Responder, lui, est un module ISAPI natif (ocspisapi.dll
) chargé par IIS et exécuté par le worker process w3wp.exe
sans CLR. En pratique :
- Changer le trust level ne modifie pas l’exécution d’OCSP.
- Vous pouvez créer un pool d’applications dédié configuré sur « No Managed Code », ce qui rappelle explicitement l’absence de dépendance .NET.
- Si d’autres applications ASP.NET partagent le site, appliquez‑leur les règles .NET nécessaires sans craindre un impact sur l’OCSP.
Architecture et composants OCSP sous IIS
Lors de l’installation du rôle Online Responder, l’assistant crée :
- Un répertoire virtuel
/ocsp
sous le site cible (souvent Default Web Site), - Une entrée Handler Mappings associant le chemin
ocsp
(ouocsp/*
) au processeur%SystemRoot%\System32\ocsp\ocspisapi.dll
, - Une console d’administration Online Responder (revocation configurations, certificats de signature OCSP, cache, etc.).
Le certificat de signature OCSP utilisé pour signer les réponses est distinct du certificat TLS d’IIS. Le premier relève d’AD CS (EKU OCSP Signing), le second est un certificat « Serveur Web » lié au site IIS. Ne les confondez pas : on peut les gérer séparément, rotation incluse.
Procédure de durcissement pas à pas
Préparer un pool d’applications dédié
- Créer un pool OCSPAppPool avec :
- .NET CLR version : No Managed Code
- Mode pipeline : Integrated
- Start Mode : AlwaysRunning (optionnel si exigence de latence minimale)
- Rapid‑Fail Protection activé (valeurs par défaut recommandées)
- Identité : ApplicationPoolIdentity (suffisant dans la plupart des cas)
- Affecter l’application
/ocsp
à ce pool.
Vérifier le mappage de gestionnaire
Dans IIS Manager > site > Handler Mappings :
- Entrée OCSP (ou équivalent) avec Module : IsapiModule, Executable : %SystemRoot%\System32\ocsp\ocspisapi.dll.
- Path :
ocsp
(ouocsp/*
), State : Allowed.
Renforcer le filtrage des requêtes
Au niveau de l’application /ocsp
, appliquer les réglages suivants :
- Extensions de fichier : voir les deux stratégies proposées plus haut (autoriser l’absence d’extension, ou autoriser explicitement l’« extension » vide).
- Limiter les verbes à GET et POST.
- Plafonner la taille de corps :
maxAllowedContentLength = 65536
(64 Ko). - Conserver doubleEscaping désactivé par défaut, sauf cas très particulier. Les requêtes GET OCSP peuvent contenir
+
,/
,=
; ces caractères sont pris en charge dans le chemin et ne nécessitent pas de double échappement.
Forcer HTTPS et durcir TLS
- Créer une liaison HTTPS sur le site/host d’OCSP avec un certificat serveur à jour (clé ≥2048 bits, SHA‑256 minimum). SNI recommandé si mutualisation.
- N’autoriser que TLS 1.2 et TLS 1.3 (si pris en charge par la version de Windows Server). Désactiver SSL 3.0, TLS 1.0, TLS 1.1.
- Privilégier des suites ECDHE avec AES‑GCM (et ChaCha20‑Poly1305 si disponible). Éviter RC4, 3DES, AES‑CBC.
Exemple PowerShell (schannel) :
# Exécuter en PowerShell (administrateur). Redémarrage requis de HTTP.sys / machine.
# Désactive TLS obsolètes côté serveur
New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Name 'Enabled' -Value 0 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Name 'DisabledByDefault' -Value 1 -PropertyType 'DWord' -Force | Out-Null
New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Name 'Enabled' -Value 0 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Name 'DisabledByDefault' -Value 1 -PropertyType 'DWord' -Force | Out-Null
# Active TLS 1.2/1.3 côté serveur (si supportés)
New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Name 'Enabled' -Value 1 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Name 'DisabledByDefault' -Value 0 -PropertyType 'DWord' -Force | Out-Null
New-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Name 'Enabled' -Value 1 -PropertyType 'DWord' -Force | Out-Null
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Name 'DisabledByDefault' -Value 0 -PropertyType 'DWord' -Force | Out-Null
Bloquer les verbes et rediriger HTTP vers HTTPS
Pour forcer systématiquement HTTPS (si URL Rewrite est installé) :
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Force HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
```
<security>
<requestFiltering>
<verbs>
<add verb="GET" allowed="true" />
<add verb="POST" allowed="true" />
<add verb="*" allowed="false" />
</verbs>
</requestFiltering>
</security>
```
</system.webServer>
</configuration> </code></pre>
<h3>Restreindre par adresse IP</h3>
<p>Si le service OCSP est destiné à des consommateurs connus (réseaux internes, proxys, équipements), appliquez une liste blanche :</p>
<pre><code><configuration>
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<add ipAddress="192.0.2.0" subnetMask="255.255.255.0" allowed="true" />
<add ipAddress="198.51.100.42" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</configuration>
</code></pre>
<h3>Configurer via PowerShell (WebAdministration)</h3>
<p>Extrait type pour appliquer les réglages <em>per‑app</em> sur <code>/ocsp</code> :</p>
<pre><code>Import-Module WebAdministration
$psPath = "IIS:\Sites\Default Web Site\ocsp"
# Extensions : option B - interdire tout sauf l'extension vide
Set-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/fileExtensions"`
-Name "allowUnlisted" -Value "False"
Add-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/fileExtensions"`
-Name "." -Value @{ fileExtension="."; allowed="True" }
# Verbes autorisés
Add-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/verbs"`
-Name "." -Value @{ verb="GET"; allowed="True" }
Add-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/verbs"`
-Name "." -Value @{ verb="POST"; allowed="True" }
Add-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/verbs"`
-Name "." -Value @{ verb="*"; allowed="False" }
# Taille maximale
Set-WebConfigurationProperty -PSPath $psPath ` -Filter "system.webServer/security/requestFiltering/requestLimits"`
-Name "maxAllowedContentLength" -Value 65536
# Pool d'applications sans CLR
Set-ItemProperty "IIS:\AppPools\OCSPAppPool" -Name "managedRuntimeVersion" -Value "" </code></pre>
<h2>Tests fonctionnels et de sécurité</h2>
<h3>Tester la disponibilité</h3>
<ul>
<li><strong>curl</strong> (POST binaire) :
<pre><code># Fichier req.der = OCSPRequest DER (facultatif si simple test de connectivité)
curl -vk -o /dev/null -s -w "HTTP %{http_code}\n" ^
-H "Content-Type: application/ocsp-request" ^
-H "Accept: application/ocsp-response" ^
--data-binary "@req.der" https://ocsp.domaine.tld/ocsp
</code></pre>
<p>Attendu : <code>HTTP 200</code>. Le corps est binaire (<em>application/ocsp-response</em>).</p>
</li>
<li><strong>certutil</strong> (Windows) :
<pre><code>certutil -url "https://ocsp.domaine.tld/ocsp" cert.cer
certutil -verify cert.cer urlfetch
Détecter les erreurs courantes
Symptôme | Cause probable | Correction |
---|---|---|
HTTP 404.7 | Extensions non listées interdites pour URL sans extension | Autoriser l’extension vide ou mettre allowUnlisted="true" sur /ocsp |
HTTP 404.2 | Handler ISAPI non autorisé | Vérifier Handler Mappings et état Allowed |
HTTP 403.4 | SSL requis mais accès en HTTP | Rediriger HTTP vers HTTPS ou documenter la contrainte |
HTTP 500 | Erreur interne du module OCSP | Contrôler le journal AD CS Online Responder et la configuration de signature |
Journalisation et supervision
- Activer la journalisation W3C sur le site/chemin OCSP (champs clés :
date
,time
,c-ip
,cs-method
,cs-uri-stem
,sc-status
,time-taken
,cs(User-Agent)
). - Surveiller le journal d’événements « AD CS Online Responder » pour les événements de signature, de cache et d’erreur.
- Mettre en place des alertes (p. ex. si taux d’erreur > seuil, time‑taken anormal, taille de réponse inhabituelle).
Performance, résilience et exposition
- Cache OCSP : ajuster les durées de validité en fonction de vos besoins (fraîcheur vs charge). Un cache plus long réduit le trafic.
- NLB / reverse proxy : placer les responders derrière un équilibreur. Prévoir du health‑check sur
GET /ocsp
et des timeouts adaptés. - WAF / filtrage L7 : s’assurer que
+
,/
,=
dans les URLs GET OCSP ne sont pas bloqués par des règles génériques. - Limites IIS : Dynamic IP Restrictions peut limiter les rafales de requêtes anormales.
Exemple complet de web.config minimal et durci pour /ocsp
À adapter à votre arborescence (site, pool…). Ce fichier se place dans le répertoire virtuel /ocsp
.
<configuration>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
```
<!-- Handler ISAPI natif (normalement créé par le rôle Online Responder) -->
<handlers>
<add name="OCSP" path="ocsp" verb="GET,POST" modules="IsapiModule"
scriptProcessor="%SystemRoot%\System32\ocsp\ocspisapi.dll"
resourceType="Unspecified" requireAccess="Execute" />
</handlers>
<security>
<requestFiltering>
<fileExtensions allowUnlisted="false">
<add fileExtension="." allowed="true" />
</fileExtensions>
<verbs>
<add verb="GET" allowed="true" />
<add verb="POST" allowed="true" />
<add verb="*" allowed="false" />
</verbs>
<requestLimits maxAllowedContentLength="65536" />
</requestFiltering>
<ipSecurity allowUnlisted="false">
<!-- Exemple : liste blanche, à adapter -->
<add ipAddress="192.0.2.0" subnetMask="255.255.255.0" allowed="true" />
</ipSecurity>
</security>
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
<add name="X-Content-Type-Options" value="nosniff" />
</customHeaders>
</httpProtocol>
<rewrite>
<rules>
<rule name="Force HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
```
AppCmd : antisèche de commandes utiles
# Cible configuration apphost, application /ocsp sous Default Web Site
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering /requestLimits.maxAllowedContentLength:"65536"
# Interdire les extensions non listées et autoriser l'extension vide
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering.fileExtensions /allowUnlisted:"False"
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering.fileExtensions ^
"/+[fileExtension='.',allowed='True']"
# Autoriser uniquement GET et POST
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering.verbs "/-[verb='*']"
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering.verbs "/+[verb='GET',allowed='True']"
%windir%\system32\inetsrv\appcmd.exe set config "Default Web Site/ocsp" ^
/section:system.webServer/security/requestFiltering.verbs "/+[verb='POST',allowed='True']"
FAQ d’audit / réponses rapides
- L’OCSP utilise‑t‑il le runtime .NET ? Non. Il s’appuie sur une extension ISAPI native (
ocspisapi.dll
), pas sur ASP.NET. - Quel trust level .NET appliquer ? Sans incidence pour l’OCSP. Conserver la valeur par défaut ou désactiver .NET si non utilisé par ailleurs.
- Quelles extensions autoriser ? Aucune extension particulière n’est requise. Les URL étant sans extension, autorisez l’« extension » vide
.
ou laissez Allow unlisted à true uniquement sur/ocsp
. - Quels verbes HTTP ?
GET
etPOST
uniquement. - Quels en‑têtes MIME ? Requête POST :
Content-Type: application/ocsp-request
. Réponse :Content-Type: application/ocsp-response
. - Pourquoi 404.7 ? Parce que IIS a interdit les URL sans extension. Corriger le requestFiltering comme indiqué.
- Faut‑il activer double escaping ? Non dans le scénario standard. Les caractères
+
//
/=
des requêtes GET OCSP sont attendus.
Checklist de durcissement
Élément | Réglage cible | État |
---|---|---|
Pool d’applications OCSP | No Managed Code, Integrated, identités par défaut | ☐ |
Handler ISAPI | ocspisapi.dll autorisé, chemin ocsp ou ocsp/* | ☐ |
Extensions | allowUnlisted=true sur /ocsp ou allowUnlisted=false + fileExtension="." autorisée | ☐ |
Verbes HTTP | Seulement GET, POST | ☐ |
Taille des requêtes | maxAllowedContentLength=65536 | ☐ |
TLS | TLS 1.2/1.3 uniquement, suites fortes | ☐ |
IP allow‑list | ipSecurity allowUnlisted=false + adresses autorisées | ☐ |
Journaux & alertes | Logs IIS + journal Online Responder surveillés | ☐ |
Mises à jour | Windows & rôle Online Responder à jour | ☐ |
Points d’attention supplémentaires
- Rotation des certificats : planifier la rotation du certificat TLS et du certificat de signature OCSP indépendamment, avec chevauchement de validité.
- Isolation : héberger OCSP sur un site dédié facilite l’application de règles spécifiques (extensions, verbes, IP).
- Reverse proxies : si un proxy s’interpose, s’assurer qu’il transmet bien le corps binaire des requêtes POST et ne tronque pas les URLs GET longues.
- Recyclage de pool : conserver un recyclage programmé hors heures de pointe si nécessaire ; l’OCSP ne maintient pas d’état applicatif.
- Disponibilité : déployer au moins deux responders derrière un équilibreur afin d’éviter un SPOF.
En résumé
Le service OCSP n’est pas une application ASP.NET : le .NET Trust Level ne s’applique donc pas. Pour satisfaire l’audit « interdire les extensions non listées » sans casser le service, autorisez l’extension vide ou laissez Allow unlisted à true uniquement sur l’application /ocsp
. Ajoutez des contrôles de verbes, renforcez TLS, mettez en place une liste blanche IP si possible, et surveillez les journaux. Ces réglages conservent la compatibilité OCSP tout en respectant les bonnes pratiques de durcissement IIS.