Can a websocket client in a browser send headers? - javascript

There is a debate raging in the office about a browsers ability to send handshake headers are part of establishing a websocket connection.
The websocket spec makes it clear that headers are possible. And, infact, in my non-browser client code I do set handshake headers and they are received without and issue.
The open debate is: Can a web browser using javascript insert headers are part of the handshake? The spec seems to indicate there is nothing against it but no one can find client side documentation that says how.
There is a lot of conflicting information. It's obviously possible because I am able to do it in Java without a problem. But for Javascript no one is seeing how. Is it a browser restriction?
To clarify how my question is different than others: Is the inability to do this a limitation of the default javascript libs? The web browser or the spec? It looks like it's a library limitation only

I am afraid that the WebSocket API in web browsers does not allow to set custom headers. Still, the browser sets cookies, if any.

The issue is that the standard API for creating a webSocket connection in a browser does not provide any mechanism for setting custom headers. So, it is a limitation of the webSocket browser API.
You can control the URL you send including query parameters and cookies are sent with the request so you have the ability to use the path, query parameters or cookies to send additional information with the connection request.
WebSocket WebSocket(
in DOMString url,
in optional DOMString protocols
);

Related

Validate WebSocket data

I have a WebSocket server written in javascript and send data to it from my CSharp application. Now how can I make sure that these are correct? I thought I could do something with hash values but I don't know how to do that. Does anyone have an idea or code example?
The first thing to understand is the types of WebSocket protocol/transports. WebSocket ws:// transport is basically unusable in terms of security as it uses HTTP. The wss:// protocol establishes a secure connection over TCP/HTTPS. The wss protocol, therefore, protects against man-in-the-middle attacks.
There is multiple methods to authenticate a user when setting up a WebSocket connection, and none are perfect. Since the standard WebSocket usage prevents additional headers from being set such as custom authentication headers, tried and true methods that would be used in a standard HTTPS request to verify the validity of a client can't be used.
The link here outlines some common methods to keep the client and server in sync while setting up a WebSocket connection, and still add some security so the server can keep track of what clients are opening WebSocket connections. There are a lot of workarounds listed for the server to safely receive sensitive, authentication data from the client.

Is it possible to force socket.io to use wss instead of ws, without having to change to https?

I have been trying to setup a server where users can send sign in using websockets, but I don't want to do this using ws. I want to be able turn on wss without having https. Sadly, there aren't any options to do this. And so the question is how would one do this on the client side without using https protocol.
Yes, this is possible. To do this, pass your websocket URL to the socket.io client directly, like this:
var socket = io('wss://example.com/');
Note that the reverse is not possible: while there's nothing to prevent HTTP pages from creating WSS connections, most browsers today block any WS connection from an HTTPS page to enforce the heightened security.
I would also caution that a websocket opened over WSS is still no more secure than the page it originated from. If you're using WSS for its security benefits, be advised that all that security could be for naught if an attacker overrides your page at the time that it's loaded (which HTTPS would prevent).
From the Websocket protocol specification:
A wss URI identifies a WebSocket server and resource name, and
indicates that traffic over that connection is to be protected via
TLS (including standard benefits of TLS such as data confidentiality
and integrity, and endpoint authentication).
Emphasis mine
Now you can understand the absurdity of your request: wss is https.
Of course the terminology is wrong (https is a different protocol than wss) but the bottom of the line is that both are simply the version of their respective TCP plain protocols (http and ws) over TLS.
So the answer is no.
As a matter of fact security is a complex thing.
Very experienced programmers refrain from inventing or exploring new ways and, based on the kind of question you asked, you don't appear to have much expertise this field.
So it's better to do things as best-practices say, it they say to use "https" use "https".
Starting studying security seriously (or hiring a contractor) is advised, inventing new ways to perform secure authentication is not, unless you have a PhD in abstract algebra and several years of experience in developing cryptographic schemes.

How can I override the Origin header in Chrome when connecting to a WebSocket?

