Closed twiss closed 8 years ago
As huge API changes would be necessary I am against adding webcrypto support. It is possible and interesting though to create a wrapper library that uses Web Crypto and falls back to sjcl when web crypto is not available. That does of course not help increasing the general speed of sjcl. The problem is not only in that an async interface would be required but that currently everything works synchronous.
Could you please re-evaluate whether to use Web Crypto? Web Crypto is supposed to be fast and secure using native browser implementations, so it would be good if this speed and security gain could be used by users of your lib just by updating the lib.
Sorry but I still think that it is not the job of sjcl to support web crypto. Web Crypto and sjcl both implement cryptographic primitives but sjcl does so with a very simple synchronous interface. Web Crypto on the other hand is asynchronous. This means that if sjcl were to support Web Crypto (meaning that it would use web crypto instead of its own crypto implementation when web crypto is available) the whole API would have to change which would mean an entire rewrite of sjcl which I definitly do not have the time to do.
Web Crypto and sjcl do also not have to be used as one entity but can be combined under a wrapper library, which at least from my point of view would also make more sense. That library would either call sjcl if web crypto is not available or call web crypto if it is available. This would also not require any changes on the side of sjcl.
If you have a HTTP server (not HTTPS), then Webcrypto is not usable on chrome. Thus, depending on the transport mechanism used, Webcrypto.subtle might or might not work (not speaking about older browser anyway). It's a shame, because when you have a HTTPS link, most of the crypto is already done for you, and there is almost no need for (complex) crypto. On HTTP side, however, you are on your own, and sjcl is filling this hole. Then, I don't see where it would make sense to have sjcl mimicking webcrypto's API.
On HTTP side, however, you are on your own, and sjcl is filling this hole.
If you use HTTP, you can forget any JS crypto anyway. Without HTTPS it's not secure on the web! Any MITM can just change the JS, so you definitively always need HTTPS.
That is also the reason why major browsers started deprecating HTTP many years ago.
My idea was that SJCL could be used as a fallback when WebCrypto is not available.
What @rugk said. Use https. Certificates are free now, there is no need to still use http in an unencrypted way.
How do you do with a home connected gizmo ? As far as I know, your IP address might change any time, and you are unlikely to have the HTTP port opened on your router for your gizmo to register a certificate automatically, or to renew it 3 months after buying it.
How do you do in a company's intranet with private IP address ? Not all company can afford to become CA to certify their internal services.
So, no, @rugk isn't completely right. There is still a need for JS crypto on HTTP, at least to avoid plaintext password and token propagating on the network. And I really doubt an unlikely MITM is a reason to avoid this protection. On such private networks, forging IP is not something that easy to do anyway, unlike listening to packets.
@X-Ryl669 You are mixing different issues here and it's really a bad security practise to do any JS crypto without any HTTPS. Or, as said: It's actually insecure! Note this is a fact and you may find HTTPS difficult, but this does not change the fact that without it, JS crypto makes no sense at all. I don't know how to emphasize this even more.
See also:
Why you should always use HTTPS (no matter whether the site is static etc.):
I don't think so. The arguments here are valid but they don't cover the problem I've described. I'm not saying you should not use HTTPS whenever possible. What I'm saying is:
(1) If a CA issued a certificate for a reverse IP DNS name, then your neighbor could have a valid certificate when he's getting your previous IP address, so SSL would not protect you, anyway.
(2) Using self signed certificate is the WORST solution, since browser make it scary, and if you told user to accept the exception, they'll do that too under a MITM attack.
(3) In a company, you can expect system administrator to install a (company based) root CA on each worker's device, but because of usual BYOD rules, it's really unfeasible nowadays.
Security works only when it's done by layer. SSL provides many of them (like the chain of trust), but that does not mean you shouldn't use any layer elsewhere. In fact, you should.
So yes, a MITM with impersonating power can change your JS code on HTTP, but such action is a rare event. A MITM that's observing is a less rare event and can be automated, and if you can secure against that, you should do it. If you don't have SSL, you must encrypt them at least for a minimal security. To the same extend, it's not because you don't have a safe at home that you should stick your cash on the front door.
Unfortunately, webcrypto guys have the same "big corp" way of thinking, such they denied having crypto lib available under HTTP, and this leads to such poor security in home IOT product because it's so damn hard to have a minimum security with HTTP. You know: "The S in IOT is for security"
@X-Ryl669 Perhaps what would solve your use case is to have a separate HTTPS domain for the "application", where you would enter (or pass in a URL parameter) the IP of the IOT device that you want to talk to. (You'd probably need to serve CORS headers from the device in order to be able to access it.)
Then, since you have a secure (trusted) application, you could also put a key in there to decrypt the data from the device, and perhaps a separate public key of the device in order to verify that the data comes from that device. (Doesn't have to be a SSL certificate, a plain RSA public key would do.)
Then an attacker can't MITM your application, nor the communication between your application and the device, and you can use Web Crypto, and the browser won't show scary warnings.
@twiss Yes, that's completely possible but that would require the device can talk to the internet. That might work for home network, but for company private intranet, that's a no-way. Also, if you, as a company operating the devices, fail and you stop the external domain/server, then your previous consumer will be very very angry I think because the devices are now useless.
A permanent HTTPS CDN delivering the main crypto code to bootstrap a secret might do the trick for as long as it's being paid for and accessible. There's basket.js
that's also helpful in that case, since it only require connecting to the HTTPS domain once and then it's caching the JS code on localStorage. When you have the connection done once and verified, you can then bypass the external internet requirement, so that might be acceptable.
Yes, that's completely possible but that would require the device can talk to the internet. That might work for home network, but for company private intranet, that's a no-way.
As long as the connection is directly between the application and the device, I don't think this is true - if you make the request to the device's IP address on the client side, in the browser, on a computer that has access to the intranet, then it should work, right?
Also, if you, as a company operating the devices, fail and you stop the external domain/server, then your previous consumer will be very very angry I think because the devices are now useless.
Many companies that have an intranet require their employees to install a root certificate, precisely because it's otherwise impossible to securely deliver pages from the intranet, as you said. So once you do that, you can host it in the intranet and the browser will accept it as HTTPS.
For other users, browsers accept pages served from localhost
as secure as well, so you could give them the static pages and a tiny server so that they can host it locally. Or you could go all the way and package it as an Electron / mobile app.
(In any case all of this is sort of off topic for this GitHub issue)
If you include HTTP resource from a HTTPS page, the browser will issue a warning (for now) and soon will refuse to load it.
Having a server on client's browser is not possible for non-tech savvy user. If you need to load an (external) app, then you completely don't care about HTTP whatsoever anymore, you can as well use a socket with SSL and private certificate. However, that's a shame you can't use plain old website to just do website-like scenario on a local network and have to ask your users to download xxMB of Electron app.
(I agree that it's not the issue topic and I've presented all my arguments for keeping sjcl alive, it's still required!)
This discussion is totally off-topic, but one final word: No you actually can get certs for internal LAN services, here is how you do:
This is IMHO better than any root cert injection into employee devices. And it works on all devices as long as they use the companies DNS server. And no external connections happen. And if not, you could also make a redirect from the public server to the private one or so.
That solution is not viable for home user (they are using ISP's DNS which (usually) don't trick/cheat) and it's too tech savvy for a general user to set up.
On a company intranet, devices don't have access to internet, so they can't assert the certificate chain (unless your certificate is provided by a Root CA which is usually not the case). You can embed the complete certificate chain in the server, yet it's not common enough, and might require manual intervention on some (old) devices (like printers/scanners) that don't have the software for this (most notably they also lack SNI support). Many CA still link the certificate to the (public) IP address of the server so it works on pre-SNI device, but it would fail in your example, since the public IP address is not accessible for these devices.
There's also the issue with the certificate (limited) lifetime where you need to update the certificate everywhere if you did manual installation at regular interval. Not all device have shell where you can run script on them, so most of the time, it's a manual process through obscure and different web interface (again, think about your office laser printer or manageable network switch or any network device with authentication). It's a real pain.
There is the possibility of using a reverse proxy that's lying depending if it's being asked from the internal network, but you have to do that for each service you intend to SSL protect (if you have hundred of them, it's a nightmare to administrate and maintain). That would also publicize all your services internal name on the internet (since certbot
requests are public and the public DNS must be able to enumerate them). That's a huge price to pay for this feature, IMHO.
The real solution would be to have an exception for user agreed servers that's not worrying and remembered automatically. So instead of the huge red sign (and 5 obscure steps to "allow exception") you currently get when receiving a self signed certificate, an IOT device should present a certificate that's auto generated, but signed by a certificate that's available and checkable on the internet (a bit like a sub-CA). The browser would assert the chain, check the IOT device is on the local network (that's the only reason HTTPS is failing currently), and ask the user to agree to the certificate (in a not worrying manner). If either the device's cert fingerprint is modified (a bit like SSH client that's storing the fingerprint of keys internally), that would mean MITM, then the browser would show the large warning sign.
That would only require the device to be connected to the internet only once to query for signing of its certificate, and I think this is acceptable.
That solution is not viable for home user
But home users also do not have any internal LAN services. Your argument is kinda strange...
On a company intranet, devices don't have access to internet, so they can't assert the certificate chain (unless your certificate is provided by a Root CA which is usually not the case).
That's simply plain wrong. In my example, it would all be signed by a CA users already have in the trust store. No internet needed.
And I also did not talk about IP addresses. Maybe you do re-read my post.
(again, think about your office laser printer or manageable network switch or any network device with authentication)
And surely, there you want to implement JS crypto with SJCL or what? This makes no sense at all. Leave legacy devices legacy sure. Then they don't need HTTPS.
There is the possibility of using a reverse proxy that's lying depending if it's being asked from the internal network, but you have to do that for each service you intend to SSL protect
You notice I mtotally described that more or less? You do not have to repeat things here.
for each service you intend to SSL protect
Or just use wildcards and do it for one server that gets the cert, and all others use that one...
That would only require the device to be connected to the internet only once to query for signing of its certificate, and I think this is acceptable.
That (all the last paragraph) sounds interesting and would maybe be possible. In the end, it would be a CA (no sub-CA, it's still a CA) that is only valid for internal networks and some TOFU thing. That is less secure than the current approach, but an idea at least that can be discussed (and there are surely many arguments). However this here is totally the wrong forum for that...
To come back to the original issue:
to have a minimum security with HTTP
You still do not seem to understand it: Minimum security === HTTPS. Exceptions are only localhost or so, even in companies LANs people could MITM you.
And there were many proposed solutions and ideas. In the end I don't think the discussion here makes any sense anymore. So I am not going to take part in it anymore.
For Airborn OS, I wrote an implementation of the default CCM mode (which isn't supported natively by Web Crypto, but CTR mode is) using Web Crypto, to make it faster. (Code here.) Of course, Web Crypto is async, so to support it sjcl would need a new API (something like
sjcl.async.encrypt
, or switch insjcl.encrypt
based on whether a callback is passed — also, Web Crypto and thus the current code uses arraybuffers). If the code is made a bit more general (less hardcoded parameters and maybe more supported modes) would you be interested in that?