Is Ruby on Rails secure?
First of all, there is no software that it's 100% secure, and there is no framework more secure than others. This doesn't mean we can't do anything about security. In this post, we'll analyze some built-in mechanisms provided by Ruby on Rails and other security measures that we need to use to build more secure software.
Security depends on the people using the web framework and the rest of the tech stack:
- the database
- the web server
- and possibly other components such as APIs, file storage, etc.
Each independent component of the tech stack can be attacked and must be protected. In this post, we'll focus entirely on the web framework.
Web applications are relatively easy to attack, as they are simple to understand and can be manipulated with little knowledge. According to the OWASP Top Ten, the most common web application security risks include broken access control, injection (cross-site scripting, SQL injection, etc), insecure design, vulnerable and outdated components, etc. To prevent or minimize the risks, you must understand these attacks.
Rails built-in security mechanisms
Rails provides built-in security mechanisms for preventing some of the most common web application security risks. But you must use them as specified by the framework.
Cross-Site Request Forgery (CSRF)
This attack method works by including malicious code or a link in a page that creates forged requests to the web application impersonating the user. If the session for that web application has not timed out, the attacker may execute unauthorized commands using the user's account.
The first countermeasure for this attack is using GET and POST appropriately, as required by the W3C. The second countermeasure, enabled by default in Ruby on Rails, is to include a security token in requests that we'll verify in the server. All forms generated by Rails will include this token. If the token sent to the server doesn't match the expected one, the request will be aborted, and no changes made to the system.
Injection is a class of attacks that manipulates user input by sending arbitrary code to make it run inside the application. Prominent examples of injection are cross-site scripting (XSS) and SQL injection.
SQL injection refers to code that will be run on the database. If the attack is successful, the attacker might have access to see or modify records that were originally out of their reach. They might steal personal information, passwords, or give their user administration privileges.
Ruby on Rails query methods have a built-in filter for special SQL characters that are used to perform these attacks and automatically sanitizes the input by default. But if you are using SQL fragments, especially in condition fragments
(where("...")), the sanitization has to be applied manually.
Make it a habit to think about the security consequences when using external data in SQL strings.
On the other hand, XSS (Cross-site scripting) attacks aim to inject code that will run in the users' web browser. If the attack is successful, the attacker might:
- steal personal information like authentication cookies to impersonate them in the app
- change elements on the page to show them fake information
- redirect the victim to a different website for phishing or stealing other information
By default, Rails escapes all the HTML automatically (unless you command it to not do it, which is not recommended). This means that any code the attacker tries to inject, it won't take effect and the browser won't execute it.
You can read a comprehensive list of security risks and their countermeasures in the security chapter of the Rails guides.
Active Community, wide adoption, and frequent updates
Keeping your codebase up-to-date is crucial when we talk about security. Web application scanners can pick up old versions of software pretty easily and have an extensive library of known exploits for each. So having an outdated version of Rails is a security concern that should be addressed as soon as possible. If you want, you can read more about what entails upgrading Ruby on Rails applications.
Last but not least, the Rails core team has a group of specialized engineers working on improving its security and addressing security-related bugs. These are found quite fast as there are big companies like Shopify, GitHub, Airbnb, and Basecamp that use Rails extensively. Every time a vulnerability is fixed, a new version is released for all versions of the framework that are alive, with instructions on how to update and how the fix works.
There are some security risks and vulnerabilities that Rails can't prevent by default and are normally the user's responsibility. It's a good practice to scan our application for vulnerabilities with a web application scanner such as Brakeman (specifically designed for Ruby on Rails applications), ZAP, or w3af.
In security, however, there is no silver bullet. Any web application scanner will scan your application but they're not context-aware. Most of them don't know your business rules and there are some vulnerabilities that they might have a hard time figuring out, such as broken access control. Access control refers to an enforcing policy such that users cannot act outside of their intended permissions. It depends specifically on the business logic. A responsible user of the framework must prevent users of their application from reading, modifying, or destroying unauthorized resources outside of their limits. This can be done easily by implementing proper user authorization with a ruby gem such as pundit or cancancan.
Answering the question "Is Ruby on Rails secure?": it is, but only if you know what are doing. Ultimately, security is a complex, cross-cutting concern of all applications and the only way to be as secure as possible is to have a careful and experienced team.
Security depends on the people using the web framework, but as you can see, Rails comes with a good set of built-in security mechanisms that can prevent the most common attacks. And we, as users of the framework, must be thankful for that. At the same time, some common security risks and vulnerabilities can't be prevented by the framework by default, and we must be aware of security. And again, it's a good practice to scan our app for vulnerabilities regularly.
There will always be malicious users out there, one has to be ready to face them from the start.