Durcissement IIS pour OCSP (Microsoft Online Responder) : .NET Trust Level, Request Filtering et sécurité TLS

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.

Sommaire

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ôleQuestion soulevée
Configurer le niveau de confiance global .NETLe service OCSP utilise‑t‑il le runtime .NET ? Si oui, quel trust level appliquer ?
Interdire les extensions de fichier non listéesQuelles extensions de fichier doivent être autorisées pour que l’OCSP fonctionne ?

Réponse et solution

  1. 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.
  2. 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 «&nbsp;Allow unlisted&nbsp;» <strong>true</strong> uniquement sur l’application OCSP</td> <td>Au niveau de l’application <code>/ocsp</code>, définir <code>&lt;fileExtensions allowUnlisted="true"&gt;</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’«&nbsp;extension&nbsp;» 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>&nbsp;:</p> <pre><code>&lt;configuration&gt; &lt;!-- Option B : sinon, interdire globalement et autoriser l'extension vide --&gt; &lt;!-- &lt;fileExtensions allowUnlisted="false"&gt; &lt;add fileExtension="." allowed="true" /&gt; &lt;/fileExtensions&gt; --&gt; &lt;!-- Requêtes OCSP petites : plafonner la taille pour réduire le risque DoS --&gt; &lt;requestLimits maxAllowedContentLength="65536" /&gt; &lt;!-- 64 Ko suffisent largement --&gt; &lt;!-- Verbes nécessaires uniquement --&gt; &lt;verbs&gt; &lt;add verb="GET" allowed="true" /&gt; &lt;add verb="POST" allowed="true" /&gt; &lt;add verb="*" allowed="false" /&gt; &lt;/verbs&gt; &lt;/requestFiltering&gt; &lt;/security&gt; <p><strong>Aucune autre extension</strong> (<code>.asp</code>, <code>.aspx</code>, <code>.dll</code>, etc.) n’est requise par l’Online Responder.</p>
  3. 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 (ou ocsp/*) 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é

  1. 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)
  2. 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 (ou ocsp/*), 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é) :

&lt;configuration&gt;
  &lt;system.webServer&gt;
    &lt;rewrite&gt;
      &lt;rules&gt;
        &lt;rule name="Force HTTPS" enabled="true" stopProcessing="true"&gt;
          &lt;match url="(.*)" /&gt;
          &lt;conditions&gt;
            &lt;add input="{HTTPS}" pattern="off" /&gt;
          &lt;/conditions&gt;
          &lt;action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /&gt;
        &lt;/rule&gt;
      &lt;/rules&gt;
    &lt;/rewrite&gt;

```
&lt;security&gt;
  &lt;requestFiltering&gt;
    &lt;verbs&gt;
      &lt;add verb="GET" allowed="true" /&gt;
      &lt;add verb="POST" allowed="true" /&gt;
      &lt;add verb="*" allowed="false" /&gt;
    &lt;/verbs&gt;
  &lt;/requestFiltering&gt;
&lt;/security&gt;
```

</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&nbsp;:</p>
<pre><code>&lt;configuration&gt;
  &lt;system.webServer&gt;
    &lt;security&gt;
      &lt;ipSecurity allowUnlisted="false"&gt;
        &lt;add ipAddress="192.0.2.0" subnetMask="255.255.255.0" allowed="true" /&gt;
        &lt;add ipAddress="198.51.100.42" allowed="true" /&gt;
      &lt;/ipSecurity&gt;
    &lt;/security&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;
</code></pre>

<h3>Configurer via PowerShell (WebAdministration)</h3>
<p>Extrait type pour appliquer les réglages <em>per‑app</em> sur <code>/ocsp</code>&nbsp;:</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)&nbsp;:
    <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&nbsp;: <code>HTTP 200</code>. Le corps est binaire (<em>application/ocsp-response</em>).</p>
  </li>
  <li><strong>certutil</strong> (Windows)&nbsp;:
    <pre><code>certutil -url "https://ocsp.domaine.tld/ocsp" cert.cer
certutil -verify cert.cer urlfetch

Détecter les erreurs courantes

SymptômeCause probableCorrection
HTTP 404.7Extensions non listées interdites pour URL sans extensionAutoriser l’extension vide ou mettre allowUnlisted="true" sur /ocsp
HTTP 404.2Handler ISAPI non autoriséVérifier Handler Mappings et état Allowed
HTTP 403.4SSL requis mais accès en HTTPRediriger HTTP vers HTTPS ou documenter la contrainte
HTTP 500Erreur interne du module OCSPContrô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" />

```
&lt;!-- Handler ISAPI natif (normalement créé par le rôle Online Responder) --&gt;
&lt;handlers&gt;
  &lt;add name="OCSP" path="ocsp" verb="GET,POST" modules="IsapiModule"
       scriptProcessor="%SystemRoot%\System32\ocsp\ocspisapi.dll"
       resourceType="Unspecified" requireAccess="Execute" /&gt;
&lt;/handlers&gt;

&lt;security&gt;
  &lt;requestFiltering&gt;
    &lt;fileExtensions allowUnlisted="false"&gt;
      &lt;add fileExtension="." allowed="true" /&gt;
    &lt;/fileExtensions&gt;
    &lt;verbs&gt;
      &lt;add verb="GET" allowed="true" /&gt;
      &lt;add verb="POST" allowed="true" /&gt;
      &lt;add verb="*" allowed="false" /&gt;
    &lt;/verbs&gt;
    &lt;requestLimits maxAllowedContentLength="65536" /&gt;
  &lt;/requestFiltering&gt;
  &lt;ipSecurity allowUnlisted="false"&gt;
    &lt;!-- Exemple : liste blanche, à adapter --&gt;
    &lt;add ipAddress="192.0.2.0" subnetMask="255.255.255.0" allowed="true" /&gt;
  &lt;/ipSecurity&gt;
&lt;/security&gt;

&lt;httpProtocol&gt;
  &lt;customHeaders&gt;
    &lt;add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" /&gt;
    &lt;add name="X-Content-Type-Options" value="nosniff" /&gt;
  &lt;/customHeaders&gt;
&lt;/httpProtocol&gt;

&lt;rewrite&gt;
  &lt;rules&gt;
    &lt;rule name="Force HTTPS" stopProcessing="true"&gt;
      &lt;match url="(.*)" /&gt;
      &lt;conditions&gt;
        &lt;add input="{HTTPS}" pattern="off" /&gt;
      &lt;/conditions&gt;
      &lt;action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /&gt;
    &lt;/rule&gt;
  &lt;/rules&gt;
&lt;/rewrite&gt;

&lt;httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" /&gt;
```


 

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 et POST 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émentRéglage cibleÉtat
Pool d’applications OCSPNo Managed Code, Integrated, identités par défaut
Handler ISAPIocspisapi.dll autorisé, chemin ocsp ou ocsp/*
ExtensionsallowUnlisted=true sur /ocsp ou allowUnlisted=false + fileExtension="." autorisée
Verbes HTTPSeulement GET, POST
Taille des requêtesmaxAllowedContentLength=65536
TLSTLS 1.2/1.3 uniquement, suites fortes
IP allow‑listipSecurity allowUnlisted=false + adresses autorisées
Journaux & alertesLogs IIS + journal Online Responder surveillés
Mises à jourWindows & 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.

Sommaire