I am trying to connect to an external web socket server, which is not run by myself. I would like to connect to it from a localhost javascript file, therefore the origin header has null value.
I understand that this is a measure against cross-site forgery. However, since I am on localhost, I should be able to fake this, by getting Chrome to send a custom Origin header.
Is it possible? (if I need an extension, that is fine)
If not, what is my best option to achieve the above? Thank you.
Web pages cannot change the Origin header, but extensions can modify the request headers via the chrome.webRequest API. But ws:// and wss:// are not supported by this API, so this doesn't help unless the server also supports other means of communication via http(s) (e.g. long-polling).
There is still a solution though: Simply load a (known) web page at the desired origin in an iframe (e.g. https://example.com/favicon.ico or https://example.com/robots.txt) and use a content script to open the WebSocket from there.
The Origin header is one of the headers that are set automatically by the user agent (as part of the browser implementation), and cannot be altered programatically or through extensions. This makes sense because web service providers cannot allow random connections from localhosts.
You can connect to an external WebSocket only if you do it from a host explicitly accepted by the web service provider. Many headers cannot be trusted (because they can be overridden), but this is not the case with Origin as it offers security not only for users, but also for service providers against unwanted connections.
As far as I know this will not be possible, it would break the security guards against CSRF in Chrome.
If you were able to do that the whole concept of XHR would fall apart.
Here is an Extension you can use to manipulate header on the fly, but so far I have not been able to get it to manipulate socket headers.
Look here if you want to read more about this.
But this doesn't stop you from implementing your own client (in place of chrome) where you can literally send whatever headers you want, not sure if this helps you, sorry.
It depends how you want to use your chrome browser. Since you mention localhost I assume you develop and will use this for some kind of scraping. I suggest that you explore Chrome DevTools Protocol which will render (almost) any kind of protection useless because you use a real browser. CORS, Origin, Cookie or any arbitrary header value will be under your control, and you can send a custom header for xhr/websocket request(s). If you want to manipulate in a more advanced way you can use Network.continueInterceptedRequest. You might only want to start chrome using parameters like "--disable-web-security, --disable-xss-auditor, --disable-client-side-phishing-detection, --allow-insecure-localhost" more about such options at peter.sh. However, the last option require a plugin in order to spoof origin header so I recommend the first option.

Secure JavaScript Running on 3rd Party Sites

We have a "widget" that runs on 3rd party websites, that is, anyone who signs up with our service and embeds the JavaScript.
At the moment we use JSONP for all communication. We can securely sign people in and create accounts via the use of an iFrame and some magic with detecting load events on it. (Essentially, we wait until the iFrames source is pointing back to the clients domain before reading a success value out of the title of it).
Because we're running on JSONP, we can use the browsers HTTP cookies to detect if the user is logged in.
However, we're in the process of transitioning our system to run realtime and over web sockets. We will still have the same method for authentication but we won't necessarily be making other calls using JSONP. Instead those calls will occur over websockets (using the library Faye)
How can I secure this? The potential security holes is if someone copies the JavaScript off an existing site, alters it, then gets people to visit their site instead. I think this defeats my original idea of sending back a secure token on login as the malicious JavaScript would be able to read it then use it perform authenticated actions.
Am I better off keeping my secure actions running over regular JSONP and my updates over WebSockets?
Websocket connections receive cookies only during the opening handshake. The only site that can access your websocket connection is the one that opened it, so if you're opening your connection after authentication then I presume your security will be comparable to your current JSONP implementation.
That is not to say that your JSONP implementation is secure. I don't know that it isn't, but are you checking the referrers for your JSONP requests to ensure they're really coming from the same 3rd-party site that logged in? If not, you already have a security issue from other sites embedding your javascript.
In any case, the 3rd-party having an XSS vulnerability would also be a very big problem, but presumably you know that already.
Whether you are sent cookies during opening WebSocket handshake by browser (and if so, what cookies) is not specified by the WS spec. It's left up to browser vendors.
A WS connection can be opened to any site, not only the site originally serving the JS doing the connection. However, browsers MUST set the "Origin" HTTP header in the WS opening handshake to the one originally serving the JS. The server is then free to accept or deny the connection.
You could i.e. generate a random string in JS, store that client side, and let that plus the client IP take part in computing an auth token for WS ..

Javascript request to SSL request

For our APP we have a Web App and a API service, On A certain event the Web app polls the api service for the state of the event using Javascript. Both the apps run on a separate HTTPS sub domain and with a self signed certificate(as it is still in alpha). The problem occurs that the polling is aborted because the https api connection is untrusted. Is it some way for the Javascript request to override the untrusted certificate issue?
Is it some way for the Javascript request to override the untrusted certificate issue?
No, it's because of the same origin policy restriction.
In your case I suppose that you have a page hosted on https://foo.bar.com and you are trying to send an AJAX request to https://baz.bar.com which is not allowed.
You may take a look at the following guide which covers the different possibilities to circumvent this restriction. They range from JSONP, server side script bridges, Flash proxies, screen scraping with YQL, ...
No, you have to add the self-signed certificate to your machine/browser's trusted certificate store.
You also have cross-domain origin issues (the different subdomain), which is separate from any certificate issues. If you're already using JSONP, you're fine; but if you're trying to make an XHR request to a different domain, it's not going to work.

Categories