Simple SSL Proxy for Insecure Browser Content with Ruby or NGINX

SSL protection is becoming de facto standard in web and mobile development. One potential problem is that website could be served via a secure SSL connection and still displayed as insecure by most of the modern browsers. It’s enough that at least one of its resources is served without SSL. In this blog post, I will explain how to setup Ruby and NGINX server to work as an SSL proxy for insecure content and describe some basic streaming techniques.

Until recently iTunes Store pages were displayed as insecure in the browsers because of http image assets. At the time of writing this blog post, iTunes API does not officially1 provide image assets via SSL.

If you want to display this kind of insecure asset2 on your webpage without browser warnings, here’s what you can do:

Download assets and serve them via Amazon S3

You could download all the required assets to deliver them via a secure connection. In this case Amazon S3 with CloudFront could serve you well. An advantage of this approach is that traffic does not go through your servers, and assets can be cached using CloudFront CDN. Unfortunately, you have to take care of updating assets yourself (app icons could change at any time), and pay for all the bandwidth.

“down” gem for streaming support

Each of the following examples uses down gem. It provides a simple API for working with file downloads and supports more advanced techniques like streaming and caching. It also has a small memory footprint of less the 0.4 MB on load.

Use Rails app as an SSL proxy

Another solution would be to proxy an asset request through a Rails-based server. In that case, a Rails app downloads an asset and sends it to the browser via a secure connection. You would need to include an asset location as a parameter of the request. Here’s how a simple Rails controller implementation could look like:

An advantage of this approach is that in case of large assets, they would not need to be instantiated into memory all at once. It’s an equivalent of using File.readlines instead of File.read when working with files. Depending on your use case you could play around with CHUNK_SIZE constant value.

Use NGINX as an SSL proxy

A different solution would be using an NGINX to proxy pass to an insecure assets. You can check out my previous blog post for tips on how to configure NGINX with free SSL. If you are using Heroku as your hosting provider, you can setup NGINX as a reverse proxy in front of your Rails app using a buildpack.

resolver 8.8.8.8; line is needed to dynamically resolve DNS config of a target asset server and enable support for different assets hosts. An advantage of this solution is that you don’t block your Ruby process and NGINX is better suited to handle multiple concurrent clients than Ruby servers.

Summary

I’ve been using the NGINX based solution in Smart Wishlist for quite a while now to serve iTunes assets via SSL to both React based frontend and iOS apps. Remember that if your project has a lot of traffic, you would need to watch out for problems with rate limiting by your assets API provider. You could also use these techniques to proxy pass any other kind of static assets, not only images.

Hope those tips can help you offload some of the work from your servers. Doing an SSL proxy pass is quicker and cheaper to implement than downloading the assets and hosting them yourself.

Disclaimer: As pointed out in the comments, these examples do not include any restrictions on how and which assets can be accessed. In theory bad guys could start piggybacking on a proxy configured like this. You should consider IP, host or asset type based whitelist to make it more secure.

iTunes API assets are available through SSL via an undocumented URL: http://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/50/b6/59/50b65977-5605-4cf3-eee6-6ff350a9c9c4/source/406x228bb.jpg but it could change at any time. Hopefully, Apple will migrate all of iTunes API to SSL only soon. Point of this blog post is to show what you could do if SSL version of the asset was not available at all. ↩