match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
- Best Practice:
- Either specify HTTP verbs or use
via: :all
when 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
\A
and\z
to anchor regular expressions instead of^
and$
.
- Whenver possible, use
- Best Practice:
-
Use the
secure_headers
RubyGem by Twitter to add anX-Frame-Options
header with the value ofSAMEORIGIN
orDENY
. -
or send this with header:
X-Frame-Options: SAMEORIGIN
-
Use @rkh's
rack-protection
instead ofsecure_headers
as 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
--binding
option 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.rb
file 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
ENV
var 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
end
https://example.com/sessions/new?destination=http://evil.com/
- Best Practice:
-
When passing a hash to
#redirect_to
, use theonly_path: true
option 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
#serialize
and#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_parameters
gem 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.