Skip to content
This repository has been archived by the owner on Jan 20, 2019. It is now read-only.

Automatic SSL in development #106

Closed
wants to merge 2 commits into from

Conversation

davewasmer
Copy link

@davewasmer davewasmer commented Apr 28, 2017

@mfeckie
Copy link

mfeckie commented Apr 28, 2017

I, for one, welcome our new secure overlords 😄 . This will be a really useful addition.

@bcardarella
Copy link
Contributor

How would this work with requirements of having a named domain for the development cert?

@bcardarella
Copy link
Contributor

bcardarella commented Apr 28, 2017

Another issue: If devcert adds to the root CA then ember-fastboot/ember-cli-fastboot#375 will be a problem. Node doesn't use the system CA, it has its own internal hard-coded list.

@bcardarella
Copy link
Contributor

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

@workmanw
Copy link

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

@rwjblue
Copy link
Member

rwjblue commented Apr 28, 2017

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:

  • 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 have a separate command to setup the cert (separate from ember s), perhaps ember setup-ssl?
  • We should likely strongly suggest that folks use SSL by default on their dev boxes. This may just be a warning that is emitted during ember s if you haven't ran the separate ember ssl-setup command (mentioned above).

@davewasmer
Copy link
Author

@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 😉). 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.

@stefanpenner
Copy link
Contributor

Would love this! (Assuming we nail the ergonomics)

@workmanw
Copy link

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?

@stefanpenner
Copy link
Contributor

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.

@workmanw
Copy link

... as lots of high profile sites (such as gmail) use cert pinning

Ah right. That's a good point.

@davewasmer
Copy link
Author

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.

@davewasmer
Copy link
Author

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 ...

@davewasmer
Copy link
Author

As far as I can tell, the -s flag I mentioned above does not provide functionality similar to Name Constraints, unfortunately.

@davewasmer
Copy link
Author

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?


# Motivation

Many of the newest web platform features (i.e. service workers) require HTTPS transport. Generating
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that you could also test Service Workers against localhost:

In order to facilitate local development, localhost is considered a secure origin by browsers as well.

MDN

@rwjblue
Copy link
Member

rwjblue commented May 15, 2017

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:

  • Add SAN support (as mentioned in Automatic SSL in development #106 (comment))
  • Determine if we can enable domain pinning for browsers that allow it?
  • 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").
  • Have a few folks do a general review of the devcert lib (its small enough to read through in a sitting and pretty well documented IMHO).

@stefanpenner
Copy link
Contributor

@iagox86 if you have any cycles, I would love your input here. Maybe we can chat about it when you are in-town?

@iagox86
Copy link

iagox86 commented May 15, 2017

I usually defer to @alexwebr on SSL questions.. maybe he has some insight?

@davewasmer
Copy link
Author

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.

@alexwebr
Copy link

alexwebr commented May 31, 2017

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?

@stefanpenner
Copy link
Contributor

stefanpenner commented May 31, 2017

@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:

  1. 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.

Is it possible for us to create one-shot (per domain) root authorities? Basically, something like:

  1. create a new local SSL domain `ember add-domain my-dev.dev'
  2. prompt for sudo
  3. generate a root CA pair (private/public)
  4. install that CA
  5. sign the leaf certificate (for the domain)
  6. discard the root CA's private key
  7. update /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:

  • is ^ reasonable?
  • Whats the best way to configure this for reuse/sharabillity between developers

@davewasmer
Copy link
Author

@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.

@stefanpenner
Copy link
Contributor

stefanpenner commented Jun 6, 2017

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 remove
  • ember domain:init sets up all domains in the rc file

@davewasmer
Copy link
Author

It 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?

@stefanpenner
Copy link
Contributor

stefanpenner commented Jun 6, 2017

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

@knownasilya
Copy link
Contributor

@davewasmer is devcert more stable now for this?

@davewasmer
Copy link
Author

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.

@rwjblue
Copy link
Member

rwjblue commented Jan 19, 2019

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!

@rwjblue rwjblue closed this Jan 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants