WebSocket API & Protocole
Le handshake
Objectifs
La finalité première de la phase de handshake est d'assurer l'initialisation de la communication entre le client et le serveur.
Elle se compose d'un échange HTTP (une requête et une réponse) un peu particulier et se conclu par l'établissement de la connexion client/serveur via WebSocket.
Nous verrons dans la prochaine partie les entêtes composants cet échange, mais c'est par un Upgrade (entête Upgrade) de la connexion que se fait la demande de connexion.
Bien entendu c'est toujours le client qui est à l'origine de la demande d'établissement de la communication, c'est donc lui qui initie le handshake.
Puis comme il a été dit précédemment cette phase de handshake permet d'assurer une compatiblité avec les infrastructures telles que les proxy et firewall et permet aussi
d'utiliser les mêmes ports que HTTP.
Fonctionnement
Le fonctionnement décrit ci-dessous est celui décrit dans le draft: draft-ietf-hybi-thewebsocketprotocol-03. Depuis le 25 février une nouvelle version du draft (version 06) est disponible.
Le handshake commence par une requête de la part du serveur:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Origin: http://example.com
^n:ds[4U
Connection et Upgrade : C'est via une requête HTTP que l'on va initialiser la communication. Mais cette communication va se faire au travers d'un autre protocole, WebSocket, c'est ce que vont indiquer
ces deux entêtes.
Host : Il permet deux choses. D'abord il permet de servir plusieurs domaines avec une même adresse IP. Ensuite il protège de certains types d'attaques (DNS rebinding par exemple).
Sec-WebSocket-Key1 et Sec-WebSocket-Key2 : Nous verrons plus en aval comment sont utilisées les valeurs de ces entêtes par le serveur. Leur rôle principal est d'assurer le cleint que le serveur est un serveur WebSocket valide.
Sec-websocket-protocol : Websocket a été pensée pour pouvoir etre utilisée si on le souhaite avec une surcouche protocolaire applicative.
Cette surcouche peut etre utilisée par exemple pour préciser le format de données dans les messages, ça peut-être JSON, XML, CSV.
Origin : Grâce à cette entête le serveur peut choisir de ne pas accepter une demande d'un client si l'origine lui est inconnue.
8 derniers octets : Ces octets et les valeurs de Sec-WebSocket-Key1 et Sec-WebSocket-Key2 vont être utilisé par le serveur pour calculer un challenge (le checksum), cette partie est expliquée plus bas.
Maintenant nous allons nous intéresser à la réponse du serveur:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-
Connection et Upgrade : Présents dans la réponse pour des raisons de compatibilité.
Sec-WebSocket-Location : Mettre d'accord le client et le serveur sur la machine (host) utilisée.
Sec-WebSocket-Origin : Le serveur précise avec quelle origine il a accepté la demande du client.
Sec-WebSocket-Protocol : Le serveur précise avec quel sous protocole il souhaite intéragir avec le client.
Le checksum : Le serveur calcul un challenge pour prouver au client qu'il est bien un serveur WebSocket valide.
Pour terminer, nous allons voir comment est calculé le checksum renvoyé au client:
- Le serveur récupère les nombres contenus dans les clés Sec-WebSocket-Key1 et Sec-WebSocket-Key2.
- Chaque nombre est ensuite divisé par le nombre d'espace de chaque clef.
- Les deux résultats sont mis sous format binaire de 32 bits et concaténés avec les 8 derniers octets de la requête.
- Puis le serveur applique un hashage md5 sur le résultat et ce dernier est envoyé au client dans la réponse HTTP.