Configuration des serveurs HTTPS
Pour configurer un serveur HTTPS, le paramètre ssl doit être activé sur les sockets d'écoute dans le bloc serveur, et les emplacements du certificat du serveur et des fichiers de clef privée doivent être spécifiés :
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ... } |
Le certificat du serveur est une entité publique. Il est envoyé à chaque client se connectant au serveur. La clef privée est une entité sécurisée et doit être stockée dans un fichier à accès restreint. Cependant, elle doit être lisible par le processus maître de nginx. La clef privée peut également être entreposée dans le même fichier que le certificat :
ssl_certificate www.example.com.cert; ssl_certificate_key www.example.com.cert; |
dans ce cas, les droits d'accès au fichier doivent également être restreints. Bien que le certificat et la clef soient entreposés dans un seul fichier, seul le certificat est envoyé à un client.
Les directives ssl_protocols et ssl_ciphers peuvent être utilisées pour limiter les connexions afin d'inclure uniquement les versions et les chiffrements forts de SSL/TLS. Par défaut, nginx utilise «ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3» et «ssl_ciphers HIGH:!aNULL:!MD5», donc les configurer explicitement n'est généralement pas nécessaire. Notez que les valeurs par défaut de ces directives ont été modifiées plusieurs fois.
Optimisation du serveur HTTPS
Les opérations SSL consomment des ressources de microprocesseur supplémentaires. Sur les systèmes multiprocesseurs, plusieurs processus de travail doivent être exécutés, au moins autant que le nombre de coeurs microprocesseurs disponibles. L'opération la plus gourmande en ressources microprocesseurs est la négociation SSL. Il existe deux façons de minimiser le nombre de ces opérations par client : la première consiste à activer les connexions keepalive pour envoyer plusieurs requêtes via une connexion et la seconde consiste à réutiliser les paramètres de session SSL pour éviter les échanges SSL pour les connexions parallèles et ultérieures. Les sessions sont entreposées dans un cache de session SSL partagé entre les workers et configuré par la directive ssl_session_cache. Un mégaoctet du cache contient environ 4 000 sessions. Le délai d'expiration du cache par défaut est de 5 minutes. Il peut être augmenté en utilisant la directive ssl_session_timeout. Voici un exemple de configuration optimisée pour un système multicoeur avec un cache de session partagé de 10 mégaoctets :
worker_processes auto; http { ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; server { listen 443 ssl; server_name www.example.com; keepalive_timeout 70; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ... |
Chaînes de certificats SSL
Certains navigateurs peuvent se plaindre d'un certificat signé par une autorité de certification bien connue, tandis que d'autres navigateurs peuvent accepter le certificat sans problème. Cela se produit parce que l'autorité émettrice a signé le certificat du serveur à l'aide d'un certificat intermédiaire n'étant pas présent dans la base de certificats des autorités de certification de confiance bien connues qui est distribuée avec un navigateur particulier. Dans ce cas, l'autorité fournit un ensemble de certificats chaînés devant être concaténés au certificat du serveur signé. Le certificat du serveur doit apparaître avant les certificats chaînés dans le fichier combiné :
cat www.example.com.crt bundle.crt > www.example.com.chained.crt |
Le fichier résultant doit être utilisé dans la directive ssl_certificate :
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.chained.crt; ssl_certificate_key www.example.com.key; ... } |
Si le certificat du serveur et le bundle ont été concaténés dans le mauvais ordre, nginx ne démarrera pas et affichera le message d'erreur :
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed (SSL: error:0B080074:x509 certificate routines: X509_check_private_key:key values mismatch) |
car nginx a essayé d'utiliser la clef privée avec le premier certificat du bundle au lieu du certificat du serveur.
Les navigateurs stockent généralement les certificats intermédiaires qu'ils reçoivent et étant signés par des autorités de confiance, de sorte que les navigateurs utilisés activement peuvent déjà avoir les certificats intermédiaires requis et ne pas se plaindre d'un certificat envoyé sans bundle chaîné. Pour garantir que le serveur envoie la chaîne de certificats complète, l'utilitaire de ligne de commande openssl peut être utilisé, par exemple :
openssl s_client -connect www.godaddy.com:443 |
on obtiendra le résultat semblable suivant :
... Certificate chain 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.7.1.4.1.311.70.2.1.3=US /1.3.7.1.4.1.311.70.2.1.2=AZ/O=GoDaddy.com, Inc /OU=MIS Department/CN=www.GoDaddy.com /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b) i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 i:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority 2 s:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority i:/L=ValiCert Validation Network/O=ValiCert, Inc. /OU=ValiCert Class 2 Policy Validation Authority /CN=http://www.valicert.com//emailAddress=info@valicert.com ... |
Lors du test de configurations avec SNI, il est important de spécifier l'option -servername car openssl n'utilise pas SNI par défaut.
Dans cet exemple, le sujet («s») du certificat de serveur www.GoDaddy.com numéro 0 est signé par un émetteur («i») étant lui-même le sujet du certificat numéro 1, étant signé par un émetteur étant lui-même le sujet du certificat numéro 2, étant signé par l'émetteur bien connu ValiCert, Inc. dont le certificat est entreposé dans la base de certificats intégrée des navigateurs (se trouvant dans la maison que Jack a construite).
Si aucun ensemble de certificats n'a été ajouté, seul le certificat de serveur numéro 0 sera affiché.
Un seul serveur HTTP/HTTPS
Il est possible de configurer un seul serveur gérant à la fois les requêtes HTTP et HTTPS :
server { listen 80; listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ... } |
Avant la version 0.7.14, SSL ne pouvait pas être activé de manière sélective pour des sockets d'écoute individuels, comme indiqué ci-dessus. SSL ne pouvait être activé que pour l'ensemble du serveur à l'aide de la directive ssl, ce qui rendait impossible la configuration d'un seul serveur HTTP/HTTPS. Le paramètre ssl de la directive listen a été ajouté pour résoudre ce problème. L'utilisation de la directive ssl dans les versions modernes est donc déconseillée.
Serveurs HTTPS basés sur le nom
Un problème courant survient lors de la configuration de deux ou plusieurs serveurs HTTPS écoutant sur une seule adresse IP :
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... } |
Avec cette configuration, un navigateur reçoit le certificat du serveur par défaut, c'est-à-dire www.exemple.com, quel que soit le nom du serveur demandé. Cela est dû au comportement du protocole SSL. La connexion SSL est établie avant que le navigateur n'envoie une requête HTTP et nginx ne connaît pas le nom du serveur demandé. Par conséquent, il peut uniquement proposer le certificat du serveur par défaut.
La méthode la plus ancienne et la plus fiable pour résoudre le problème consiste à attribuer une adresse IP distincte à chaque serveur HTTPS :
server { listen 192.168.1.1:443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 192.168.1.2:443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... } |
Un certificat SSL avec plusieurs noms
Il existe d'autres méthodes permettant de partager une même adresse IP entre plusieurs serveurs HTTPS. Cependant, toutes ont leurs inconvénients. Une méthode consiste à utiliser un certificat avec plusieurs noms dans le champ de certificat SubjectAltName, par exemple, www.example.com et www.example.org. Cependant, la longueur du champ SubjectAltName est limitée.
Une autre méthode consiste à utiliser un certificat avec un nom générique, par exemple, *.example.org. Un certificat générique sécurise tous les sous-domaines du domaine spécifié, mais uniquement à un niveau. Ce certificat correspond à www.example.org, mais ne correspond pas à example.org et www.sub.example.org. Ces deux méthodes peuvent également être combinées. Un certificat peut contenir des noms exacts et génériques dans le champ SubjectAltName, par exemple, example.org et *.example.org.
Il est préférable de placer un fichier de certificat avec plusieurs noms et son fichier de clef privée au niveau de configuration http pour hériter de leur copie mémoire unique dans tous les serveurs :
ssl_certificate common.crt; ssl_certificate_key common.key; server { listen 443 ssl; server_name www.example.com; ... } server { listen 443 ssl; server_name www.example.org; ... } |
Indication du nom du serveur
Une solution plus générique pour exécuter plusieurs serveurs HTTPS sur une seule adresse IP est l'extension TLS Server Name Indication (SNI, RFC 6066), qui permet à un navigateur de transmettre un nom de serveur demandé pendant la négociation SSL et, par conséquent, le serveur saura quel certificat il doit utiliser pour la connexion. SNI est actuellement pris en charge par la plupart des navigateurs modernes, bien qu'il puisse ne pas être utilisé par certains clients anciens ou spéciaux.
Seuls les noms de domaine peuvent être transmis dans SNI, cependant certains navigateurs peuvent transmettre par erreur une adresse IP du serveur comme nom si une requête inclut une adresse IP littérale. Il ne faut pas s'y fier.
Pour utiliser SNI dans nginx, il doit être pris en charge à la fois dans la bibliothèque OpenSSL avec laquelle le binaire nginx a été construit ainsi que dans la bibliothèque à laquelle il est lié dynamiquement au moment de l'exécution. OpenSSL prend en charge SNI depuis la version 0.9.8f s'il a été construit avec l'option de configuration «--enable-tlsext». Depuis OpenSSL 0.9.8j, cette option est activée par défaut. Si nginx a été compilé avec la prise en charge SNI, alors nginx affichera ceci lorsqu'il sera exécuté avec le commutateur « -V » :
$ nginx -V ... TLS SNI support enabled ... |
Cependant, si le nginx compatible SNI est lié dynamiquement à une bibliothèque OpenSSL sans prise en charge SNI, nginx affiche l'avertissement :
- nginx a été créé avec la prise en charge SNI, mais il est désormais lié
- dynamiquement à une bibliothèque OpenSSL qui ne prend pas en charge tlsext,
- donc SNI n'est pas disponible
Compatibilité
- L'état de prise en charge SNI est indiqué par le commutateur « -V » depuis 0.8.21 et 0.7.62.
- Le paramètre ssl de la directive listen est pris en charge depuis 0.7.14. Avant 0.8.21, il ne pouvait être spécifié qu'avec le paramètre par défaut.
- SNI est pris en charge depuis 0.5.23.
- Le cache de session SSL partagé est pris en charge depuis 0.5.6.
- Version 1.23.4 et ultérieures : les protocoles SSL par défaut sont TLSv1, TLSv1.1, TLSv1.2 et TLSv1.3 (si pris en charge par la bibliothèque OpenSSL).
- Version 1.9.1 et ultérieures : les protocoles SSL par défaut sont TLSv1, TLSv1.1 et TLSv1.2 (si pris en charge par la bibliothèque OpenSSL).
- Version 0.7.65, 0.8.19 et ultérieures : les protocoles SSL par défaut sont SSLv3, TLSv1, TLSv1.1 et TLSv1.2 (si pris en charge par la bibliothèque OpenSSL).
- Version 0.7.64, 0.8.18 et antérieures : les protocoles SSL par défaut sont SSLv2, SSLv3 et TLSv1.
- Version 1.0.5 et ultérieures : les chiffrements SSL par défaut sont « HIGH:!aNULL:!MD5 ».
- Version 0.7.65, 0.8.20 et ultérieures : les chiffrements SSL par défaut sont « HIGH:!ADH:!MD5 ».
- Version 0.8.19 : les chiffrements SSL par défaut sont « ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM ».
- Version 0.7.64, 0.8.18 et antérieures : les chiffrements SSL par défaut sont «ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP».