when I am trying to use Paho MQTT javacrript with Mosquito MQTT websockets, everything works as long as the web server that I am using to serve my page and Mosquito are in the same server (same origin). However, if I try to connect to a different Mosquito instance (cross domain), Firefox throws a security error.
Problem is that the Javascript client initiates a http connection to the Mosquito web socket server and it gets upgraded to ws:// as part of negotiation. Had the initial request itself been over ws:// , SOP would not have kicked in.
I tried to connect to the second server from http://mitsuruog.github.io/what-mqtt/ and it works fine without SOP error. So, I know that the server can support ws:// . How to get this done using the Paho implementation?
Is there any way to work around this?
The issue is that I was trying to initiate an un-secure (ws:// instrad of wss://) while the page was itself loaded over https:// . This results in a mixed content error that is not explicitly reported by Firefox. Chrome prints a better warning and allows to temporarily bypass it as well.
Related
I am developing a websocket server (let's call it WS), which is totally independent from another HTTPS server which I am also developing (let's call it Main).
WS itself is working well and I also have a command line testing tool which is written in Node.JS that can communicate with WS via websocket messages.
Main itself is also working well and I can open web pages with browsers via HTTPS without any problem.
Here's the problem:
Since command-line testing is not user-friendly to engineers that are not familiar with command lines, I want to create a "Browser Webpage Testing Tool" on Main in order to send messages to WS and receive response.
I basically used codes from here: https://blog.teamtreehouse.com/an-introduction-to-websockets#:~:text=To%20send%20a%20message%20through,binary%20data%20through%20a%20WebSocket.
However on this line
// Create a new WebSocket.
var socket = new WebSocket('ws://Ws-address');
The browser tells me "The page at 'https://MainUrl/testing-tool' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://Ws-address/'. This request has been blocked; this endpoint must be available over WSS."
However the WS server is a real time application and is not intended to work over wss, rather as a requirement it must be optimized in speed as much as possible and anything else must be sacrificed.
Therefore WS will use plain ws instead of wss which has an additional tls handshake.
Is there any way to make my "Testing Tool" work?
I have a java client and I need to rewrite it in (client-side) javascript.
I open the java Socket like this:
Socket socket = new Socket("127.0.0.1", 5015);
So I tried to use websocket in javascript:
let socket = new WebSocket("http://127.0.0.1:5015");
but here I have a js error:
Uncaught DOMException: Failed to construct 'WebSocket':
The URL's scheme must be either 'ws' or 'wss'. 'http' is not allowed.
I tried also to use the 'ws' or 'wss' protocol but the server didn't want to handshake with such protocols.
Is there a way to make such socket connection in client-side javascript or it's definitely prohibited?
The answer is a little more complicated than "no you can't do it".
Javascript in a regular web page running in a web browser cannot open a plain socket. The fundamental reason is that it is a security risk for the user. So it is intentionally not allowed.
WebSockets are the secure way to do this. In conjunction with other browser security mechanisms, they limit what a web page is permitted to connect to.
However, that is not the end of the story. It is possible (at least in theory) for trusted code to send and receive TCP and UDP traffic. The problem is that the APIs for doing this are non-standard (e.g. browser specific). In some cases are themselves implemented as 3rd-party browser extensions.
So if you really wanted to pursue this for you application, you are going to have to distribute your code as a trusted browser plugin / extension AND deal with a range of browser portability issues.
It is worth noting that there was a W3C Working Group that was trying to standardize raw socket APIs, but they have officially abandoned their efforts. Their last working draft can be found at:
https://www.w3.org/TR/tcp-udp-sockets/
Finally, there is the problem that a trusted browser extension / plugin requires the user's consent to install. Getting informed consent for something like this is difficult, given the deep and subtle security issues associated with embedding this kind of functionality in the user's browser.
No, you can't make an arbitrary TCP connection from a web page in any browser.
Web Sockets are fundamentally different than TCP sockets... they're essentially unrelated. They're a thin layer on top of HTTP along with a client API which allows bidirectional communication between a Web Socket client and a server supporting Web Sockets.
There are proxy servers you can run that allow connecting through them to make TCP connections, but this of course is a server feature and not something you can do in-browser alone.
The opening handshake is intended to be compatible with HTTP-based
server-side software and intermediaries, so that a single port can be
used by both HTTP clients talking to that server and WebSocket
clients talking to that server. To this end, the WebSocket client's
handshake is an HTTP Upgrade request:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
https://www.rfc-editor.org/rfc/rfc6455
WebSockets server must be able to handle HTTP requests!
I need to connect to broker over websocket.
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
<script>
// Create a client instance
client = new Paho.MQTT.Client("broker.hivemq.com", 8000, "" , "gokden");
// connect the client
client.connect({onSuccess:onConnect});
function onConnect(){
console.log("Connected!");
}
</script>
This is my connection code but i get this error:
mqttws31.min.js:36 Mixed Content: The page at 'karantinagunlugum.com' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://broker.hivemq.com:8000/'. This request has been blocked; this endpoint must be available over WSS.
You have 2 related but separate problems here.
broker.hivemq.com doesn't support Secure MQTT over Websockets (wss://) which is why the connection is being closed after 30 seconds when you try to connect
You are trying to connect from a page that was loaded over HTTPS. Pages loaded securely can not connect to insecure resources due to the secure origin policy in the browser, this is what the second error is telling you.
You have 2 choices
Turn off HTTPS for your site. This is not a good idea.
Setup your own broker that supports Secure MQTT over Websockets.
You shouldn't really be using broker.hivemq.com for anything other than basic testing and playing, if you want to do anything serious you should be either paying for a properly hosted broker or running your own.
I have a web app in javascript that connects to a socket using socket.io and a Chrome Extension which connects in the same way and to the same server.
Everything works fine in most computers and internet connections, but one of my customer's computer is failing to have the Chrome Extension connected (the web app connects successfully).
By inspecting the extension's console for background.js (the script within the extension creating the socket connection) I see that it is not trying to connect to the right URL (my socket server) but to an unknown URL which seems to be a proxy: https://gateway.zscloud.net/auT?origurl=http%3A%2F%2Fmy_socket_server_domain...
Since this is happening only in that specific computer (from the 10 or so that I have tried with so far) using different internet connections (corporate network, guests network, mobile hotspot) and since other computers in those same networks DID succeed in connecting, I assume something installed or configured in the problematic computer is catching the connection request before it happens and tries to redirect it through a proxy.
Again, this happens only in the context of the Chrome Extension. The very same computer using the same internet connection DOES succeed in connecting from a web page in the same browser (Google Chrome).
Does anybody know what the problem could be? The client is not aware of having a security software (firewall, antivirus, etc...) that could be causing this, but it's a computer managed by his company so an admin could have done that for him. If that was the case, however, shouldn't the connection from the webpage be captured too? Is there anything specific to socket connections in Chrome Extensions that differ from regular web apps?
Thanks!
WebSocket connections differ from normal HTTP requests; they require a protocol upgrade after establishing that (some!) proxies may be unable to support.
I was at some point behind one such (transparent) proxy at work; however, it does not attempt to intercept HTTPS, which means I could use wss: WebSockets but not ws: WebSockets.
..which you should be using, anyway! With Let's Encrypt on the market, the barrier of entry for HTTPS is very low. If any sensitive data at all is sent through that connection, it's in your best interest.
For the record, that particular proxy is part of ZScaler which is a security solution. Sadly, it includes HTTPS MITM, so the above is unlikely to solve the problem (but should be implemented anyway!). It's set up as an OS-level proxy - if that setting is possible to change, or override with Chrome's proxy settings, that would fix it. However, that's going to piss off network security!
If you can't do that, then your client is a SOL and should complain up the chain about the security solution breaking legitimate applications.
Edit: I looked around and found this, which seems to claim that using SSL (that is, wss:) is enough. But that's from 2012 - perhaps before ZScaler was able to MITM all HTTPS traffic.
It should be possible to test whether wss: switch will work using https://www.websocket.org/echo.html - if it can connect then everything will work over wss:
I'm working on a website in my local development environment (Ubuntu 16.04) and testing the website on Chrome (58) via http://localhost.example/ - which connects to the local web server.
Running this Javascript:
$(document).ready(function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
});
Triggers this error:
[Deprecation] getCurrentPosition() and watchPosition() no longer work
on insecure origins. To use this feature, you should consider
switching your application to a secure origin, such as HTTPS. See
https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins for more details.
Why is that? I understand that public facing websites need to be running HTTPS for the geolocation library/ functionality to work. We have a number of public websites running similar code across HTTPS.
However according to the depreciation documentation:
localhost is treated as a secure origin over HTTP, so if you're able
to run your server from localhost, you should be able to test the
feature on that server.
The above Javascript is running in-line in the HTML body loaded via http://localhost.example/test-page/ - so why am I getting the "insecure origins" error in Chrome?
Firefox (53) shows the in browser access location prompt, as expected.
Chrome considers localhost over http as secure. As you are using hostnme localhost.example over http, this is not considered as secure.
Note: Firefox will behave similarly as of Firefox 55
SSL over HTTP protocol ensures the private communication within Client and Server. The information might transmit through the private networks while transmission. Any third person (hacker) on the network can steal that information. To avoid that browser forces the user to use a secure connection.
On the local server, the information is not going beyond our private local network since there is not need of this kind of security. So we can expect a browser to allow geolocation without SSL on the local server. Ideally, the browser developer should skip this validation for localhost and 127.0.0.1 or similar origins.
There must be tricks available to avoid such issues i.e. you can install self-signed SSL certificate on the local server or you can edit the Chrome configuration file to allow domains to access the geolocation, webcam etc.
Helpful links,
https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins
https://ngrok.com/