“Only Secure Origins Are Allowed”
– Chrome 47
Chrome 47 now forces secure origins (mostly) with HTTPS. This can be a pain to deal with, but Xander Dumaine is here to help with some guidance. Xander is a Senior Software Engineer who deals with the good and bad of WebRTC for Interactive Intelligence in Raleigh, NC. He is helping maintain simpleWebRTC and organises the Triangle WebRTC Meetup group in that area.
{“editor”: “chad hart“}
Chrome 47 brought a new change, and one that’s caused a lot of confusion and irritation for some WebRTC developers. Despite the warnings and PSAs from the WebRTC team at Google, and the console deprecation warning, some didn’t get the message that getUserMedia
now requires that the requesting app be served over HTTPS.
Here are a couple tips for quickly getting up and running with getUserMedia
on HTTPS in development and when deployed.
Development
localhost exception
The only exception to the HTTPS requirement is localhost. If you’re developing from a local server, you should be fine, as you can serve on localhost with HTTP or HTTPs.
So what happens if you’re developing from a different IP or host? If you’re comfortable setting up self signed certs for your services, you’re good to go. For many, this might be prohibitive.
Local proxy to localhost
Often developers will have a container or collection of containers for serving an application and related services. These typically all use HTTP communication. If you were to simply start serving the web content over HTTPS, and you’re connecting to a WebSocket for signaling, you’ll find that Chrome disallows connecting to an insecure WebSocket from a secure origin. In this case, you’ll want to continue using all HTTP traffic, but the only way to do so is with localhost. To do this, you really just want to create a reverse proxy for the web content. You can pick your own favorite method of doing this, but one that I find very easy is a little nginx proxy:
1 2 3 4 5 6 7 |
server { listen 8080; server_name localhost; location / { proxy_pass http://your.dev.box.ip:8080; } } |
Now, you can just visit http://localhost:8080. Your page will be served over HTTP, but because it’s localhost, Chrome allows getUserMedia
to continue, and you don’t have to worry about upgrading your WebSockets (WS) to secure WebSockets (WSS).
HTTPS proxy
Alternatively, if you do want to serve your web content over HTTPS, but don’t want to modify your services to use secure WebSockets for development, you can use a simple proxy to to upgrade your WebSockets as well. I have an example of those in node, using express:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
var express = require('express'); var https = require('https'); var httpProxy = require('http-proxy'); var pem = require('pem'); pem.createCertificate({ days: 1, selfSigned: true }, function (err, keys) { var httpsOptions = { key: keys.serviceKey, cert: keys.certificate }; var proxy = httpProxy.createProxyServer({ target: http://signaling.example.com, ws: true, secure: false, changeOrigin: true }); var proxyWebsocket = function (req, socket, head) { // replace the target with your signaling server ws url proxy.ws(req, socket, head, { target: 'http://signaling.example.com' }); }; var app = express(); var server = https.createServer(httpsOptions, app); server.on('upgrade', proxyWebsocket); server.listen(8443); }); |
With this method, you can create a secure websocket request to https://localhost:8443, which will be proxied to an insecure websocket to your development signaling server.
Deployment
When deploying your app, there are lots of ways to get HTTPS, like paying your hosting provider, or buying a cert yourself, but there are also some easy, free alternatives.
I’ve used two primary options for quick apps – Github Pages or surge + free CloudFlare https. Both are great if your apps is a static client app, and both allow you to use your own domain, with free SSL. Note that if this is a WebRTC app (not just getUserMedia
) and you’ve got a WebSocket for signaling, you’ll still have to make sure your signaling server has HTTPS as well. And for the near future, more free SSL is right around the corner.
Happy Encrypting!
{“author”, “Xander Dumaine“}
Chad McElligott says
ngrok.com is another nice resource for getting an HTTPS link to your development app. Very easy to use. I use it all the time and have had very few issues with it.
Coolio Jones says
I don’t believe this resolves the issue. You can use the https link provided by ngrok but Chrome will still not permit getUserMedia
gman says
If you’re using containers another solution is just to stick an HTTPS proxy in front. Just added a few lines to my docker-compose file and was done
https://github.com/dmp1ce/nginx-proxy-letsencrypt
Aaron Gokaslan says
I also found an extremely easy way to solve this issue for testing, no advanced setup required. There is a Python library that will forward all requests to a certain port(s) on localhost to any websites you choose. This allows for easy and rapid debugging since it takes advantage of the localhost exception for the policy.
https://pypi.python.org/pypi/maproxy
Note: This library is not in the Python base package, but it can easily be installed with pip.
Chad Hart says
Thank you for sharing!
darkknigh27 says
Hey, I am using getUserMedia in an iframe(https source) in a page deployed over http. How can i make this work? I am getting the same warning in the console