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.
Developer console and URL bar display insecure content warnings on https://wishlist.apki.io.
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.
You can check yourself:
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:
Then you could access the asset using the following URL:
Streaming for large assets
When dealing with a larger asset a better idea would be to stream it to client part by part. To do it you need to assign an object responding to
each method to
response_body controller property:
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.
You can also check out my other blog post for more tips on how to reduce memory usage in Rails apps.
Use Ruby Rack app as an SSL proxy
You could improve performance by dropping Rails altogether and using a barebones Rack app to serve the asset. Here’s a basic Rack server implementation:
You can run Rack apps with a rackup command
Assets streaming with Rack
Here is how you could send an asset part by part using
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.
Here’s a sample config:
resolver 18.104.22.168; 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.
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.jpgbut 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. ↩