Everyone writing code must be responsible for security. đź”’
Start with the Rails Security Guide to see how Rails protects you.
-
Keep secret tokens out of your code -
ENV
variables are a good practice -
Even with ActiveRecord, SQL injection is still possible if misused
User.group(params[:column])
is vulnerable to injection. Learn about other methods
-
Use SecureHeaders
-
Protect all data in transit with HTTPS - you can get free SSL certificates from Let’s Encrypt
Add the following to
config/environments/production.rb
config.force_ssl = true
-
Add your domain to the HSTS Preload List
config.ssl_options = {hsts: {subdomains: true, preload: true, expires: 1.year}}
-
Protect sensitive data at rest with a library like attr_encrypted and possibly KMS Encrypted
-
Prevent host header injection - add the following to
config/environments/production.rb
config.action_controller.default_url_options = {host: "www.yoursite.com"} config.action_controller.asset_host = "www.yoursite.com"
-
Set
autocomplete="off"
for sensitive form fields, like credit card number -
Make sure sensitive request parameters aren’t logged
Rails.application.config.filter_parameters += [:credit_card_number]
-
Use a trusted library like Devise for authentication (see Hardening Devise if applicable)
-
Notify users of password changes
-
Notify users of email address changes - send an email to both the old and new address
-
Rate limit login attempts with Rack Attack
-
Log all successful and failed login attempts and password reset attempts (check out Authtrail if you use Devise)
-
Rails has a number of gems for authorization - we like Pundit
-
Ask search engines not to index pages with secret tokens in the URL
<meta name="robots" content="noindex, nofollow">
-
Ask the browser not to cache pages with sensitive information
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" response.headers["Pragma"] = "no-cache" response.headers["Expires"] = "Sat, 01 Jan 2000 00:00:00 GMT"
-
Use
json_escape
when passing variables to JavaScript, or better yet, a library like Gon<script> var currentUser = <%= raw json_escape(current_user.to_json) %>; </script>
-
Be careful with
html_safe
-
Don’t use assets from a public CDN, as this creates unnecessary availability and security risk
-
If you still use
attr_accessible
, upgrade to strong_parameters
-
Brakeman is a great static analysis tool - it scans your code for vulnerabilities
-
bundler-audit checks for vulnerable versions of gems
gem install bundler-audit bundle audit check --update
To fix
Insecure Source URI
issues with thegithub
option, add to the top of yourGemfile
:git_source(:github) do |repo_name| repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end
And run
bundle install
. -
npm audit checks for vulnerable versions of JavaScript packages (if you use
package.json
) -
git-secrets prevents you from committing sensitive info
brew install git-secrets git secrets --register-aws --global git secrets --install git secrets --scan
Subscribe to ruby-security-ann to get security announcements for Ruby, Rails, Rubygems, Bundler, and other Ruby ecosystem projects.
- Observatory scans your site for best practices
- Hakiri monitors for dependency and code vulnerabilities
- CodeClimate provides a hosted version of static analysis
- HackerOne allows you to enlist hackers to surface vulnerabilities
Have other good practices? Know of more great tools? Help make this guide better for everyone.
Also check out Production Rails.