Closed mwatson2 closed 7 years ago
Add text saying "Developers should use Secure Origins, although this is not strictly required."
Discussion on 7/11 call suggest requiring a secure origin, in the stronger sense of requiring the top-level browsing context to be secure.
I assume that the secure origin test should be performed as the first step in each WebCrypto method. This would mean that errors due to WebIDL type conversion would still occur on insecure origins, but then you would get the secure origin test failure.
IIUC, Chrome's current implementation does algorithm normalization and possibly other parameter validation before checking for the secure origin.
PR #122
-1 for requiring a secure origin (though I'm okay with it being recommended).
The "Secure Messaging" use case, for example, doesn't require TLS in order to preserve the privacy of the exchange, so long as only ciphertext is transmitted. Simply put, we don't want the extra roundtrips associated with establishing a TLS session when they are superfluous to the actual security solution, since this leads to a worse end-user experience with no tangible benefit.
Whatever you do, please do not use the incumbent or entry settings objects here. Current settings object is more correct. See https://readable-email.org/list/public-script-coord/topic/multiple-globals-and-you
Looking at https://w3c.github.io/webappsec-secure-contexts/#new, would it be simpler to add [SecureContext]
to GlobalCrypto
, Crypto
, and/or SubtleCrypto
?
That would probably work, although it would have different normative effects than adding a guard. (Adding a guard causes errors at call time, whereas [SecureContext] prevents the interfaces from existing at all.)
@bdhess Without a secure origin, you can only make security arguments with respect to passive attackers. An active attacker - one who can modify the pages served to the client - has full access.
Privacy against passive observation is not without value and this is the argument I have used in the past against requiring a secure origin. However, we'd need some evidence that there were users with that use-case as a requirement (my company was one of those, but no longer).
@ddorwin Yes, that would seem to me to be simpler and clearer. However the secure context specification recommends both. I am not sure why, since if the interface is only exposed in secure contexts the guard could never fail. @mikewest ?
@mwatson2 In our operating environment, there's no sensitive data or PII that's emanating from the client. Ultimately, our use of Web Crypto is entirely to provide security around server-provided assets. So the protection of client-side key material is therefore a concern for us, but as I understand it, out of scope for Web Crypto.
Yes, that would seem to me to be simpler and clearer. However the secure context specification recommends both.
Adding the [SecureContext]
IDL attribute to the relevant interfaces should indeed be enough. The API won't be exposed in non-secure contexts, and since the state of a context can't change, the explicit guard in the algorithm is redundant (though probably worth noting next to the algorithm in any event). If you're ok with the implications (hiding the interface rather than throwing), then that sounds like a totally reasonable way to address the issue.
Is it web-compatible to hide the API from insecure contexts? That's the main tradeoff solution-wise.
Safari and IE both ship prefixed variants of the crypto.subtle
APIs. I imagine developers would have to be feature-detecting anyway if they don't want to error out on those browsers.
Marking with [SecureContext] SGTM.
-1 for requiring a secure origin (though I'm okay with it being recommended).
Note that Chrome already doesn't allow Web Crypto over non-secure origins. So clients needing to support Chrome will have to address this in their implementation regardless.
IIUC, Chrome's current implementation does algorithm normalization and possibly other parameter validation before checking for the secure origin.
Chrome (currently) does the origin check after (most) WebIDL checks on the parameters, but before things like "algorithm normalization", and rejects with NotSupportedError in that case. Hence it is not very consistent as far as what parameters have been processed. Marking with [SecureContext] avoids that problem.
What should happen when structured (de) cloning a CryptoKey into an insecure context? Under the crypto.subtle is hidden model, I presume you could still postMessage a CryptoKey to an insecure context. Is that relevant?
@ericroman920
Note that Chrome already doesn't allow Web Crypto over non-secure origins. So clients needing to support Chrome will have to address this in their implementation regardless.
So the contention is, since Chrome has already defined a behavior, there's no point in discussing changes that would make the spec inconsistent with Chrome's present behavior? This seems like a really backwards way of developing community standards. I'm not the first person to object to this behavior:
https://www.w3.org/Bugs/Public/show_bug.cgi?id=25972#c6 https://www.w3.org/Bugs/Public/show_bug.cgi?id=25972#c20 https://www.w3.org/Bugs/Public/show_bug.cgi?id=25972#c22
From the record, it's pretty clear that Chrome came to this decision based on the assumption that there exists no scenario in which there is value in being able to use the Web Crypto API in an insecure context. Including myself, there are at least four commenters who've disputed that.
I suspect that were you to ask the people that objected to this in the past again, they are probably more agreeable to this now. E.g., Mark commented in this very thread saying so.
Also, the concerns Ehsan raised there were mostly about the original solution easily being bypassed. Secure contexts addresses those concerns. He didn't really state any use cases for Web Crypto in insecure contexts and I don't really think you have clearly done so either.
New PR using [SecureContext]
: #131
A problem with PR #131 is that it marks window.crypto as [SecureContext].
This means that window.crypto.getRandomValues() is no longer accessible on insecure contexts.
I don't believe we want that change -- getRandomValues() has always been available on insecure contexts.
Instead I propose marking only SubtleCrypto (i.e. window.crypto.subtle) as [SecureContext].
Yep, I missed that. I'll update it.
I'd lean towards requiring a secure origin here. I feel a little sad about losing hash capability in insecure origins (since that is not sensitive in any way, similar to getRandomValues) but overall given the current threat landscape I believe it is better to strongly protect key material even if we take this bit of collateral damage.
Hi, I don't think that enforcing HTTPS everywhere is a good solution, especially with that API.
I am currently developing a distributed app that works on a local network, without internet access. Each node has a little "admin" interface. Due to the cost of having and maintaining a PKI, especially for small clients, I don't want this admin interface to be on HTTPS. Having a self-signed certificate is not an option either, because of all the security warning that would cause the user to skip the warning without even looking at it, making the whole thing as vulnerable as plain HTTP.
For the solution I designed, I implemented a key exchange mechanism over HTTP and encrypt only sensitive data as needed. But on first try with chrome on another computer, I realized that my thing is entirely broken.
I want to use new APIs, but the work of having HTTPS on each node is a no-go for me, and in the end of the day, I can't make my site any safer by using this API... that's really too bad. It's like telling a homeless to give his address when he wants to buy a blanket to cover himself...
That being said, I suppose that I need to find a crypto library... Which is just the same as using webcrypto from insecure origin, but with more js weight, less maintained code and less performance.
this pisses me off greatly, i just want to calculate my sha1 using your super secure web crypto shit, and it cant because well, i don't care about being all cryptic, i just need my sha1 please, looks like you got lost in definitions, not everything named "secur..." needs to be turned off
I do not want to be rude but whoever came with the idea that crypto should not be available in non-secure context was probably only thinking about his narrow set of usage scenarios. We have an intranet exam server for schools which they use separately in every class room for computer-based final exams. We cannot use HTTPS because schools cannot buy certificate for every intranet computer they want the exam server to run on and we do not want to use self-signed certificate because browsers would issue warnings which we want to avoid. So we use window.crypto.subtle to implement our own asymmetric cryptography to protect sensitive information on the wire. Now we will have to use some JS crypto library which will only increase bundle size and decrease performance.
Can someone stop this environmentally unfriendly idea since everyone can calculate hash and encrypt data without this API but with bigger code size and lower speed.
Please reopen this. There is no justification given for the need of secure origin limitation. The use case of using this on HTTP is too important not to account for it. The most common use case:
This bug actually worsen the security because:
Currently, the only reason why one might want webcrypto.subtle to only be restricted to HTTPS is:
I'd like to add my voice to this chorus as well. Hiding the interface is pretty developer unfriendly. I can make do without it, but only by fetching a crypto library through a CDN (or copy-paste), which adds new potential points of failure (not to mention slowing down the page).
My use-case is just that I want to avoid sending out plaintext e-mail addresses in URLs over HTTP (which must then be decryptable on the other side). The context is not secure and can't be made secure. Not being able to access a standard library function because of the context in which it runs seems to violate the principle of least astonishment.
For us as well this limitation is unjustified. HTTPS is not a good default option for configurable enterprise intranet oriented IoT devices like IP cameras etc.
@X-Ryl669 put together a wonderful post detailing a plethora of reasons this was an incredibly stupid decision. I'd like to add to the list:
It seems like the only reason you decided to limit WebCrypto to HTTPS was because "Chrome did it first" -- that's bunk. Unless Chrome is now 100% of the World Wide Web Consortium and holds total sway over the future of web standards, they deserve a swift kick in the crotch and need to sit down.
Here's my use case that you're buggering with: I'm developing a video player. The video player will loads ads using the IMA SDK, and it will have analytics reporting playback statistics to AWS. Calls to AWS must be signed securely, and so I wish to use WebCrypto for SHA256 and HMAC generation. This player works when pushed to production where we have a valid SSL certificate and can use WebCrypto, but for local development it either fails because:
http://localhost
(in an attempt to avoid scripts spamming ad servers to generate fake ad views)hosts
entry to point http://test.local
to 127.0.0.1
(because now I'm suddenly in an insecure context)Now I'm forced to either generate an SSL certificate and run a web server just to test my player locally, push my code to production in order to test it (nope.jpg), or add some bulky and potentially insecure SHA256/HMAC library to my code (also-nope.jpg)
This asinine "requirement" (which makes the web slower, less secure, and less user friendly) has now turned my new developer onboarding steps from:
npm install
To:
npm install
hosts
fileRunning into this absurdity as well, internal use, cant HTTPS/SSL/ect, should have exceptions at the very least. No option = anti open
+1
I have a scientific application running offline that uses the web browser for rendering. I simply call crypto.subtle.digest
to calculate a hash of function arguments that is used for memoizing an expensive function. Was confused why my app stopped working once I left localhost and found this issue. I can write my own hashing function, but it's insane to think that this standard doesn't trust developers to call a hash function in an insecure context. A hash function has many uses besides crypto.
I'm using a third-party libary that itself relies on certain hash functions provided in window.crypto.subtle
so I really need the global defined.
I was able to shim this in webpack for local development on an insecure host like http://my-virtualbox-vm
like so:
npm install --save-dev @peculiar/webcrypto
// webpack.config.dev.js
var webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.ProvidePlugin({
'CryptoShim': '@peculiar/webcrypto',
}),
]
}
// index.js (executes in browser context)
if(window.crypto.subtle === undefined){
console.warn(`Shimming window.crypto.subtle using Nodejs library!`);
let Crypto = new CryptoShim.Crypto();
window.crypto.subtle = Crypto.subtle;
}
I hope this can help any other webpack users for local development.
That said, in my case, I am actually consuming a cross-domain API secured by TLS so it is pretty silly not to be able to generate hashes, signatures, etc., as required for API clients. In production, this client will be served also over TLS.
Another option for individuals just working locally over HTTP is to enable the chrome://flags/#unsafely-treat-insecure-origin-as-secure
flag for Chrome.
Can the digest functionality be made accessible? Even on a different API to distinguish it. I just want to create a digest of some text. There is nothing security critical about my use case, otherwise I have to store a far larger blob of text for comparisons.
In case anyone else is looking for a simple digest I'm trying https://github.com/indutny/hash.js and it seems to work well. For my purposes SHA-1 works just fine. It's a pity I'm not allowed access the perfectly serviceable native solution though.
This is absurd. For what god camn reason shouldn't I be able to get the checksum of a file just because I'm not using https? What were you thinking? Why shouldn't I be able to use any feature at all unless I'm on https?
If anyone is looking for HMAC-SHA256 support (and not just a checksum or simple digest), I wrote the following for my project:
https://gist.github.com/stevendesu/2d52f7b5e1f1184af3b667c0b5e054b8
The code was designed for efficient minification, and intended to be loaded via CommonJS - but it can be pretty trivially wrapped to support other use cases. For instance:
var hmac = {};
(function (module) {
// ... paste code here ...
})(hmac);
// can utilize hmac here without requiring CommonJS
The module exports 3 methods:
Usage:
var hmac = require("./hmac");
var key = "mySecretKey";
var data = "myData";
var signature = hmac.hex(hmac.sign(key, data));
Also, what's the deal with "chrome did so it's standard now"? Am I the only one that thinks a single corporation whims shouldn't dictate technical standards? If they want to do weird stuff and require https, that's their problem.
This is absurd. For what god camn reason shouldn't I be able to get the checksum of a file just because I'm not using https? What were you thinking? Why shouldn't I be able to use any feature at all unless I'm on https?
This is covered in the comments, but admittedly quite some time ago.
If you are on HTTP you are vulnerable to a MITM attack which could replace the webcrypto API (or indeed any of your code) with an attackers version. So, then, all security bets are off. For example, the attacker's webcrypto could return the checksum you expect for a file, but the file could still be the attacker's version.
At the time of writing, there were large, well-known, supposedly reputable ISPs conducting MITM attacks on the Internet to modify the Javascript code on websites. So the argument that MITM attacks are hard or rare or only applicable in particular network scenarios didn't carry much weight.
There are trade-offs, of course, as noted above, as there could be applications concerned only about passive attacks and they could work over HTTP with Webcrypto if webcrypto was not restricted to secure contexts.
@mwatson2 Out of curiosity, if malicious JavaScript has been executed in an insecure context, what is to stop someone from shimming window.crypto.subtle
anyway as I had in this comment? It doesn't seem like removing the API accomplishes anything?
@mwatson2 that's a reason to use https, not a reason to FORCE people to use https. Why should people be FORCED to use it?
@StephenLynx The reason is that webcrypto over http is not functional - in the practical sense of being able to rely on the results - except in very limited circumstances. So it would be misleading for the standard to suggest that it was.
@patrickjrm Sure, an attacker performing a downshift attack from https to http could shim webcrypto. So the existence of the webcrypto API is not proof that the site has loaded over https. Nor is any other check that you do in JS that the attacker could spoof / disable. I don't see the relevance to the question of whether webcrypto should be available over http, though.
@mwatson2 What does that even means? You can't rely on the result of ANYTHING that's from IO. Are you going to force XMLHttpRequest to also be only usable under https? And if it's so important, why no one touched on it until chrome started requiring https?
And @mwatson2 is not for people to justify crypto being on http, is for people to justify why it shouldn't be. Imagine needing a justification for every single tool on every single context. That's the same as justifying a liberty. Is for the people denying the liberty to justify why it shouldn't be allowed. Otherwise it's a very authoritarian scenario. This is how I feel: this decision was fruit of pure authoritarianism. If people want to run unsecure websites that's their problem, not the standard.
If the standard for correctness of an API is that it cannot be corrupted by an attacker, what is the argument for enabling any API whatsoever, on HTTP or HTTPS?
HTTPS may protect against MITM attacks, but it does not protect against all forms of code injection. WebCrypto and other libraries are still vulnerable to attacks in an HTTPS environment, they're just vulnerable to a narrower range of attacks that are in principle easier to guard against.
What's more, all other libraries are just as vulnerable. Do the other libraries not carry significant risks too if they are corrupted? Is their correctness not also impossible to guarantee?
Is it within an API's jurisdiction to decide whether the caller is taking too great a risk by assuming that it is what it says it is? I personally do not think so.
I understand the need to balance between security and usability concerns, but this seems like an opaque, arbitrary decision that does not at all take the user's experience into account.
Remember that the error the user gets is that the specified API does not exist, not that it's correctness "cannot be guaranteed".
These are not unreasonable points. I'm just describing how the issue was decided because that context is way way back up the thread.
Different considerations apply to a cryptography API and other APIs that don't purport to enable implementation of secure protocols. End users have a particular interest in site developers not being given security footguns and end users interests come above site developers in the priority of constituencies. That's not to say there are no security footguns in the web platform, but the existence of others would not be an argument for introducing another one.
Nevertheless, there are trade offs, as I said, as this is how this one was decided.
No, it was decided because google decided on it and you decided that papa google knows best. People were OVERWHELMINGLY against it but it went forward anyway.
Speaking of which, who are you and who do you work for? I can't seem to find anything about you.
I've been following this issue for over a year. It's been quite saddening to see the complaints coming in over that time. I guess I hoped that the weight of the complaints would eventually add up to some kind of meaningful change.
@mwatson2 you say it's “decided” so I guess there's no reason to keep following the issue. I just wasn't aware that W3C worked that way.
Bug 25972 from bugzilla:
As with service workers implementations want to require a secure origin in order to get access to cryptographic functionality. We should make that a requirement in the specification so that implementations do not have to reverse engineer each other.
In particular you want to refer to the origin of http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#entry-settings-object
Secure origin is defined by https://w3c.github.io/webappsec/specs/mixedcontent/
Ryan probably knows which flavor of secure origin is to be used here.