Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wss://url:8084/mqtt in node.js worked but in browser using webpack failed #741

Closed
Qtianv587 opened this issue Dec 12, 2017 · 9 comments
Closed
Labels

Comments

@Qtianv587
Copy link

Qtianv587 commented Dec 12, 2017

I used mqtt.js in node.js and I used wss as protocol. I used the self-signed certificates to connect to mqtt. In node.js, it worked. So I browserify the MQTT.js with Webpack, and it failed.
The error log shows in Chrome's console is:
WebSocket connection to 'wss://url:8084/mqtt' failed: WebSocket opening handshake was canceled.
And it will remain reconnecting and show this error.
The code in Chrome is:

    options = {
        'username':username,
        'password':password,
        'clientId':genID(username),
        'retain': false,
        'protocol': "wss",
        'key': cert_key.toString(),
        'cert': cert_crt.toString(),
        'ca': cacert.toString(),
        'passphrase': "client",
        'rejectUnauthorized': false
    };
    var broker = "wss://url:8084/mqtt";

    client = mqtt.connect(broker, options);

this is same as I write in node.js:

var options = {
    'username':username,
    'password':password,
    'clientId':"ssss",
    'retain':false,
    'protocol': "wss",
    'key': cert_key.toString(),
    'cert': cert_crt.toString(),
    'ca': cacert.toString(),
    'passphrase': password,
    'rejectUnauthorized': false
};

var client = mqtt.connect(broker, options);

It's so confused and could someone else also suffered this problem and had solved? I'm here begging your help!
:-(

@mcollina
Copy link
Member

mcollina commented Dec 12, 2017

You can't use the key, cert, and ca in the browser. You need to trust that certificate manually in the browser, otherwise the secure websocket connection will fail. Feel free to send a PR to update the README with this info!

@Qtianv587
Copy link
Author

Qtianv587 commented Dec 13, 2017

@mcollina So grateful for your answer! But there is still some questions about this.

  1. As you answered, I needn't set key, cert and ca in options. But how can I use the certificates in the browser js if I use the trusted certificates? It seems no "entry" to import these certificates into the connection environment. Till now, I set these certificates into localStorage in chrome and then import them into environment.
  2. And more confused, the key file seems not a certificate and cannot be trusted by browser. Is it necessary to be imported into the environment?

@RangerMauve
Copy link
Contributor

@Qtianv587 The browser version of MQTT.js uses the built-in Websocket implementation, which means it uses the Browser's TLS support.

Browsers don't provide any APIs to developers that allow custom certificate chains, you have no choice but to use certificates that are signed by an authority that's trusted by the browser.

If getting a valid certificate is a problem, I would advise using Letsencrypt

@Qtianv587
Copy link
Author

@RangerMauve @mcollina
Well, I use Mac OS to test my certificate and I have found some tricks to import certificate into environment. And I don't know whether it's harmful or not.

First we need generate the .pfx certificate with the ca, cert and key mentioned above.
I used the following command:
openssl pkcs12 -export -out certificate.pfx -inkey client1.key -in client1.crt -certfile cacert.pem

And then add the certificate certificate.pfx into the trusted key tools of Mac.
Extra step is needed for the key which is added during the certificate being added. I changed the permission of the key in the trusted key tools, which made every appliction able to access the certificate. (Windows OS may need another way.)

OK, next is my trick. I add the following codes before the mqtt.connect(url, opts):
browWS.wsConnect("wss://url/mqtt", ["mqtt"]);
The function wsConnect(url, protocols) comes from the file Websocket.js in module ws of Node.js. Excuting the function will actually execute the function new Websocket(url, protocols) which in fact is the constructor function in Websocket.js. I used webpack to achieve it.

My purpose at first is trying to generate a websocket between mqtt and browser. But by executing the wsConnect(), the browser will notice you to import the certificate.
The function wsConnect() will fail and generate nothing, but the certificate will be imported.
And the following step mqtt.connect("wss://url:8084/mqtt", opts) will successfully be executed and also the browser client will connect to mqtt successfully.
Questions come. Could you please tell me whether it's harmful and safe in this way?

@RangerMauve
Copy link
Contributor

I'm honestly not sure. Could you post some code so that I can see in detail?

@Qtianv587
Copy link
Author

Qtianv587 commented Dec 15, 2017

@RangerMauve
OK, my first purpose is trying to generate a websocket by creating a new JS file called testWebsocket.js and using the following code:

var WS = require('ws');//ws is a module original from Node

module.exports = {
    wsConnect: function (url, protocols) {
        return new WS(url, protocols);
    }
};

And then I use webpack to transfer this file to another JS file which could be executed in H5.

webpack testWebsocket.js ./browWS.js --output-library browWS

I have detected ever that the url was wss://host:8084/mqtt and the protocols was ["mqtt"].

I 'required' the browWS.js file into environment using <script src = 'browWS'>, and then is the code of the whole connection to mqtt.

var client;
var options;
var broker = "wss://host:8084/mqtt";
var user;

//**!!!!!****The browser will notice me to import the certificate when execute this function.**
browWS.wsConnect(broker, ["mqtt"]);

function connect(browBuffer, mqtt, username, password, callback) {
    user = username;
    options = {
        'username':username,
        'password':password,
        'clientId':genID(username),
        'retain': false,
        'protocol': "wss",
        'passphrase': password,
        'rejectUnauthorized': false
    };
    client = mqtt.connect(broker, options);
}

That's the whole steps. The wsConnect function will cause some error like GET https://host:8084/mqtt 400 (Bad Request) and generate nothing, but this step will notice me to import the certificate both in Chrome and Firefox. And in this way, the connection will be successfully executed.

@RangerMauve
Copy link
Contributor

RangerMauve commented Dec 15, 2017

I'm not sure you need to use wsConnect here, maybe you can get away with using fetch to make a request to the website first, but if opening a websocket connection is enough to prompt you to add the certificate, I think it makes sense.

However, I must warn you that self-signed browser certificates are vulnerable to man-in-the-middle attacks, so you should not trust them if you're planning on using any public wifi, or if you can't trust your Internet Service Provider (most of the time you shouldn't)

@github-actions
Copy link

This is an automated message to let you know that this issue has
gone 365 days without any activity. In order to ensure that we work
on issues that still matter, this issue will be closed in 14 days.

If this issue is still important, you can simply comment with a
"bump" to keep it open.

Thank you for your contribution.

@github-actions github-actions bot added the stale label Sep 25, 2022
@github-actions
Copy link

github-actions bot commented Oct 9, 2022

This issue was automatically closed due to inactivity.

@github-actions github-actions bot closed this as completed Oct 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants