Here I will list some basic security measures from my experience which are easy to implement and you can effortlessly incorporate into your application.
Emails are something that almost every contemporary web application requires from the user when one is making a registration. Think of those scenarios when implementing a user registration feature:
Disposable emails are emails that live for a very short amount of time. They are usually used to create fake users. Intentions vary depending on the particular individual. Some people might use them innocently to check up the app's features (without leaving any personal data) while others might deliberately use disposable emails for spam and malicious actions.
In general, this types of registrations do not enrich your database with valuable users.
You can find a blacklist online that you could incorporate into your app's registration feature.
This one is somehow trivial but it is worth mentioning as some web apps that I've seen just do not require a password on email change. One must take into consideration the case when a user changes her email address. Always require a password on email change. This prevents from account hijacking - ensure that the change of the email is made by the actual user and not somebody else when, for example, the particular user has forgotten to log out.
This is another easy to implement step:
Imagine that you have a one-to-many association for your
class User < ApplicationRecord has_many :pictures end
class Picture < ApplicationRecord belongs_to :user end
A common mistake is to query the pictures model like so:
This is not optimal from the perspective of security. For example,
some_id might be something else and not an integer (e.g. an array of ids). Always use scope loading. In this scenario it is better to use only:
Something which relates to the aforementioned. Always convert your values with
to_i, etc. in order to avoid any unexpected input which might be used for injection. Use this especially on input params in the case when user input is passed to jobs, internal methods, views, etc.
Always validate user input on both the client and the server side. Sanitize data before persisting it to the database and sanitize data before showing it to the user in the views. Never call
html_safe on user input!
Imagine that your app is not sanitized and someone decides to save an HTML tag as a, let's say first_name:
user.first_name # => "<img src='http://example.com?parameter=1234532' style='display:none;'>"
What happens here is that no image is going to be visualized. Instead, the malicious site
http://example.com will be requested with the sensitive data inside parameter when the browser interprets this HTML tag.
This is a simple example of a Cross-site request forgery. Users might not even know that their data has been leaked. Usually such persisted tags aim to capture HTML elements from the page and send them as url parameters to a malicious server.
First of all, never ever use HTTP GET to change or delete data on your site. Know how to properly use HTTP verbs. Diving into the HTTP protocol exceeds the scope of this blog post. Let's now look at another countermeasure against CRSF.
Rails provides a simple one-liner for a protection against forged requests. It is a default behavior for the new freshly-generated Rails apps.
protect_from_forgery with: :exception
The protection boils down to a security token that our site knows but other sites are unfamiliar with. This token is included in requests and is being verified on the server. It is automatically included in all forms and AJAX requests generated by Rails. If the submitted token does not match the expected one - an exception will be raised.
A common practice for storing user information is the use of persistent cookies. In such a scenario, they will not be automatically cleared by the CSRF protection. If you are following a standard configuration of your app, this piece of code, placed inside
ApplicationController would be enough:
rescue_from ActionController::InvalidAuthenticityToken do |exception| sign_out(current_user) # An example for destroying the user cookies. end
Now, when a CSRF token is not present or is incorrect on a non-GET request, this method will be called.
Here is a simple explanation: Timing attack is an attack that is related to the measuring of the time between the request and the response for distinct inputs. The attacker receives hints from the non-constant elapsed time and he can receive hint how close or how far is he to compromising the system.
We can compare two strings by the usage of
ActiveSupport::SecurityUtils. The values are first processed by SHA256 so there is no leakage of information regarding timing attacks. This is essential when it comes to token-comparison.
protect_from_forgery with: :exceptionin your ApplicationController
ActiveSupport::SecurityUtils.secure_comparewhen you compare sensitive attributes (e.g. tokens)