Skip to content

Commit 4474a89

Browse files
[Issue #12] Security Audit (#26)
Co-authored-by: Rocket <[email protected]>
1 parent 8c2e720 commit 4474a89

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Application Security
2+
3+
Application security is a top priority for technology application development, which is why the Rails framework's security helper methods and countermeasures help speed up secure application delivery. However, the framework isn't useful by itself; its helper methods and configurations only work if they are used properly.
4+
5+
Each item below will be checked if it is already implemented by default, or unchecked if it is not implemented by default. This is meant to be a living document and should be updated as additional security tools and configurations are implemented, as well as when new vulnerabilities are discovered or introduced.
6+
7+
This document uses the Rails Guide to [Securing Rails Applications](https://guides.rubyonrails.org/security.html) to audit this project's Rails security best practices.
8+
9+
## Sessions
10+
We use Devise to manage sessions and cookies. Devise configuration is managed in the [`devise.rb`](app-rails/config/initializers/devise.rb) file. For more detailed information, see the [Devise documentation](https://rubydoc.info/github/heartcombo/devise).
11+
- [x] SSL (`config.force_ssl = true`) is enforced in production environments.
12+
- [x] Provide the user with a prominent logout button to make it easy to clear the session on public computers.
13+
- [x] Cookies stored client side do not contain sensitive information.
14+
- [x] Cookies time out in 15 minutes of inactivity
15+
- Note: That is set with `config.timeout_in` in the [Devise configuration file](app-rails/config/initializers/devise.rb).
16+
- [x] Cookies are encrypted client side.
17+
- Note: Devise uses BCrypt and the secret_key_base by default for secret hashing.
18+
- [ ] Expire sessions after a set amount of time, regardless of activity,
19+
- Note: Automated session expiration can be easily set by the auth service, such as in AWS Cognito.
20+
- [ ] Use a nonce generator to protect against cookie replay attacks.
21+
- Note: The commented out code for this is located in [`/app-rails/config/initializers/content_security_policy.rb`](/app-rails/config/initializers/content_security_policy.rb) Review the impact this may have if there are several application servers.
22+
- [x] Automatically expire sessions on sign in and sign out.
23+
- Note. This is set in the [Devise configuration file](app-rails/config/initializers/devise.rb) with `config.expire_all_remember_me_on_sign_out = true`.
24+
25+
## Cross-Site Request Forgery (CSRF)
26+
- [x] GET, POST, DELETE, and rails’ resources are used appropriately in the `routes.rb` file.
27+
- [x] Pass a CSRF token to the client.
28+
- Note: This is accomplished with `<%= csrf_meta_tags %>` in [application.html.erb](app-rails/app/views/layouts/application.html.erb)
29+
- [ ] Set forgery protection in production
30+
31+
## Redirection and Files
32+
There is currently no file upload or download functionality at this time, so please review these items when adding file management functionality.
33+
- [x] Do not use user inputs to generate routes (ie. creating a route with the username), which is vulnerable to XSS attacks.
34+
- [x] `link_to` methods do not interpolate to user inputs.
35+
- [x] `redirect_to` methods do not interpolate to user inputs.
36+
- [ ] Prevent files from being uploaded if the filename do not match a set of permitted characters.
37+
- Note: Filtering on filename on its own can still leave an application vulnerable to XSS attacks.
38+
- [ ] Do not allow file uploads to place files in the public directory as code in those files may be executed by the browser.
39+
- [ ] Prevent users from downloading files to which they shouldn't have access.
40+
- [ ] Prevent files from being downloaded if the filename do not match a set of permitted characters.
41+
- [ ] For website search, prevent including files in the search results if the file is not from an appropriate directory.
42+
43+
## User Management
44+
- [x] Store only cryptographically hashed passwords, not plain-text passwords.
45+
- [x] Consider Rails' built-in `has_secure_password` method which supports secure password hashing, confirmation, and recovery mechanisms.
46+
- Note: When using Devise there's no need to use `has_secure_password`.
47+
- [x] Username error is generic and does not indicate whether it was an error with the username or password.
48+
- [x] Forgot password confirms the email was sent, and not whether the username exists.
49+
- [x] Use a secondary verification when users change their password
50+
- Note: Change password requires 6 digit code from email sent to user's email address.
51+
- [ ] Require user's password when changing email.
52+
- [ ] Include honeypot fields and logic on Non logged in forms to catch bots that spam all fields (good resource: https://nedbatchelder.com/text/stopbots.html).
53+
- [ ] Consider using Captcha on account creation, login, change password, and change email forms.
54+
- Note: Captchas are often not accessible to screen readers and their use should be part of a UX discussion.
55+
- [x] Filter log entries so they do not include passwords or secrets
56+
- Note: Log filtering is set in [filter_parameter_logging.rb](app-rails/config/initializers/filter_parameter_logging.rb): `:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn`.
57+
- [x] Use the correct Ruby REGEX: `\A` and `\z` and not the more common: `/^` and `$/`.
58+
- [ ] Add `multiline: true` to regex `format:` in validations.
59+
- [x] When searching for data belonging to the user, search using Active Record from the user and not from the target data object. ie. Instead of doing: `@task = Task.find(params[:id])`, instead do: `@user.tasks.find(params[:id])`.
60+
- Note: This application is also using [pundit](https://github.com/varvet/pundit) to support resource authorization.
61+
62+
## Injection
63+
- [ ] When defining security related `before_action` and `after_action` on controllers, use `except: […]` instead of `only:[…]` Ie. Instead of `after_action :verify_policy_scoped, only: :index` use `after_action :verify_policy_scoped, except:[ :rails_health_check, :users, :dev, ...]`. This ensures that when new views are added, they're behind the security actions by default.
64+
- [x] Don't interpolate params into SQL fragments. Ie. `.where(“name ='#{params[:name]}'”`.
65+
- [x] Ensures all cookies are `httponly`.
66+
- Note: While we’re not setting `secure: true` on the cookies themselves, the `config.force_ssl = true` option in production sets them as `httponly`.
67+
- [x] Sanitize content in the erb files that come from user inputs, using `<%=h <some user provided input> =>` to protect against defacement.
68+
- [x] Use a permitted list of tags in inputs that allow html or when allowing a text input that will be converted into html, using:
69+
- Note: The most common Rails tool for text to html conversion is RedCloth.
70+
```
71+
tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p)
72+
s = sanitize(user_input, tags: tags, attributes: %w(href title))
73+
```
74+
- [x] Rails `sanitize()` method is used on inputs that will be presented to the UI, including the Admin UI if there is one.
75+
- Note: While consensus seems mixed about the necessity to sanitize Rails input fields for defacement, sanitizing inputs is very useful to protect against encoding injection.
76+
- [ ] Inputs for custom colors or CSS filters are sanitized with Rail's `sanitize()` method, and the application builds the CSS in the web application first and ensures it is valid CSS before sanitizing.
77+
- Note: We don't include that functionality, but this is a common attack vector in applications that do.
78+
- [x] Controllers that output strings, rather than views, are escaped.
79+
- [x] All methods called by the application to execute commands on the underlying operating system include the `parameters` parameter, ie. `system(command, parameters)`. Applicable methods include:
80+
* `system()`
81+
* `exec()`
82+
* `spawn()`
83+
* `command`
84+
- [x] Don't use the `open()` method to access files, instead use `File.open()` or `IO.open()` that will not execute commands.
85+
- [ ] [`ActionDispatch::HostAuthorization`](https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization) is configured in production to prevent DNS rebinding attacks.
86+
87+
## Unsafe Query Generation
88+
- [x] Confirm `deep_munge` hasn't been disabled.
89+
- Note: `config.action_dispatch.perform_deep_munge` is `true` by default.
90+
91+
## HTTP Security Headers
92+
Default security headers can be overridden in [application.rb](app-rails/config/application.rb) with `config.action_dispatch.default_headers`.
93+
- [x] Lock down X-Frame-Options to be as restrictive as possible.
94+
- Note: By default this is set to allow iframes from the same origin.
95+
- Note: Set this to deny if not using any iframes to embed.
96+
- Note: If you need to permit an iframe from another origin, a controller can then use an `after_action :allow_some_service`.
97+
- [ ] To help protect against XSS and injection attacks, define a Content-Security-Policy in the provided [content security policy file](app-rails/config/initializers/content_security_policy.rb).
98+
- Note: Set the policy to be more restrictive than you need and you can override defaults when necessary in the controllers.
99+
- [ ] Log content security policy violations to continuously improve security by setting the report_uri config on the content security policy and configure a controller to log the reports.
100+
- Note: `report_uri` is being deprecated, and will eventually become `report_to`.
101+
- [x] Set `csp_meta_tag` in [application.rb](app-rails/config/application.rb).
102+
- [ ] Use the `csp_meta_tag` tag with nonce generation in the content security policy.
103+
- [ ] Configure which browser features are allowed in [permissions_policy.rb](app-rails/config/initializers/permissions_policy.rb).
104+
- Note: This policy can be more restrictive than necessary because features can be allowed on specific controllers.
105+
- [ ] If opening up endpoints as APIs, configure CORS, by installing and configuring the `rack-cors` gem.
106+
107+
## Intranet and Admin Security
108+
If adding an Admin view, consider adding the following:
109+
- [ ] Sanitize all user inputs as they may be viewed here even if they aren't visible anywhere else in the application.
110+
Some effective admin protection strategies include:
111+
- [ ] Limit admin role privileges using the principle of least privilege
112+
- [ ] Geofence admin login IP to the USA.
113+
- [ ] Consider putting the admin app at a subdomain so the cookie for application can't be used for the admin console and vice-versa.
114+
115+
## Environmental Security
116+
- [x] Secrets are not stored in the application repository.
117+
118+
## Dependency Management and CVEs'
119+
- [x] Use a service to be notified when libraries are outdated
120+
- Note: We're using dependabot to notify us if we have outdated gems.
121+
122+
## Additional Reading
123+
* [Securing Rails Applications](https://guides.rubyonrails.org/security.html)

0 commit comments

Comments
 (0)