Security
Here we list tools and best practices that we use at NECOLT to make sure our web apps are as secure as possible.
Rails
- Use built-in framework CSRF protection
# Add the following to your ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery, with: :exception
end
# And add the meta tag to your HTML head
<%= csrf_meta_tags %>
- Always escape user-provided data (never call html_safe or raw on user-input without sanitizing first)
# GOOD: strip all tags and attributes that are not white-listed
<%= sanitize(@user.name) %>
# GOOD: data inserted in HTML is automatically escaped
<% @user.name %>
# BAD: data will be inserted in HTML without escaping
<%= @user.name.html_safe %>
- Avoid common security gotchas when using ActiveRecord methods.
- Explicitly whitelist attributes in controllers with strong parameters.
- Use rake secret to generate secret keys for encryption.
- Use secureheaders to add security-related HTTP headers in responses.
- Use devise for user authentication and password management.
- Use bundler-audit to check for vulnerable versions of gems in Gemfile.lock.
- Remove sensitive information from rails logs by adding rule to
config/initializers/filter_parameter_logging.rb
. - Read about and follow other security conventions in Rails guides.
- Regularly update libraries and technologies used in projects.
Securing File uploads
- Whitelist or blacklist extensions and content types in every Carrierwave uploader
class MyUploader < CarrierWave::Uploader::Base def extension_whitelist %w(jpg jpeg gif png) end def content_type_whitelist %r{image\/} end # alternatively def content_type_blacklist ['application/text', 'application/json'] end end
- Use ruby-filemagic to properly extract content type
class ContentTypeExtractor def initialize(file) @file = file end def filemagic @filemagic ||= FileMagic.new(FileMagic::MAGIC_MIME_TYPE) end def extract content_type = nil File.open(@file.path) do |fd| data = fd.read(1024) || '' content_type = filemagic.buffer(data) end content_type end end
React.js
- Do not use dangerouslySetInnerHTML on user-provided data.
Node.js
- Use up-to-date Node.js version.
- Use helmet to secure Express applications.
- Use secure cookie storage with strong secret keys. (cookie-session)[https://github.com/expressjs/cookie-session] is a good choice.
- Ensure dependencies don’t have vulnerabilities. nsp and snyk are good tools to find packages with vulnerabilities.
- Make sure ORM sanitizes parameters to queries, to prevent SQL injections. Use sqlmap to help detect SQL injection vulnerabilities.
Brakeman
Brakeman is an open source static analysis tool that we use to checks Rails applications for security vulnerabilities.
bundle exec brakeman -A -q
### Ignore false positives
Brakeman reports some vulnerabilities that are false positives. False positives are warnings about potential vulnerabilities which are not actual vulnerabilities. Before ignoring a false positive, be certain it is actually a false.
The -I option (or –interactive-ignore) is the simplest way to create and manage an ignore configuration.
Authorization
It is important to always check user permissions on resources that users can access or modify.
- When finding records, always use scopes to ensure proper access to the resources
class TasksController < ApplicationController # GOOD: task search is limited to current users tasks expose(:task) { current_user.tasks.find(params[:task_id]) } # BAD: user can access any task in the database by sending its id the request expose(:task) { Task.find(params[:task_id]) } end
- When more complicated authorization rules are necessary, use cancancan rubygem
Content encryption
When there is a need to have encrypted content use attr_encrypted to encrypt application data. If necessary, for performance reasons use attr_encrypted_pgcrypto which in turn uses PostgreSQL pgcrypto module to perform encryption and decryption.
Encryption key management
Encryption keys for content encryption should be stored in separate configuration file. This file should not be indexed by git and there should be a corresponding entry for a key file in .gitignore. Each project environment should have its own encryption key.
SSH
- Use strong passphrases (e.g. multiple words separated with special symbols) when generating ssh keys.
Using Passwords
- Use specific tool to generate random passwords (1password, pqgen, keepass.info).
HTTPS
- Use HTTPS rather HTTP.