insecure content from aws s3 - ruby-on-rails-3

I'm storing photos using aws s3 and I get a chrome warning saying some of the content on the site isn't secure. In the dev console I see:
The page at https://domain.herokuapp.com/users/1/ displayed insecure content
from http://s3.amazonaws.com/domain/photos/user_thumbnail/casing-earphones.jpg?1365720318.
The amazon link isn't https how can I fix this my apps access to the entire bucket?
Following the setup instructions here: https://devcenter.heroku.com/articles/paperclip-s3
I have the following code I guess i need to add a URL option somewhere somehow:(config/environment/production.rb)
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['AWS_BUCKET'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
}
}

I needed to add this line:
:s3_protocol => 'https'
It's not mentioned in the setup instructions but paperclip s3 configuration options can be found here: http://rdoc.info/github/thoughtbot/paperclip/Paperclip/Storage/S3

You may be able to just add the s to the http URL and have it work fine. If that works, then fix the link to refer to https instead of http.
If that doesn't work, you may need to contact Amazon customer service. As long as you have links to http pages from an https connection you and your users will get that message. More importantly however, you open your users up to XSS, CSRF, and MitM attacks.

Related

Wildcard subdomain cookies ignored in some browsers. Rails 3.2 app on Heroku

I have a rails 3.2 app on Heroku using Devise.
Starting after a deploy yesterday, the session_id quit being stored on some browsers.
After a debugging marathon, we discovered that our cookies were being set up like this:
Application.config.session_store :cookie_store, :domain => :all
This was sending the set cookie header with a domain of .herokuapp.com, allowing us to visit our development, staging, etc.
This code has been working for > 1 year. Yesterday, after a deploy, the bug arose.
The fix was setting the domain explicitly, using the actual subdomain in the cookie domain:
Application.config.session_store :cookie_store, :domain => 'example.herokuapp.com'
While this "fixed" the problem, I have not figured out why this cookie was being ignored by some browsers, but not others. They should all allow wildcard subdomain cookies AFAIK.
Please help me understand this issue.
On May 14, 2013, herokuapp.com was added to the Mozilla Foundation’s Public Suffix List. This list is used in several browsers (Firefox, Chrome, Opera) to limit how broadly a cookie may be scoped.
Source: https://devcenter.heroku.com/articles/cookies-and-herokuapp-com

API subdomain for Heroku app, is it possible?

