HTTP/2
HTTP/2[1] (Protocolo de Transferencia de Hipertexto, versión 2) es un protocolo de red utilizado por la World Wide Web que llega con el objetivo de actualizar el protocolo HTTP/1.1, con el que es compatible.
Protocolo de Transferencia de Hipertexto 2.0 (HTTP) | ||||||||
---|---|---|---|---|---|---|---|---|
Familia | Familia de protocolos de Internet | |||||||
Función | Transferencia de hipertexto | |||||||
Última versión | 2.0 | |||||||
Ubicación en la pila de protocolos | ||||||||
| ||||||||
Estándares | ||||||||
RFC 1945 (HTTP/1.0, 1996) RFC 2616 (HTTP/1.1, 1999) RFC 7540 (HTTP/2.0, 2015) | ||||||||
HTTP 2.0 no modifica la semántica de aplicación de Http. Todos los conceptos básicos, tales como los métodos HTTP, códigos de estado, URI, y campos de cabecera, se mantienen sin cambios; sin embargo, HTTP 2.0 introduce innumerables mejoras como el uso de una única conexión, la compresión de cabeceras o el servicio ‘server push’.
Inicialmente surgió el protocolo SPDY para implementar HTTP cuyo objetivo era reducir la latencia (suma de retardos temporales dentro de una red). Este nuevo protocolo logró mejorar hasta en un 60 por ciento la velocidad de carga de las páginas web estándar y hasta en un 55 por ciento las conexiones protegidas con cifrado [2][3] SSL.
A principios del año 2012 basándose en el proyecto SPDY, el IETF (Internet Engineering Task Force) creó un equipo para el desarrollo de un nuevo protocolo llamado HTTP 2.0 o HTTP/2. El borrador inicial de HTTP/2 se publicó en noviembre de 2012 pero no es hasta el año 2015 cuando los navegadores comienzan a utilizarlo como soporte.
SPDY se abandona en favor de HTTP 2.0 [4] debido a que la mayoría de ventajas que aporta SPDY también se encuentran en HTTP 2.0. HTTP/2 es más rápido que SPDY, en parte debido a que sus mensajes de solicitud son más pequeños gracias a la compresión de cabeceras HPACK.
Características del protocolo
HTTP/2 llega con el objetivo de mejorar las carencias existentes en las anteriores versiones. Sus características son las siguientes:
Una única conexión
Con HTTP/1.x para cargar cualquier contenido web es necesario el uso de múltiples conexiones TCP simultáneas para poder descargar todos los elementos de dicha web. En cambio, HTTP 2.0 utiliza una única conexión para ofrecer múltiples solicitudes y respuestas en paralelo. Teniendo en cuenta que cada página web puede contener objetos HTML, CSS, JavaScript, imágenes, vídeo… la diferencia de trabajo entre utilizar una única conexión o utilizar varias es elevada.
Eliminación de información redundante
Otro cambio de gran relevancia en HTTP 2.0 es la eliminación de información redundante cuyo objetivo es evitar el envío de datos repetidos durante una misma conexión, así conseguiremos que se consuman menos recursos, obteniendo una menor latencia.
Multiplexación
Con HTTP/1.1 el navegador envía una petición y debe esperar la respuesta del servidor para poder enviar la siguiente solicitud. El problema es que las webs modernas suelen tener más de 100 objetos, por lo que el retardo es grande. La solución que introduce HTTP 2.0 a este problema es la denominada Multiplexación.
La multiplexación permite enviar y recibir varios mensajes al mismo tiempo optimizando la comunicación. Con la multiplexación se consigue reducir el número de conexiones mejorando considerablemente la velocidad de carga y disminuyendo la congestión de los servidores web.
HTTP 2.0 es un protocolo binario
La ventaja que tiene el uso de un protocolo binario es la facilidad para encontrar el comienzo y el final de cada frame, que es algo realmente complicado en cualquier protocolo de texto. Además, los protocolos binarios son mucho más simples y por lo tanto son menos propensos a tener errores que los protocolos de texto utilizados por las versiones anteriores a HTTP 2.0.
Servicio 'server push'
El servicio “server push”[5] también conocido como “cache push”, se basa en estimaciones para que el servidor sea capaz de enviar información al usuario antes de que éste la solicite para que la información esté disponible de forma inmediata.
La forma de actuar del servidor es enviar varias respuestas a una única solicitud del cliente, es decir, además de la respuesta a la solicitud original, el servidor puede enviar recursos adicionales. Esto es así porque una página web está formada por decenas de archivos referenciados que gracias al servicio “server push” el servidor envía tras recibir una única solicitud ahorrando mensajes innecesarios.
HTTP 2.0 contiene un campo denominado ‘Ajustes’ con el que el cliente puede indicar si desea o no obtener los recursos que proporciona el servicio ‘server push’.
Compresión de cabeceras para transmitir menos información
Con las versiones anteriores a HTTP 2.0, las cabeceras de los mensajes de solicitud eran de texto claro, sin ningún tipo de compresión. El problema aparece como consecuencia del incremento de tamaño que sufren estas cabeceras por los user-agent de los navegadores, al uso de cookies (también deben aparecer en los mensajes de solicitud), etc. Además, cuando HTTP/1.1 envía una petición, debe esperar la respuesta del servidor para poder enviar la siguiente solicitud, aumentado mucho el retardo sufrido.
Asimismo, hay que tener en cuenta que cuando un cliente hace numerosas peticiones a un mismo servidor, los encabezamientos apenas cambian unos de otros, por lo que se envía mucha información redundante.
Con HTTP 2.0 las cabeceras experimentan compresiones, con lo que se obtienen mejores tiempos de respuesta y también se mejora la eficiencia (sobre todo en terminales móviles). El algoritmo empleado para realizar la compresión de cabeceras es HPACK.[6] HPACK es un algoritmo simple y poco flexible que se basa en eliminar campos de cabecera redundantes, además de prevenir posibles vulnerabilidades.
Priorización de flujos
Un mensaje HTTP se puede dividir en múltiples fragmentos en su recorrido desde el cliente hasta el servidor o desde servidor al cliente. El orden y el retardo con el que estas tramas llegan a su destino son fundamentales, dado que algunos objetos de las webs son más importantes que otros. Nos interesará que los objetos más relevantes cuenten con algún tipo de prioridad.
Para poder ‘controlar’ la prioridad que tienen las tramas, HTTP 2.0 permite asignar a cada flujo un peso (entre 1 y 256) y una dependencia. Debemos ser conscientes de que las prioridades pueden variar durante la ejecución.
Con las prioridades y la dependencia se hace un árbol de prioridades.
Ejemplo; Si A tiene un peso de 12 y B tiene un peso de 4: A dispondrá del 75 % de los recursos y B se quedará con el 25 % restante.
No requiere cifrado TLS
En HTTP/2 el uso de cifrado TLS (Transport Layer Security) es opcional. De todos modos un gran número de fabricantes de software[7] (Firefox, Internet Explorer o Google Chrome por ejemplo) ya han anunciado que sus implementaciones solo soportarán HTTP 2.0 sobre TLS usando la extensión ALPN[8] que requiere TLSv1.2 o superior.[9]
Recordemos que TLS es un protocolo criptográfico de la capa de transporte (de criptografía asimétrica), que proporciona comunicaciones seguras por la red. El uso de TLS añade un retardo adicional.
Formato de la trama
Las frames pueden tener múltiples tamaños, hasta un límite máximo de 16 kb, a no ser que el cliente y el servidor lleguen a un acuerdo para utilizar un tamaño de frame mayor, en cuyo caso el máximo tamaño al que puede llegar es de 16 MB. Pese a esta posibilidad las frames no suelen superar los 16 kb de tamaño.
Todas las frames comienzan con una cabecera de 9 octetos fijos seguidos de la carga útil de longitud variable. El formato es el siguiente:
- Length: 24 bits que indican la longitud de dicho frame sin contar los 9 bytes de la cabecera.
- Type: 8 bits que nos informan de cómo se interpreta el resto de la trama. A pesar de que hoy día hay pocos tipos de frames disponibles, los 8 bits dejan espacio para 256 formatos diferentes de frames.
- Flags: 8 bits que determinan el contenido de los flags.
- R: se trata de un bit reservado. Debe permanecer con valor ‘0’ al ser enviado y debe ser ignorado cuando se recibe.
- Stream Identifier: Se trata de un identificador de flujo de 32 bits. El bit más significativo siempre es 0.
- Payload: contiene los datos, es de longitud variable.
Códigos de errores
Los códigos de error son campos de 32 bits utilizados para notificar los distintos fallos que pueden producirse. Los códigos que pueden darse se muestran a continuación:
- NO_ERROR (0x0): La condición asociada no es el resultado de un error. Por ejemplo, podría usarse para indicar que el ordenador ha cerrado la conexión de forma inesperada.
- PROTOCOL_ERROR (0x1): Error producido en el protocolo específico.
- INTERNAL_ERROR(0x2): El punto final encontró un error interno inesperado.
- FLOW_CONTROL_ERROR (0x3): Se da cuando el punto final detecta que su par incumple el protocolo de control de flujo.
- SETTINGS_TIMEOUT (0x4): Tiene lugar cuando el punto final envía ajustes de marco, pero no recibe una respuesta a tiempo.
- STREAM_CLOSED (0x5): Cierra la secuencia actual y libera todos los recursos.
- FRAME_SIZE_ERROR (0x6): El punto final recibe una trama con un tamaño no válido.
- REFUSED_STREAM (0x7): El servidor no procesa la respuesta.
- CANCEL (0x8): Campo utilizado por el punto final para indicar que la conexión ya no es necesaria. Se termina el stream.
- COMPRESSION_ERROR (0x9): Error al realizar la compresión de cabeceras. La conexión es cerrada por un motivo poco usual.
- CONNECT_ERROR (0xa): La conexión establecida se ha cerrado de forma inesperada.
- ENHANCE_YOUR_CALM (0xb): El punto final detecta que su par está exhibiendo un comportamiento que podría generar una carga excesiva.
- INADEQUATE_SECURITY (0xc): Se activa cuando no se cumplen los requisitos mínimos de seguridad.
- HTTP_1_1_REQUIRED (0xd): El punto final requiere que se utilice HTTP versión 1.1 en lugar de usarse HTTP versión 2.0.
Definiciones de la frame
Cabeceras
Las cabeceras se utilizan para iniciar un flujo, y pueden contener los siguientes campos:
- Pad Length (8 bits): contiene la longitud de la trama. Se mide en octetos.
- E (1bit): Bandera de un bit. Depende de la prioridad.
- Stream Dependency (31 bits): se trata de un identificador de flujo.
- Weight (8 bits): representa el nivel de prioridad, su valor puede variar de 1 a 256.
- Header Block Fragment: es un fragmento del bloque de cabecera.
- Padding: octetos para padding (tiene un tamaño variable).
- Quedan definidos los siguientes indicadores:
- END_STREAM (0x1): El último mensaje en una secuencia utiliza este campo para indicar el final de la transferencia de datos.
- END_HEADERS (0x4): Campo que indica el final de las cabecera. En este caso la trama contiene un bloque de cabecera completo.
- PADDED (0x8): Cuando se establece, indica que el campo de Longitud Pad y cualquier tipo de relleno están presentes.
- PRIORITY (0x20): Con este campo se puede indicar al servidor la prioridad que tiene el mensaje. Podrá ser modificada durante la ejecución.
Prioridad
Las frames utilizan campos de prioridad (type = 0x2) para comparar distintos tipos de tramas dando preferencias a unas respecto de otras.
Esta prioridad puede ser modificada en cualquier momento, sea cual sea el estado de la frame, pero es aconsejable que durante el intercambio de cabeceras no sea modificado su valor.
En el caso en el que, por cualquier motivo, se reciba una prioridad sin contenido se produce el siguiente error: ‘Protocol error’.
En el caso en el que se reciban en primer lugar los contenidos, y en segundo lugar sus prioridades, estás no se tendrán en cuenta a la hora de procesar las tramas.
Tipos de stream
Las stream son secuencias de frames independientes y bidireccionales que se intercambian entre cliente y servidor durante una conexión HTTP 2.0. Una única conexión HTTP/2 puede contener múltiples streams activos de forma simultánea que serán procesados en el destino en el orden en el que fueron enviados.
Los puntos finales no se coordinan en la creación de flujos, pero cabe destacar que los streams pueden ser cerrados por cualquiera de los puntos finales de la comunicación.
Todos los stream contienen un identificador (un número entero) asignado por el origen y parten de un estado ‘inactivo’. En este estado pueden ocurrir los siguientes sucesos:
- Si se envían o reciben cabeceras, el stream pasa al estado ‘abierto’ y, en algunos casos, puede pasar a un estado ‘medio-cerrado’.
- Si se produce un envío de ‘push_promise’ el stream pasa a un estado ‘reservado (local)’.
- Cuando se recibe el envío ‘push_promise’ se pasa a un estado ‘reservado (a distancia)’.
Intercambio de mensajes con HTTP 2.0
HTTP 2.0 está destinada a ser lo más compatible posible con los usos actuales de HTTP. Esto significa que, desde la perspectiva de aplicación, las características del protocolo apenas sufren cambios.
Cada mensaje de solicitud o respuesta de HTTP 2.0 consta de:
- Una o varias cabeceras que deben ser enviadas al comienzo de la comunicación, es lo primero que en ser enviado. Son tramas de información.
- En segundo lugar debe enviarse el contenido del mensaje (payload).
- Por último se envían los posibles campos de cola (por ejemplo el campo padding).
Seguridad
Padding como mecanismo de seguridad
En HTTP/2 el padding puede ser utilizado para ocultar el tamaño exacto del contenido de la trama, con la idea de ocultar la compresión de los datos más sensibles.
Debe tomarse en consideración que el uso del padding de forma redundante puede llegar a ser contraproducente, además de que su uso, en el mejor de los casos, sólo hace que sea más complicado para un atacante hacerse con la información, pero en ningún caso consigue hacerlo inevitable.
Vulnerable a un ataque de denegación del servicio
En HTTP 2.0 se permiten múltiples intercambios de stream por cada conexión TCP. El problema que puede darse es de denegación del servicio (sobrecarga de los recursos computacionales del sistema), debido a que se permite un total de 2^31 intercambios de stream por conexión.
Un atacante que quisiera sobrecargar la red podría abrir múltiples conexiones en las que se intercambiasen numerosos stream. Por este motivo se debe limitar el intercambio de stream por conexión.
Vulnerabilidad por el uso del servicio server push
Uno de los posibles problemas que nos podemos encontrar en HTTP 2.0 es debido al uso del servicio ‘server push’.[10]
Un atacante podría aprovechar las múltiples respuestas que realiza el servidor a una única solicitud, el uso de memorias caché… con el fin de poder acceder a contenidos web que fueron de uso público y ahora son de uso privado (que requieren de privilegios para poder ser accedidos).
Implementaciones del protocolo
A pesar de que el borrador del protocolo se proporcionó a la IETF el 11 de febrero de 2015, algunos navegadores ya lo han implementado, al igual que algunos servidores. Por poner un ejemplo, Google comenzó en abril de 2014 a ofrecer servicios HTTP 2.0 en unos pocos servidores a modo de prueba.
Las últimas versiones de los navegadores más actualizados (desde las versiones de Firefox v36, Chrome v40 y Explorer v11) ya son compatibles con este nuevo protocolo. En Google Chrome y en Firefox se ha decidido que el protocolo HTTP 2.0 sólo sea utilizado en conexiones criptografiadas.
En países como Reino Unido (53,1%), Alemania (58,02%) o Canadá (50,35%)[7] las peticiones con HTTP 2.0 ya superan a las peticiones que usan los protocolos anteriores. Estos datos demuestran cómo HTTP 2.0 se empieza a afianzar pese a ser un protocolo tan reciente.
Referencias
- «RFC de HTTP/2».
- «Latencia con SPDY».
- «Ventajas con SPDY».
- «Abandono de SPDY».
- «servicio 'server push'».
- «HPACK RFC».
- «HTTP/2 Statistics - KeyCDN Report on HTTP/2 Distribution». KeyCDN (en inglés). Consultado el 11 de octubre de 2019.
- «RFC 7301 - Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension». IETF. July 2014.
- Belshe, M.; Peon, R.; Thomson, M. «Hypertext Transfer Protocol Version 2, Use of TLS Features». Archivado desde el original el 15 de julio de 2013. Consultado el 10 de febrero de 2015.
- «Vulnerabilidad por 'Server push'».
Enlaces externos
- «HTTP/2 Frequently Asked Questions».
- «HTTP/2».
- «Características HTTP/2». Archivado desde el original el 27 de noviembre de 2015. Consultado el 27 de noviembre de 2015.
- «Web más rápido con HTTP/2».
- «Visión general de HTTP/2».
- «Protocolo HTTP/2». Archivado desde el original el 25 de noviembre de 2015. Consultado el 27 de noviembre de 2015.
- Prueba de compatibilidad HTTP/2