Il se peut que vous ayez un jour besoin, comme ce fut le cas pour moi aujourd’hui, de :

  • Créer un service WCF (facile)
  • Le publier sur un IIS 7 (facile aussi)
  • Rendre les services accessibles par https (mhhh...)
  • Qu’ils soient accessibles par un site avec un binding précis (sur un sous-domaine particulier)
  • Utiliser un certificat émis par le serveur lui-même (no comment)

Host name Binding et HTTPS

Il faut déjà savoir que host name binding et HTTPS ne font pas bon ménage, pour une raison assez logique : étant donné que l’entête http est chiffrée lors d’un échange HTTPS, du coup l’information sur l’host interrogé par le client l’est aussi. Il est donc impossible de savoir vers quel site la requête doit être renvoyée sans déchiffrer l’entête. Sauf que chacun des sites peut avoir un certificat différent pour déchiffrer l’entête. Mais on ne sait pas quel certificat utiliser sans avoir lu l’entête HTTP, etc.

Donc l’interface de IIS 7 ne permet tout simplement pas d’indiquer un host name lorsque l’on ajoute un binding HTTPS :

Add Https Binding

Cependant, il peut y avoir des cas où c’est le même certificat qui va servir pour toutes les requêtes. Dans un tel cas IIS n’aurait qu’un certificat à utiliser, donc il pourrait utiliser le seul certificat déclaré pour déchiffrer les entêtes et faire son “aiguillage”. Sauf que non.

Host name Binding et WCF

Là où cela devient drôle, c’est lorsque WCF se joint à la partie. En effet, celui-ci se base sur l’host name pour renvoyer l’adresse à interroger dans le contrat WSDL. Si votre service nécessite l'utilisation de HTTPS, le contrat renverra donc une url de la forme suivante :

<soap:address location="https://mymachine/Service.svc/Soap"/>

Etant donné que IIS ne fournir aucune information sur le host name, WCF renvoie le nom de la machine comme adresse à interroger. Un client se basant sur le contrat WSDL pour déterminer l'url du service n'arrivera pas à accéder à votre serveur si celui-ci se trouve sur Internet.

La solution

Trois outils sont nécessaires pour réussir à configurer correctement IIS : appcmd, netsh et SelfSSL

  • Le premier permet d’administrer la metabase IIS et de passer outre certaines restrictions de l’interface. Il est disponible dans le répertoire %systemroot%\System32\inetsrv
  • Le second permet d’affecter des certificats SLL sur un ensemble application/port/binding (l’outil de configuration IIS manipule aussi netsh en fait).
  • SelfSLL est disponible dans IIS 6.0 Resource Kit Tools (mais aussi directement via un lien du post de Rob Bagby dont il est question plus loin).

Dans mon exemple, j'utiliserai les postulats suivants :

  • Le nom de la machine est "mymachine"
  • L'adresse du site sur laquelle on souhaite exposer le service est www.example.com
  • L'identifiant numérique du site sous IIS est 2 (colonne ID sous IIS Manager)
  • Le nom du site sous IIS est My Site (colonne Name sous IIS Manager)

1ère étape : génération du certificat auto-signé

Premier problème : la génération d’un certificat à l’aide de IIS Manager utilise le nom de la machine comme "Issued To" et ne permet pas de le changer.

La seule astuce trouvée consiste à utiliser l’application SelfSSL, qui permet de générer un certificat auto-signé en permettant de spécifier la valeur du champ CN.

Vous trouverez les étapes nécessaires décrites sur le blog de Rob Bagby, mais en gros la commande ressemblera à ça :

SelfSSL.exe /N:CN=www.example.com /V:1000 /S:SiteId (où SiteId vaut 2 dans notre exemple)

Vous obtenez donc un certificat qui sera installé dans les certificats du serveur (visibles à la racine de IIS Manager, cf. blog de Rob Bagby).

Si vous pensez que cela suffira, ce n’est pas le cas. Certes, cela vous permet d’accéder à votre site en https sans recevoir une erreur indiquant que le site interrogé ne correspond pas au site désigné par le certficat, mais WCF continue de renvoyer l’adresse de la machine comme adresse SOAP à interroger.

Note : MakeCert, fourni avec Visual Studio, semble aussi permettre la génération de certficats auto-signés avec un CN personnalisé.

2ème étape : Récupération des informations de binding sur le certificat

Pour une étape ultérieure, il va nous falloir connaître l’idenfiant de l’application IIS ainsi que la signature SHA du certificat.

Pour cela, il vous faut tout d’abord assigner votre certificat SSL auto-signé sur l’un de vos sites (temporairement), ensuite, exécutez en ligne de commande "netsh http show sslcert".

Netsh Http Show SSLCert

Le programme vous renverra 2 informations intéressantes :

  • Certificate Hash, ici "079…"
  • Application Id, ici "{4dc...}"

Notez ces informations puis supprimez votre binding IIS.

3ème étape : Création du binding IIS HTTPS avec host name

Pour pouvoir forcer la création d’un binding HTTPS avec le certificat créé précédement ET le host name de notre adresse publique, il nous faut utiliser appcmd, comme expliqué sur cet autre blog.

La commande ressemblera à :

appcmd set site /site.name:"MySite" /+bindings.[protocol='https',bindingInformation='*:443:www.example.com']

La partie que vous devez remplacer sera "MySite", à remplacer par le nom de votre site sous IIS, et www.example.com à remplacer par l’url de votre site web https.

Pour vérifier si tout s’est bien déroulé, rendez-vous sur votre site IIS et vérifiez qu'un binding HTTPS a été ajouté. Normalement, la partie host name devrait être remplie avec l'adresse que vous avez saisi. Surtout ne modifiez pas le binding par IIS Manager, celui-ci supprimera les informations sur le host name.

Il ne reste qu'un détail à régler. En l'état, le site n'est pas encore accessible en HTTPS. En effet, le fait d'ajouter le binding à la main via appcmd ne rattache pas le certificat au binding (on peut le voir en faisant "Edit" sur le binding : aucun certificat n'est sélectionné, ou par "netsh http show sslcert" qui ne renvoie aucun certificat).

Il va falloir le faire à la main à l'aide d'une dernière commande.

4ème étape : Ajout du certificat sur le binding

Pour cette dernière étape, il va falloir utiliser la commande netsh avec les options suivantes :

netsh http add sslcert ipport=0.0.0.0:443 certhash=<Certificate Hash> appid=<Application Id>

Remplacez les deux valeurs par celles que vous aviez relevé lors de l'étape 2.

Une fois toutes les opérations effectuées, accédez à votre contrat WSDL, l'attribut "location" devrait désormais valoir https://www.example.com/Service.svc/Soap.

Références

Laissez un commentaire