I am trying to build an API and I am concerned that all my resources will either not be accessible with the api.myapp.com domain or that they will "live" with the wrong uris.
I have added the CNAME for my domain name to point to my Heroku app.
(ex: browsing to www.myapp.com takes you to https://myherokuapp.heroku.com)
I would like to set up an API subdomain, so that a GET to
https://api.myapp.com takes you to https://myherokuapp.heroku.com/api/v1
The best scenario would be that a POST to https://api.myapp.com/accounts/12345 would create a new account. Is that even possible?
(I know that subdomains (eg: mysubdomain.myappname.heroku.com) are not possible with Heroku)
I believe the answer could be in three different places:
Something to do with DNS provider forwarding configs (maybe
something to do with "A" records).
Something to config in Heroku, possibly a paid add-on to handle domains/subdomains.
Handle all subdomains within my app.
If you want to differentiate between api.mydomain.com and www.mydomain.com and have different controllers for your API requests then you could certainly use Rails routes constrained to your api subdomain to handle this
constraints :subdomain => "api" do
scope :module => "api", :as => "api" do
resources :posts
end
end
which would then use the posts_controller.rb in the app/controllers/api folder of your application.
You'll then have both www.mydomain.com and api.mydomain.com added a custom domains for your application and then the routes will take care of the rest.
You might also want to look into the Grape Gem for helping build your api

Will this approach freeze the application?

I am using Heroku and Amazon S3, for storage.
I'm trying to make the download dialogue appear for the audio file, instead of the browser playing it.
In one of my controllers, I have:
response.content_type = 'application/octet-stream'
response.headers['Content-Disposition'] = "attachment; filename=#audio.filename"
response.headers['X-Accel-Redirect'] = #audio.encoded_file_url
render :nothing => true
#audio.encoded_file_url returns http://bucket_name.s3.amazonaws.com/uploads/19/test.mp3.
Which seems to work on my local machine. However, I am wondering if this approach will block an entire HTTP request handler, freezing the app until the download completes.
In Heroku, a HTTP request handler is one Dyno. And having several Dynos is expensive.
I'm not sure that you can rely on nginx being used (X-Accel-Redirect is an nginx-ism) - the heroku docs imply that it's not always used.
In addition, X-Accel-Redirect is, to my knowledge only for redirecting to files actually on the server, not for externally hosted files. Why not do a normal redirect to the S3 hosted file (using an authenticated URL if needed) ?
If you need to set headers like content disposition, this can be done either at time of upload or afterwards. If you use fog to do your s3 business you could do it like this (assuming storage is a Fog::Storage object)
storage.copy_object("your_bucket", "filename","your_bucket","filename", "x-amz-metadata-directive" => 'REPLACE', 'Content-Disposition' => '...')
Note that this overwrites all the metadata - if you have other fields such as Content-Type, Cache-Control etc. then make sure to set them here or they will be lost.
I would really recommend against letting users download files from your application via the dynos that your using to server your pages. Any static assets should really be served from S3, which you can then direct users to for file downloads.
Whilst the user is downloading, your dyno is effectively just feeding that file to them, and thus unable to do anything else.

Rails 3.1 force .html instead of no extension

One of my clients wants his new Rails application to look more like his traditional web site. He wants to know if I can force urls to have a file extension, preferably .html.
I don't want to hard-code the extension in routes.rb as
match ':controller/:action/:id.html'
(or similar) because the client also wants to have a respond_to-style JSON API which requires the use of .:format.
Can this be done?
Just as Mattias Wadman suggested, in config/application.rb add:
AppName::Application.default_url_options = { :format => "html" }
But also change config/routes.rb to:
root :to => 'pages#home', :defaults => { :format => "html" }
Im no Rails routing expert but I tried to force HTML format by changing the default URL options and at least the URL helpers seams to generate .html URLs now, it's a start.
config/application.rb (at the bottom)
AppName::Application.default_url_options = {:format => "html"}

rails 3 sessions across subdomains not working in Internet Explorer

I am working on a rails 3 application which use subdomains. I used railscasts #221 "Subdomains in rails 3" (http://railscasts.com/episodes/221-subdomains-in-rails-3) as a guide and everything goes well, except in Explorer.
To keep my session across all the subdomains I put the next line in session_store.rb as the tutorial says:
MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => "example.com"
I have tested my app on Firefox and Chrome and it works well, but for some reason is not working at all in Internet Explorer. The behavior is strange because sometimes it seems the session is share across all my subdomains, but some others there are some subdomains where I am logged in and other sudomains where I am not logged in.
I can't find any reason for this and I would appreciate any idea...
I am using Devise for authentication with rails 3.0.5
I believe you'll need to change your domain value to .example.com (the leading dot indicates that the cookie can be used across subdomains):
MyApp.application.config.session_store :cookie_store, :key => '_myapp_session', :domain => ".example.com"
For some reason this did not work (rails 3.2.11) for any session data that was set on a subdomain. It took a piece of custom Middleware to fix it. A summary of that solution is below.
tl;dr: You need to write a custom Rack Middleware. You need add it into your conifg/environments/[production|development].rb. This is on Rails 3.2.11
Cookie sessions are usually stored only for your top level domain.
If you look in Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com} You can see that there will be separate entries for sub1.yourdomain.com and othersub.yourdomain.com and yourdomain.com
The challenge is to use the same session store file across all subdomains.
Step 1: Add Custom Middleware Class
This is where Rack Middleware comes in. Some relevant rack & rails resources:
Railscasts about Rack
Railsguide for Rack
Rack documentation for sesssions abstractly and for cookie sessions
Here is a custom class that you should add in the lib
This was written by #Nader and you all should thank him
# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
def initialize(app, default_domain)
#app = app
#default_domain = default_domain
end
def call(env)
host = env["HTTP_HOST"].split(':').first
env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{#default_domain}"
#app.call(env)
end
def custom_domain?(host)
host !~ /#{#default_domain.sub(/^\./, '')}/i
end
end
Basically what this does is that it will map all of your cookie session data back onto the exact same cookie file that is equal to your root domain.
Step 2: Add To Rails Config
Now that you have a custom class in lib, make sure are autoloading it. If that meant nothing to you, look here: Rails 3 autoload
The first thing is to make sure that you are system-wide using a cookie store. In config/application.rb we tell Rails to use a cookie store.
# We use a cookie_store for session data
config.session_store :cookie_store,
:key => '_yourappsession',
:domain => :all
The reason this is here is mentioned here is because of the :domain => :all line. There are other people that have suggested to specify :domain => ".yourdomain.com" instead of :domain => :all. For some reason this did not work for me and I needed the custom Middleware class as described above.
Then in your config/environments/production.rb add:
config.middleware.use "CustomDomainCookie", ".yourdomain.com"
Note that the preceding dot is necessary. See "sub-domain cookies, sent in a parent domain request?" for why.
Then in your config/environments/development.rb add:
config.middleware.use "CustomDomainCookie", ".lvh.me"
The lvh.me trick maps onto localhost. It's awesome. See this Railscast about subdomains and this note for more info.
Hopefully that should do it. I honestly am not entirely sure why the process is this convoluted, as I feel cross subdomain sites are common. If anyone has any further insights into the reasons behind each of these steps, please enlighten us in the comments.