Depuis le 15 Mai 2015 - date de la ratification de la RFC 7540 - HTTP/2 est officiellement devenu le nouveau standard du Web.  Il faut dire qu’après 16 ans de bons et loyaux services remplis par HTTP1.1, cette mise à jour était très attendue pour répondre aux besoins du web d’aujourd’hui.

En effet, les dernières tendances montraient un accroissement continu du nombre et de la taille des requêtes web. En moyenne, une page Web pèse 2Mo et contient 80 éléments !

 

 

Temps de chargement: quand tu nous tiens !

Qui n’a pas pesté contre les pages web qui mettent une éternité à se charger ? Le dernier speed index montrait un temps de chargement moyen de l’ordre de 11s pour les 40 ténors du web et du e-commerce en France.

HTTP1.1 est très sensible à la latence réseau et c’est justement cette latence –plus que la bande passante- qui influe sur les temps de chargement.

Un autre point faible d’HTTP1.1 affectant le temps de chargement est le traitement des requêtes qui se fait séquentiellement en FIFO: le navigateur est obligé d’attendre la réponse du serveur Web avant de pouvoir soumettre une autre requête. Bien sûr, le pipelining a amélioré –partiellement- les choses en permettant de lancer plusieurs requêtes en même temps mais cela n’empêchait pas qu’une requête demandant un traitement long puisse bloquer la file d’attente (Head of Line Blocking).

HTTP1.1 avait aussi une fâcheuse tendance à consommer les connections TCP. Alors que les navigateurs sont limités à 6-8 connections TCP par hostname cible, une des techniques pour améliorer les performances, le sharding (où le découpage de la ressource Web sur plusieurs hosts cibles) a permis d’outrepasser la limitation des 6 connections TCP en parallélisant en quelque sorte le chargement d’une page web, mais au prix d’une explosion du nombre de connections TCP.

Aujourd'hui, une page web requiert du navigateur web d’établir en moyenne 38 connections TCP !

 

Ce qui ne change pas avec HTTP/2

HTTP/2 a été conçu pour ne pas impacter le Web, de faire en sorte qu’il puisse prendre en charge nativement des clients HTTP1.1 et de proxifier les serveurs en HTTP1.1. Il est ainsi complètement retro-compatible avec HTTP1.1.

Cela veut dire que :

- Les méthodes HTTP1.1 restent les mêmes: GET, POST, PUT, HEAD, TRACE, DELETE, CONNECT …

- Les schémas URI http:// et https:// restent inchangés.

- Codes de statuts, les entêtes, la négociation restent le mêmes.

 

Ce qui change

Par rapport à HTTP1.1, HTTP/2 décorrèle le protocole lui même de la couche de transport TCP, en introduisant une couche d’abstraction qui a pour objectif d’optimiser le transport des sémantiques HTTP. L’objectif étant de réduire le nombre d’allers retours, la taille des entêtes échangés, de lever le problème du Head of Line Blocking…bref, de faire un meilleur usage du réseau.

L’autre objectif d’HTTP/2 est de normaliser les extensions optionnelles de HTTP1.1 telles que le pipelining, l’inlining, le sharding, la concaténation. Il faut dire que les 4 façons normalisées de parser un message HTTP1.1 ou les extensions optionnelles -pas toujours bien ou toutes implémentées- pouvaient poser des problèmes d’interopérabilité. Par exemple, le pipelining est désactivé par défaut sur les navigateurs web afin de garantir une interopérabilité large.

L’approche choisie sur HTTP/2 est à l’opposé de ce qui a été fait sur HTTP1.1: il n’y a plus d’options, ni d’extensions. Les spécifications sont obligatoires et le protocole est désormais binaire (fini au passage le telnet sur le port 80), et donc plus compact et plus facile à décoder.

 

Multiplexage

C’est la nouveauté phare du protocole. HTTP/2 utilise la notion de trames binaires et permet l’envoi des requêtes et la réception des réponses en parallèle et indépendamment l’une de l’autre, sur une seule connexion TCP. Une réponse qui requiert du temps de traitement ne bloque plus les autres.

Cela se fait via des “streams” qui sont des séquences de trames bi-directionnelles échangés entre le client et le serveur.

Une connexion http/2 peut contenir une centaines de streams ouverts sur une seule connexion TCP et chaque stream possède une notion de priorité qui peut être modifiée dynamiquement par le navigateur web.

 

Compression d’entêtes

 Avec HTTP1.1, il fallait en moyenne 7 à 8 échanges TCP pour charger les entêtes d’une page web contenant 80 objets. Les entêtes étant souvent répétitifs et de plus en plus volumineux, la compression est un bon moyen de réduire les échanges.

