Picking up where we left off last week, check out Rails Vulnerabilities and Where To Find Them – Part 1 if you have not, we will be taking a look at some additional common security issues with Ruby on Rails applications and where they are typically found within the code or other configurations.
When we are doing security testing of applications, we usually use a broad set of different types of testing including static, component, and runtime analysis, but also more advanced techniques like fuzzing, reverse engineering, and manual source code review. This post focuses in on manual source code review for Ruby on Rails – if you’re interested in the other techniques / methodologies mentioned, definitely check out our security training courses for developers!
Security Misconfiguration is something of a catch-all category in the OWASP Top 10 because many very common problems fall within this classification. Items like authentication that doesn’t invalidate cookies, cloud storage with incorrect access controls, and lack of properly set security headers all fit within this bucket.
Speaking of security headers – the RailsGoat application we are using for demonstration does not have proper security headers set. We identified this by inspecting the response headers of a request to the dashboard:
Generally we would hope to see the following security headers set:
Some of these tags don’t apply directly to our RailsGoat because we have not set up SSL, so we would not expect HSTS for example. These headers help protect against a few different types of attacks including XSS, clickjacking, and Man in the Middle attacks that might attempt to downgrade the HTTP connections to the server. You can quickly check the security headers for your live application by visiting https://securityheaders.io – though this won’t work with our RailsGoat because it’s not accessible on the internet. The good thing about security headers is that generally they are very easy to implement. Take a look at the secureheaders project to get more specific details for Ruby on Rails implementation.
Cross Site Request Forgery
Cross Site Request Forgery (CSRF) is a type of vulnerability that could fit under ‘security misconfiguration’ but is big enough to have it’s own classification. These attacks generally rely on social engineering, and use a 3rd party website to send requests to your application. Because your application has not properly implemented request forgery protections, the victim’s session cookie is recognized and the actions are accepted as normal even though they came from an outside source.
This all sounds quite complex, but fortunately Rails (and most modern frameworks) make it very easy to protect against these attacks. This is why this issue could also be classified as security misconfiguration – these settings really should be turned on. In order to see if a Rails application is protected against CSRF attacks, first check “/app/controllers/application_controller.rb” for the “protect_from_forgery” method.
Oh no! It looks like the CSRF protections have been intentionally disabled by the developers on this application! That’s not good. You also must check “/app/views/layouts/application.html.erb” to see if the “csrf_meta_tags” tag has been included in the layout’s header for “protect_from_forgery” to work:
It looks like this too has been manually disabled by the developer because of their lack of understanding around this functionality. The good news here is that uncommenting these two lines of code will re-enable the CSRF protections across the app!
Missing Function Level Access Controls
Lastly we will look at something that dives a bit deeper into the business-logic of this application, but is important and a common mistake none the less. Generally applications have some kind of access control baked in that enables ‘admin access’ to special parts of the application, and it is all too common for the restrictions built around that access to be half-baked. On Rails applications it’s typical to use a “before_action” filter in order to check if a user should have access to a part of the app. In this case, it appears that there is a special admin dashboard. We can see that by visiting the path “/admin/1/dashboard” where it looks like we can view and edit other user’s info with just a low-privileged account!
Why does this problem exist? Let’s look at the before_action in admin_controller.rb:
Based on this it looks like the “before_action :administrative” filter, which checks if the user is an admin, is being skipped with a simple logic flaw. If :admin_param is being provided, it skips this filter and shows the admin page. No good! It’s always a good idea to have a second set of eyes verify that critical security functionality like this has been implemented correctly (and also test scenarios that verify it on a continual basis). In order to fix this issue all that is required is to remove the “if: :admin_param” set of the rule.
After spending time auditing the security across different applications it becomes clear that there is a pattern to the vulnerabilities discovered – certain traits that point us where to look to find issues. These patterns are actually why the OWASP Top 10 exist – to help us classify and understand what types of issues exist, how they work, and ultimately to build awareness so that more potential problems are found and corrected before data loss or other exploitation has taken place.
We hope these posts have helped enlighten you to some common issues we see in Ruby on Rails applications. If you’re interested in learning more about application security, definitely check out our security training offerings, or if your organization needs an independent application security review, definitely contact us for more details!