match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase- Best Practice:
- Either specify HTTP verbs or use
via: :allwhen adding routes with#match
- Either specify HTTP verbs or use
/^[a-z ]+$/i =~ "Joe User"
# => 0 # Match
/^[a-z ]+$/i =~ " '); -- foo"
# => nil # No match
/^[a-z ]+$/i =~ "a\n '); -- foo"
# => 0 # Match- Best Practice:
- Whenver possible, use
\Aand\zto anchor regular expressions instead of^and$.
- Whenver possible, use
- Best Practice:
-
Use the
secure_headersRubyGem by Twitter to add anX-Frame-Optionsheader with the value ofSAMEORIGINorDENY. -
or send this with header:
X-Frame-Options: SAMEORIGIN
-
Use @rkh's
rack-protectioninstead ofsecure_headersas provides more protection. +One thing secure_headers provides that rack-protection does not is Content Security Policy setup. Among other things, this gives you the ability to let browsers know they are not permitted to run inline javascript on the page. This drastically reduces the vector for script injection for attacks.
-
- Binding to 127.0.0.1 is a safer default than 0.0.0.0 in all Rails environments.
- The Fix:
- Rails already provides a
--bindingoption to change the IP address that the server listens on. The default should be changed from 0.0.0.0 to 127.0.0.1. Developers who need to bind to other interfaces in production can make that change in their deployment configurations.
- Rails already provides a
WebStore::Application.config.secret_token = '4f06a7a…72489780f'- Unfortunately, Rails falls flat in dealing with these secret token. The
secret_token.rbfile ends up checked into version control, and copied to GitHub, CI servers and every developer's laptop. - Best Practice:
- Use a different secret token in each environment. Inject it via an
ENVvar into the application. As an alternative, symlink the production secret token in during deployment.
- Use a different secret token in each environment. Inject it via an
class SignupsController < ApplicationController
def create
# ...
if params[:destination].present?
redirect_to params[:destination]
else
redirect_to dashboard_path
end
end
endhttps://example.com/sessions/new?destination=http://evil.com/
- Best Practice:
-
When passing a hash to
#redirect_to, use theonly_path: trueoption to limit the redirect to the current host:```ruby redirect_to params.merge(only_path: true) ``` -
When passing a string, you can parse it an extract the path:
```ruby redirect_to URI.parse(params[:destination]).path ```
-
<%= link_to "Homepage", user.homepage_url %>
user.homepage_url = "javascript:alert('hello')"
<a href="javascript:alert('hello')">Homepage</a>
- Head over to http://Rails-SQLi.org
class User < ActiveRecord::Base
serialize :preferences
store :theme, accessors: [ :color, :bgcolor ]
end- Best Practice:
-
Use the JSON serialization format instead of YAML for
#serializeand#store:```ruby class User < ActiveRecord::Base serialize :preferences, JSON store :theme, accessors: [ :color, :bgcolor ], coder: JSON end ```
-
- By default, Ruby on Rails uses a Cookie based session store. What that means is that unless you change something, the session will not expire on the server. That means that some default applications may be vulnerable to replay attacks. It also means that sensitive information should never be put in the session.
- Best Practice:
-
Use a database based session, which thankfully is very easy with Rails:
Project::Application.config.session_store :active_record_store
-
- Use the
strong_parametersgem with Rails 3.x
- Many Ruby on Rails apps are open source and hosted on publicly available source code repositories. Whether that is the case or the code is committed to a corporate source control system, there are certain files that should be either excluded or carefully managed.
/config/database.yml - May contain production credentials. /config/initializers/secret_token.rb - Contains a secret used to hash session cookie. /db/seeds.rb - May contain seed data including bootstrap admin user. /db/development.sqlite3 - May contain real data.