Pour HTTP/2, HPACK a été développé pour être plus rapide que deflate ou gzip, autorisant la ré-indexation par un proxy et surtout non vulnérable à l’attaque CRIME et BREACH qui touchaient la compression dans TLS et SPDY.

Avec HTTP/2, les entêtes vont regroupés et servis en une seule fois via une trame et un stream spécifiques.

Pour tout ce qui est payload HTTP, le protocole proscrit l’utilisation de la compression (y compris celle de TLS) dès qu’il s’agit de confidentialité (secure channel) et que la source de données n’est pas de confiance.

Server Push

Sur HTTP 1.1, le navigateur récupère les données du serveur en lui demandant explicitement la ressource souhaitée. au fur et à mesure du chargement de la ressource HTTP, le navigateur va parser le DOM et demander au serveur de lui fournir les objets associés (CSS, JS, images, etc). 

Avec le Server Push, lorsque le navigateur va demander au serveur la ressource HTTP (par exemple /default.html), le serveur va bien sûr servir la première requête mais il va aussi lui pousser préemptivement tous les objets associés et qui seront placés dans le cache du navigateur (ils faut quand même que les objets servis soient “cacheables”). Quand celui-ci devra faire le rendu de la page, les objets étant déjà présent dans le cache, le temps de d’affichage en sera accéléré.

Le Server Push est une fonctionnalité activée par défaut coté serveur mais qui reste désactivable et contrôlable par le navigateur. Lors de l’établissement de la connexion, si le navigateur envoi au serveur le paramètre SETTINGS_ENABLE_PUSH avec la valeur 0, le serveur s’abstient de pousser les objets et bascule sur l’ancien mode où la navigateur va récupérer objet par objet (client pull). Même si le Server Push est actif entre le serveur et le navigateur, celui-ci peut aussi à tout moment envoyer au serveur une trame RST_STREAM pour lui dire d’arrêter de pousser du contenu.

 

Chiffrement en TLS 

HTTP/2 prévoit deux mode de transports:  HTTP/2 sur TLS (h2) pour les URIs en https:// et HTTP/2 sur TCP (h2c) pour les URIs en http://.

Concernant les URI http:// (en clair sur le port 80) et après des débats houleux au sein du groupe de travail, le protocole prévoit un mécanisme où le client envoie au serveur une requête avec l’entête Upgrade et la clé h2c. Si le serveur parle HTTP/2 en clair, il envoie au client une réponse “101 Switching” et bascule sur HTTP/2. 

Même si la RFC ne l’impose pas, les implémentations actuelles d’HTTP/2 sur les navigateurs et les serveurs web ne se font que sur du TLS (l’exception est avec les implémentations de Curl et de nghttp2)

Dans le mode h2 (chiffré), HTTP/2 impose un profil TLS dont les caractéristiques sont les suivantes:

- TLS en version 1.2 à minima

- une liste noire (blacklist) de suites de chiffrement à ne pas utiliser (en particulier, les algorithmes d’échange de clés qui sont non éphémères sont exclus)

- les extensions SNI et ALPN doivent utilisées. Le protocole ALPN (Application Layer Protocol Negociation) normalisé pour HTTP/2 remplace le NPN de SPDY et permet de négocier le protocole qui va être utilisé au dessus de TLS. La différence entre ALPN et NPN est qu’avec ALPN, c’est le serveur qui choisit le protocole utilisé parmi une liste de protocoles proposés par le client.

- la compression TLS doit être désactivée (à cause des attaques BREACH et  CRIME)

- la renégociation TLS doit être désactivée

- les échanges de clés doivent se faire en crypto éphémère: DHE en 2048 bits minimum et ECDHE en 224 bits minimum.

- le socle commun à respecter est : TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 avec le P-256 Elliptic Curve

 

 

Support de HTTP/2 sur BIG-IP

Le F5 BIG-IP a été le premier ADC du marché à prendre en charge HTTP/2 et la version 11.6 sorti en septembre 2014 supportait déjà le draft 14 en mode expérimental.

Le support d’HTTP/2 dans sa spécification finale est pris en charge dans la version 12.0 de TMOS.

 

 

 

Démonstration

Une vidéo de démonstration de HTTP/2 sur BIG-IP vaut mieux qu’un long discours.

On y voit une page web contenant 100 objets mettant 17 secondes à se charger en HTTP1.1 et seulement 6 secondes de chargement en HTTP/2  ...