In a great post about named routes in Rails, path vs. url, Viget Labs ponders which variant is best used.
Most often we use foo_path, which when used in Rails URL helpers will generate a relative path, where foo_url generates a full URL. In most cases the path makes most sense, but not always.
Can you see where this is going yet?
# to take Viget's example
map.resources :doohickeys
link_to 'index of doohickeys', doohickeys_url
# => <a href="http://www.example.com/doohickeys">index of doohickeys</a>
Where did www.example.com come from? Let’s take a look. In both Rails 2.3.5 and Rails 3 beta, if we have not explicitly passed in a :host option, we get @request.host_with_port. So, no matter what hostname you used to resolve the app, that hostname will be used to generate full URLs.
One man’s casual bug is another man’s security exploit, right? Let’s modify our local hosts file:
# /etc/hosts # map the target website's IP to your favorite web destination 10.0.0.0 emphaticsolutions.com
Now, when we visit the target website with our own domain, those URLs look like this:
map.resources :doohickeys
link_to 'index of doohickeys', doohickeys_url
# => <a href="http://emphaticsolutions.com/doohickeys">index of doohickeys</a>
If the target application is caching content that includes these links, and you’re lucky enough to hit an uncached section of the site, you’ve just injected your own hostname into the target’s website content for other users to see and click on. Your directing clicks on their site, back to yours.
Sure, there are a lot of variables that have to pan out for this issue to be exploitable. That doesn’t make the issue any less real. One solution to this would be to include a configuration option that is defined per environment, to identify the desired hostname for a given app. Think of it as the canonical hostname that should be used unless you explicitly set one when generating a URL. I think this solution works for most applications, and if you don’t use the configuration, you’ll get the existing behavior.
Another solution is to configure your web server to use a specific hostname for both http and https URLs. Here is that configuration for Apache:
So what do you think? Should Rails provide a configuration option to specify an app’s hostname, or is that outside the scope of what the app should be concerned with?