web-dev-qa-db-fra.com

En-têtes HTTP dans l'API du client Websockets

On dirait qu'il est facile d'ajouter des en-têtes HTTP personnalisés à votre client Websocket avec n'importe quel client d'en-tête HTTP qui prend en charge cela, mais je ne trouve pas comment le faire avec l'API JSON.

Pourtant, il semble qu'il devrait y avoir un soutien ces en-têtes dans la spécification .

Quelqu'un sait-il comment y parvenir?

var ws = new WebSocket("ws://example.com/service");

Plus précisément, je dois pouvoir envoyer un en-tête d'autorisation HTTP.

158
Julien Genestoux

Mis à jour 2x

Réponse courte: Non, seuls le chemin et le champ de protocole peuvent être spécifiés.

Réponse plus longue:

JavaScript WebSockets API ne permet pas de spécifier des en-têtes supplémentaires à envoyer par le client/navigateur. Le chemin HTTP ("GET/xyz") et l'en-tête de protocole ("Sec-WebSocket-Protocol") peuvent être spécifiés dans le constructeur WebSocket.

L'en-tête Sec-WebSocket-Protocol (qui est parfois étendu pour être utilisé dans l'authentification spécifique à Websocket) est généré à partir du deuxième argument facultatif du constructeur WebSocket:

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

Les résultats ci-dessus apparaissent dans les en-têtes suivants:

Sec-WebSocket-Protocol: protocol

et

Sec-WebSocket-Protocol: protocol1, protocol2

Un modèle courant pour obtenir l’authentification/autorisation WebSocket consiste à implémenter un système de ticket dans lequel la page hébergeant le client WebSocket demande un ticket au serveur, puis transmet ce ticket lors de la configuration de la connexion WebSocket, soit dans la chaîne URL/requête, dans le champ de protocole, ou requis comme premier message une fois la connexion établie. Le serveur n'autorise ensuite la poursuite de la connexion que si le ticket est valide (existe, n'a pas déjà été utilisé, l'adresse IP du client est codée dans les correspondances de ticket, l'horodatage du ticket est récent, etc.). Voici un résumé des informations de sécurité WebSocket: https://devcenter.heroku.com/articles/websocket-security

L'authentification de base était auparavant une option, mais celle-ci est obsolète et les navigateurs modernes n'envoient pas l'en-tête, même s'il est spécifié.

Informations d'authentification de base (obsolètes) :

L'en-tête d'autorisation est généré à partir du champ nom d'utilisateur et mot de passe (ou simplement nom d'utilisateur) de l'URI WebSocket:

var ws = new WebSocket("ws://username:[email protected]")

Les résultats ci-dessus résultent dans l'en-tête suivant avec la chaîne "nom d'utilisateur: mot de passe" codée en base64:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

J'ai testé l'authentification de base dans Chrome 55 et Firefox 50 et vérifié que les informations d'authentification de base sont bien négociées avec le serveur (cela risque de ne pas fonctionner dans Safari).

Merci à Dmitry Frank pour l’authentification de base réponse

172
kanaka

Le problème d'en-tête d'autorisation HTTP peut être résolu de la manière suivante:

var ws = new WebSocket("ws://username:[email protected]/service");

Ensuite, un en-tête HTTP d'autorisation de base approprié sera défini avec les variables username et password fournies. Si vous avez besoin d'une autorisation de base, vous êtes prêt.


Cependant, je veux utiliser Bearer et j'ai eu recours à l'astuce suivante: je me connecte au serveur de la manière suivante:

var ws = new WebSocket("ws://[email protected]/service");

Et lorsque mon code côté serveur reçoit un en-tête d'autorisation de base avec un nom d'utilisateur non vide et un mot de passe vide, le nom d'utilisateur est alors interprété comme un jeton.

31
Dmitry Frank

Il s’agit plutôt d’une solution alternative, mais tous les navigateurs modernes envoient les cookies de domaine en même temps que la connexion. Vous utilisez donc:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

Terminez avec les en-têtes de connexion de demande:

Cookie: X-Authorization=R3YKZFKBVi
20
Tim

Vous ne pouvez pas ajouter d’en-têtes, mais si vous avez juste besoin de transmettre des valeurs au serveur au moment de la connexion, vous pouvez spécifier une partie de chaîne de requête sur l’URL:

var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

Cette URL est valide mais, bien sûr, vous devrez modifier le code de votre serveur pour l’analyser.

17
Gabriele Carioli

Vous ne pouvez pas envoyer d'en-tête personnalisé lorsque vous souhaitez établir une connexion WebSockets à l'aide de l'API JavaScript WebSockets. Vous pouvez utiliser les en-têtes Subprotocols en utilisant le second constructeur de la classe WebSocket:

var ws = new WebSocket("ws://example.com/service", "soap");

et vous pouvez ensuite obtenir les en-têtes de sous-protocoles en utilisant la touche Sec-WebSocket-Protocol sur le serveur.

Il existe également une limitation: vos valeurs d'en-tête de sous-protocoles ne peuvent pas contenir de virgule (,)!

12
Saeed Zarinfam

L'en-tête d'autorisation d'envoi n'est pas possible.

La liaison d'un paramètre de requête de jeton est une option. Cependant, dans certaines circonstances, il peut être indésirable d'envoyer votre jeton de connexion principal en texte brut en tant que paramètre de requête, car il est plus opaque que d'utiliser un en-tête et finira par être enregistré partout. Si cela vous pose un problème de sécurité, ne alternative consiste à utiliser un jeton JWT secondaire uniquement pour le type de socket Web.

Créez un noeud final REST pour générer ce JWT, auquel seuls les utilisateurs authentifiés par votre jeton de connexion principal (transmis via un en-tête) peuvent accéder. Le socket Web JWT peut être configuré différemment de votre jeton de connexion, par exemple. avec un délai plus court, il est donc plus sûr d’envoyer en tant que paramètre de requête de votre demande de mise à niveau.

Créez un JwtAuthHandler distinct pour le même itinéraire que celui sur lequel vous enregistrez le SockJS eventbusHandler. Assurez-vous que votre gestionnaire d'authentification est enregistré en premier afin de pouvoir vérifier le jeton de socket Web par rapport à votre base de données (le JWT devrait être lié d'une manière ou d'une autre à votre utilisateur dans le backend).

5
Norbert Schöpke

Totalement piraté comme ça, grâce à la réponse de kanaka.

Client:

var ws = new WebSocket(
    'ws://localhost:8080/connect/' + this.state.room.id, 
    store('token') || cookie('token') 
);

Serveur (utilisant Koa2 dans cet exemple, mais devrait être similaire où que ce soit):

var url = ctx.websocket.upgradeReq.url; // can use to get url/query params
var authToken = ctx.websocket.upgradeReq.headers['sec-websocket-protocol'];
// Can then decode the auth token and do any session/user stuff...
1
Ryan Weiss

Techniquement, vous allez envoyer ces en-têtes via la fonction de connexion avant la phase de mise à niveau du protocole. Cela a fonctionné pour moi dans un projet nodejs:

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);
0
George