Building Web Applications with Ruby on Rails: Best Practices and Tips

November 14, 2023
Building Web Applications with Ruby on Rails: Best Practices and Tips

Frameworks are primarily designed to assist web developers in creating web applications. Despite the numerous frameworks available, the likelihood of encountering common vulnerabilities like Cross-Site Request Forgery (CSRF), content spoofing, and issues such as XML Entity and Parameter Pollution remains significant.

While certain frameworks offer features to enhance the security of web applications, developers should not solely rely on these built-in security measures to protect their apps from unauthorized access. In reality, ensuring the security of a web application is an ongoing process, and no single security mechanism is entirely foolproof for isolating an application. However, web developers can reduce risks with the assistance of frameworks.

This article focuses on best practices for Ruby on Rails, highlighting some of its built-in features. It also emphasizes the importance of not relying solely on these built-in security features. Additionally, this tutorial demonstrates how web developers can utilize Ruby on Rails gems like secure_headers by Twitter to mitigate risks. Furthermore, it provides insights into hijacking and injection attacks that can target Ruby applications and offers strategies for minimizing the risks associated with session hijacking and SQL injection. The concluding section provides links to Ruby on Rails security resources and blogs to help developers expand their knowledge of securing Ruby applications.

Brief Overview of Ruby on Rails

Ruby on Rails is a web framework designed for building web applications using the Ruby programming language. This framework not only aids web developers in securing Ruby applications but also streamlines the web development process by reducing the amount of code developers need to write. Notably, Rails places a strong emphasis on convention over configuration, guided by the following core principles:

The DRY Principle (Don’t Repeat Yourself):

The DRY principle advocates against redundancy in code. Developers are encouraged to avoid duplicating information or logic, creating more maintainable code.

Convention over Configuration:

Rails is an opinionated framework that simplifies development by adhering to its established conventions rather than requiring extensive configuration files. This approach reduces the complexity of setting up and managing projects.

Ruby on Rails’ built-in security features:

Ruby on Rails' built-in security features

Ruby on Rails is inherently secure by default, but it’s important to note that relying solely on its built-in security features is not recommended.

For instance, while Rails provides Active Record, a library for database access abstraction, some query methods like the Calculation Method, Delete All Method, and Destroy All Method, Exist. Method, Joins Method, Order Method, and others don’t automatically sanitize or scrutinize raw SQL arguments. This leaves room for potential SQL injection vulnerabilities, so caution is needed when using these methods.

Despite Rails offering methods to sanitize raw SQL arguments, web developers can further enhance security by leveraging Rails’ clever helper methods and utilizing Rails gems that can outperform the built-in features. It’s crucial to understand that while the framework can assist in building secure applications, achieving security is not a one-size-fits-all solution. It depends on the diligence of developers and the chosen development approach.

Model View Controller (MVC):

Cross-site scripting vulnerabilities arise when websites fail to properly sanitize user input, including HTML, JavaScript, or VBScript. In Rails, sanitizing user input is straightforward thanks to the Model View Controller (MVC) architecture. Any data retrieved or stored in Rails passes through a model, making it easier to ensure input security.

Additionally, Rails provides the sanitize method, which allows for input or output sanitization in the view. This method encodes all tags and strips any blacklisted tags, further enhancing security.

For instance, let’s assume we have common XSS payloads, such as:

<img  src=x  onerror=prompt(1)>

<img/src=`%00`  onerror=this.onerror=confirm(1)

<img src=`%00`&Newline; onerror=alert(1)&NewLine;

When you pass one of the above:

<%= sanitize  ‘img src=x   onerror=prompt(1)>’ %>

By default, Rails takes the initiative in handling inputs, permitting the use of “img src=x” while likely removing the event attribute. This automatic decision-making is because we haven’t explicitly blacklisted any XSS payloads. Instead of relying on payload blacklisting, it’s advisable to follow secure coding practices. To ensure secure coding practices, we can depend on the Rails_best_practices gem.

The resulting output will appear as follows:

<img src=’’x’’>

Rails administrators need to exercise caution when dealing with the blacklisting and whitelisting of XSS payloads. Unlike SQL, JavaScript is a dynamically typed language, which makes it challenging to blacklist all possible XSS payloads. Additionally, there are XSS payloads with the capability to circumvent validation mechanisms, although that topic is not within the scope of this article.

Html_escape() or h()

In Rails, the HTML_escape () method, also known as h() (which is an alias for html_escape()), serves as a crucial tool for escaping and encoding HTML tag characters. It stands as the primary method for encoding output in Rails. For encoding strings such as URLs, you can utilize the url_encode(s) or u(s) functions.

In the first example, let’s allow the same XSS payload to pass through the Html_escape() function:

<%=  html_escape  ‘<img  src=x onerror=prompt(1)>’  %>

The Html_escape() will make the output appear as:

&lt ; img  src=x  onerror=prompt(1)&gt ;

The HTML_escape () method has converted the  < and >  characters into HTML entities.  

Authenticity_token

Rails safeguard applications against CSRF (Cross-Site Request Forgery) by incorporating a token called authenticity_token into HTML responses. This token is stored in a user’s session cookie. A session comprises a hash of values and session IDs, which are typically included in cookies. Consequently, every cookie sent to the user’s browser contains the session ID, typically a 32-character string.

In Rails, you can utilize the following method to save and retrieve values:

Session[:user_id]  

= @current_user.id  

User.find(session [ : user_id])

Ruby on Rails Security Gems

While Rails does provide several built-in features to mitigate input validation flaws and other web-based attacks, these security mechanisms have their limitations. I place trust in a diverse set of security measures to enhance the protection of Ruby applications, rather than relying solely on Rails’ built-in security features. To minimize the risks of session hijacking, cross-site request forgery, and SQL injection, I prefer to incorporate Rails gems.

Let’s explore some of the most popular security gems that can fortify web applications against session hijacking, cross-site request forgery, and SQL injection.

Devise

Devise is a widely adopted authentication solution for Rails applications. It offers an array of features, including secure password storage through bcrypt for hashing salted passwords, user registration, and forgotten password functionality.

The devise gem is built on top of Warden, which provides authentication capabilities for Rack-based Ruby applications. Warden manages the cookies that validate a logged-in user’s identity through a session string, where the user’s ID is stored and concealed from public view. For comprehensive guidance on effectively utilizing Devise, you can refer to Devise’s README, which contains all the necessary information to get you started.

Devise Utility Methods: 

authenticate_user! — authenticate_user! method is used for applications that require a user to log in to access their pages. 

current_user! — The current_user! method simply returns the model class relating to the signed-in or logged-in user.  If a user is not yet signed in, it returns nil.

user_signed _in? — This query method just checks if the current_user method returns a value that isn’t nil.

sign_in(@user) — This method is useful to allow a user to log in to a  newly created account.

sign_out(@user) — This method is useful to allow a user to log out successfully.

user_session — This method returns metadata on a logged-in user.

https://www.codementor.io/ruby-on-rails/tutorial/ruby-on-rails-security-best-practices

Conclusion

The top Ruby on Rails tips and tricks involve adhering to the best practices established by the framework and a community of experienced developers who have discovered the most effective coding methods. Thankfully, the Ruby on Rails community is renowned for its excellence, which is one of the reasons why Ruby developers hold it in such high regard.

When you follow these best practices, creating and managing your web application with Ruby on Rails can become an efficient, well-organized, and enjoyable project for both yourself and any other developers who join your team.