Closed davewasmer closed 5 years ago
I, for one, welcome our new secure overlords 😄 . This will be a really useful addition.
How would this work with requirements of having a named domain for the development cert?
Another issue: If devcert
adds to the root CA then https://github.com/ember-fastboot/ember-cli-fastboot/issues/375 will be a problem. Node doesn't use the system CA, it has its own internal hard-coded list.
One more concern, a quick review of devcert
it doesn't look to be generating certs with a SAN. As of Chrome 58 the CN is no longer accepted and the cert will be rejected. A SAN is required: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category$3ACanary%7Csort:relevance%7Cspell:false
We use SSL for dev and we also got bit by not having a SAN on our devcert. My personal experience with self-signed cert leads me to believe there just a lot of subtleties that are going to make this approach not great.
I actually think a better solution would be to have an ember-cli util that can generate a self-signed cert on multiple platforms, put it into a directory in the app, modify the .ember-cli
file and lastly provide the user with instructions about how to get the cert trusted globally on their OS (Mac OS => KeyChain.app
, Linux => ca-certificates/certutil
).
Something like:
$ ember generate-ssl-cert --hostnames=localhost,localdev,myappdev
> Cert has been generated (ssl/server.cert and ssl/server.key)
> `.ember-cli` has been modified to use this cert
> You will need to add this cert to your OS keychain, more info can be found at: https://ember-cli.com/user-guide#ssl-cert
How would this work with requirements of having a named domain for the development cert?
I believe that it would need to be provided, which is why (below) I suggest using a separate command for setting up (separate from ember s
).
One more concern, a quick review of devcert it doesn't look to be generating certs with a SAN. As of Chrome 58 the CN is no longer accepted and the cert will be rejected.
Awesome, thanks for pointing that out @bcardarella!
I actually think a better solution would be to have an ember-cli util that can generate a self-signed cert on multiple platforms, put it into a directory in the app, modify the .ember-cli file and lastly provide the user with instructions about how to get the cert trusted globally on their OS (Mac OS => KeyChain.app, Linux => ca-certificates/certutil).
@workmanw Isn't that what the devcert
library does (and what is being proposed)? It generates a machine + app specific cert, and updates the machine to trust it.
FWIW, I do agree that there are some ergonomics to work out though. For example:
ember s
, which means the cert details should be installed into .ember-cli
file.ember s
), perhaps ember setup-ssl
?ember s
if you haven't ran the separate ember ssl-setup
command (mentioned above).@workmanw Isn't that what the devcert library does (and what is being proposed)? It generates a machine + app specific cert, and updates the machine to trust it.
Yep, exactly. The root devcert certificate authority is added to the machine's various trust stores so we can avoid the tedious process of trusting a certificate for each app.
I think the benefit devcert (or something like it) provides here is precisely that: it does the tedious trust-the-certificate work, letting you avoid telling the user to "open Keychain Access, add to there with SSL policy, now run brew install certutil, then locate your Firefox profile directory ..."
One more concern, a quick review of devcert it doesn't look to be generating certs with a SAN. As of Chrome 58 the CN is no longer accepted and the cert will be rejected.
Thanks for the heads up on this. I'll dig into it, but at first glance looks like an easy fix in devcert.
I want to be able to launch with ember s, which means the cert details should be installed into .ember-cli file. We should likely strongly suggest that folks use SSL by default on their dev boxes.
Ergonomics is definitely important here (well, it's basically the only thing the RFC does :wink:). But I'm not sure I see how this would be better. Wouldn't just setting "ssl": true
in .ember-cli
and using the proposed semantics from the RFC do the same thing here? Not sure I see the benefit to requiring a separate setup command, since devcert will automatically trigger the "setup" flow on first-run, and never after that.
Would love this! (Assuming we nail the ergonomics)
The root devcert certificate authority is added to the machine's various trust stores so we can avoid the tedious process of trusting a certificate for each app.
Hmm, this is both interesting and a little scary. I would like to read more about this because adding a CA as trusted to the machine seems like it could potentially open it up to Man-in-the-middle. I'm imagining that the devcert CA's private key is stored on the disk so it could be accessed at runtime by the server to sign a cert. But if an attacker could get that CA private key, they could generate a gmail
cert that would be trusted by your browser, right?
they could generate a gmail cert that would be trusted by your browser, right?
not quite (but still not ideal), as lots of high profile sites (such as gmail) use cert pinning.
... as lots of high profile sites (such as gmail) use cert pinning
Ah right. That's a good point.
One additional option might be to leverage a Name Constraints extension, which would let us restrict the available domains that the root CA could sign for to something like localhost
and .dev
. The challenge there is that it looks like macOS doesn't support Name Constraints, but there might be some kind of different workaround there.
It appears that macOS might have something that could compensate for their lack of Name Constraint support, but the docs are frustratingly lacking. When devcert adds the root CA to the macOS system keychain, it uses the security
command, which mentions the following argument:
-s policyString Specify policy-specific string.
It doesn't provide any further detail, and googling around has only turned up this StackOverflow answer which seems to suggest it might restrict the certificate to certain domains:
In addition, it is probably wise to specify the policy string using the -s flag... in my case that's just the localhost.
I'll do some testing to see if I can figure out the behavior ...
As far as I can tell, the -s
flag I mentioned above does not provide functionality similar to Name Constraints, unfortunately.
Haven't gotten around to updating devcert to support SAN just yet, but just wanted to check about the security concerns above. Does that seem like a showstopper?
Haven't gotten around to updating devcert to support SAN just yet, but just wanted to check about the security concerns above. Does that seem like a showstopper?
I don't think it is fundamentally a show stopper, but we need to do some due diligence to make sure we are all comfortable (there is little worse than security enhancements that accidentally end up being exploitable).
From my perspective, I think we need to do at least the following:
devcert
lib (its small enough to read through in a sitting and pretty well documented IMHO). @iagox86 if you have any cycles, I would love your input here. Maybe we can chat about it when you are in-town?
I usually defer to @alexwebr on SSL questions.. maybe he has some insight?
Add SAN support
I'll probably wait until we settle some of the specifics here before tackling this, in case further changes are needed to devcert as well, so I can avoid the additional context switching.
Determine if we can enable domain pinning for browsers that allow it?
My understanding of cert pinning was that the browser would pin the cert for a server/domain that requested it, and multiple domains could pin the same cert. If that's the case, I'm not sure what we could do on our side to make things more secure via pinning. If we pinned the locally generated certs, that wouldn't prevent an attacker's ability to generate their own certs off the root authority to MITM some third party site that doesn't pin.
Determine about creating a machine specific CA. I think the rest of the general tooling proposed here is good even if we have to ask for elevated permissions per-app (though I do hope we can find a good solution that makes us all happy and doesn't require elevated permissions "all the time").
An alternative to the vulnerable trusted root CA approach (that I think @rwjblue is hinting at here) is to install a non-CA certificate, per-app, into the system trust stores. This avoids letting attackers generate arbitrary trusted certs, and is better than "sudo prompt every time you run ember s
", but does mean a prompt per-project and leaves open possible MITM on the development domains (a far smaller concern I'd say).
Although - after thinking this over a bit more, the common use case is actually better than I originally thought. Unless users are doing some DNS hackery or editing their hosts file (which is not most people I'm guessing), they'll will be hitting localhost
to run their app. We only need to generate one trusted cert per domain, so one cert / one prompt for all your apps running localhost
would work.
An alternative to the vulnerable trusted root CA approach (that I think @rwjblue is hinting at here) is to install a non-CA certificate, per-app, into the system trust stores. This avoids letting attackers generate arbitrary trusted certs, and is better than "sudo prompt every time you run ember s", but does mean a prompt per-project and leaves open possible MITM on the development domains (a far smaller concern I'd say).
@davewasmer What's the MITM scenario you're thinking about, in this case?
@davewasmer good job on devcert! I think this direction is great, I am glad you have done much of the heavy lifting already.
Given some thought to a detailed design/workflow:
sudo
usage can cause some sadness, as permissioning issues spread like a contagion. Is it possible for us to create one-shot (per domain) root authorities? Basically, something like:
/etc/hosts
for my-dev.dev localhost
This should mitigate my concerns about leaking the power of creating new valid (for that keychains) certificates.
Questions:
@davewasmer What's the MITM scenario you're thinking about, in this case?
@alexwebr For example, macOS apparently hits the network when attempting to do a DNS lookup on localhost. That means that, if an attacker than is able to access the locally stored copy of the localhost
certificate and able to intercept the DNS lookup on the network, they could resolve localhost to an attacker-controlled machine and use the localhost
certificate to make the connection trusted.
Of course, that's means your environment is already severely compromised, and would only let the attacker impersonate localhost
, so IMO the risk is acceptably small.
Never require any ember command to be run with sudo, instead prompt with a native dialog (if/when possible) and run the privileged code in a sub-process? Accidental sudo usage can cause some sadness, as permissioning issues spread like a contagion.
Definitely agree with the goal, not sure about the implementation. When you say prompt with a "native" dialog - do you mean a sudo prompt on the command line that is visible because the parent ember process is sharing the pipe with the child? Or do you mean an actual GUI dialog box? Not sure how to trigger the latter off the top of my head.
Is it possible for us to create one-shot (per domain) root authorities?
I think (I'd have to actually try it out to double check) that we can just trust the leaf certificate without needing the root CA. Basically, the CA ability of a given cert is just a flag on the cert itself - you can add a cert to the trust stores with or without that flag.
create a new local SSL domain `ember add-domain my-dev.dev' Whats the best way to configure this for reuse/sharabillity between developers
Since the proposed add-domain
command would be system-wide (a.k.a. non-project-specific), perhaps we could add something like domains
to .ember-cli
, combined with some system-wide tracking of "installed" domains. That way, you can see something like:
my-project/$ ember serve
ERROR: This project requires the following custom development domain(s) to be setup:
my-project.dev
admin.my-project.dev
Run `ember add-domain <domain name>` to setup a custom development domain.
Or, we could automatically run the add-domain command when expected domains are missing (but I know there was some concern above about prompting for elevated permissions on ember serve
).
We could even add a --save
flag, so that ember add-domain my-app.dev --save
would add the domain to the local .ember-cli
.
Definitely agree with the goal, not sure about the implementation. When you say prompt with a "native" dialog - do you mean a sudo prompt on the command line that is visible because the parent ember process is sharing the pipe with the child? Or do you mean an actual GUI dialog box? Not sure how to trigger the latter off the top of my head.
Ya, this may not be required, but the important bit is that the command run with elevated permissions is limited to very very specific script (not all of ember-cli).
I was thinking of evaluating something like: https://www.npmjs.com/package/sudo-prompt to make it feel more legit :)
Since the proposed add-domain command would be system-wide (a.k.a. non-project-specific), perhaps we could add something like domains to .ember-cli, combined with some system-wide tracking of "installed" domains. That way, you can see something like:
Ya that sounds good
ember add-domain my-app.dev --save
Some ideas:
ember domain:add www.my-startup.com
(save by default)ember domain:remove www.my-startup.com
removeember domain:init
sets up all domains in the rc fileIt feels like there's really two levels of commands here - system wide "installation" of the domain, and per-project "configuration" of the domain.
For example, if I run
my-app/$ ember domain:add my-app.dev # Installs the domain in /etc/hosts, generates cert, and saves to local .ember-cli
Then:
my-app/$ ember domain:remove my-app.dev
What happens? Is the domain "uninstalled" from my system (i.e. removed from /etc/hosts, SSL cert untrusted, etc)? Is it removed from my local .ember-cli
?
What happens? Is the domain "uninstalled" from my system (i.e. removed from /etc/hosts, SSL cert untrusted, etc)? Is it removed from my local .ember-cli?
My first thought is that it would remove from SSL. /etc/hosts and .ember-cli
@davewasmer is devcert more stable now for this?
Yes - the recent release of 1.0 should put it in a good spot for this. I'm also working with the webpack, preact, and gatsby CLI teams to integrate with them as well.
Of particular note for Ember: the new version now ships with an overridable ui
layer, allowing the consuming library to completely control all the user-facing prompts and language, meaning Ember-CLI could customize it for it's own workflow.
We are working on closing the ember-cli/rfcs repo in favor of using a single central RFC's repo for everything. This was laid out in https://emberjs.github.io/rfcs/0300-rfc-process-update.html.
Sorry for the troubles, but would you mind reviewing to see if this is still something we need, and if so migrating this over to emberjs/rfcs?
Thank you!
Rendered