Talks

Rails' Insecure Defaults

Rails' Insecure Defaults

by Bryan Helmkamp

In the talk titled "Rails' Insecure Defaults" presented by Bryan Helmkamp at Rails Conf 2013, the speaker delves into the security mechanisms of the Ruby on Rails framework, emphasizing that while Rails provides many safeguards against various types of web attacks such as SQL injection and cross-site scripting (XSS), there are still several default behaviors that may leave applications vulnerable. Helmkamp asserts that Rails is generally secure out of the box but points out specific areas where it could enforce more secure defaults. The key points discussed include:

  • Insecure Defaults: Highlighting the importance of secure defaults in programming, the talk underscores that overly relying on programmers to implement security features can lead to neglect over time.
  • Server Header: Rails includes a verbose server header that can expose sensitive information about the Ruby version in use. Best practice suggests configuring this to reduce information leakage.
  • Binding to Zero Interfaces: The default behavior of binding to "0.0.0.0" can expose applications to attacks, especially in development environments. It is recommended to bind to "localhost" instead.
  • Logging of Sensitive Information: The SQL logging feature can inadvertently expose sensitive data like password hashes, leading to potential data breaches. Suggestions were made to implement better log filtering.
  • Secret Token Management: The secret token generated during application setup should not be committed to version control. Helmkamp advocates that Rails should ignore secret token files by default to enhance security.
  • Redirecting Users: The use of user-controlled URLs for redirection can lead to phishing attacks. It's advisable for Rails to enforce domain restrictions on redirects by default.
  • Link Generation with JavaScript: Links created from user input can lead to XSS vulnerabilities if checks are not in place. It is suggested that Rails limit protocols that can be used in links.
  • SQL Injection Concerns: Misuse of certain Active Record methods can open the door to SQL injection attacks. Developers are advised to familiarize themselves with which methods are safe to use.
  • Serialization Issues with YAML: Using YAML for serialization can lead to serious vulnerabilities, and switching to JSON as a default is recommended.

The primary takeaway from Helmkamp's presentation is the call for awareness and discussions within the Rails community about these existing vulnerabilities and the necessity for Rails to adopt more secure defaults. By highlighting specific improvements, the speaker hopes to inspire changes in future versions of the framework to safeguard against potential security risks.

00:00:16.480 Cool! So, this is a really advanced talk about security. If you don't know what a cross-site request forgery attack is, or if you've never heard of cross-site scripting or SQL injection, it's going to be very difficult to follow. Hopefully, people have self-selected into this talk, and the rest of you can hold on for dear life. My name is Bryan. I started a company called Code Climate, so this is a quick ego boost for me. How many people have heard of Code Climate? Awesome! And how many people have actually used it, open-source or otherwise? It's pretty good. The rest of you, we'll talk later.
00:00:33.520 Security researchers will sometimes say that insecure defaults are insecure. What they mean is, if a programmer has to take an action every time they write something in order to create secure behavior, then eventually, the programmer will forget to do that. Over a long enough period, if you have an insecure default, you end up with an insecure system. We prefer secure defaults where, if you don't do anything, it's secure, but you have to go out of your way to shoot yourself in the foot—something we all will do eventually. So, we'll start with a survey: How many people believe the statement 'Rails is secure by default' is true? Raise your hand if you believe this is true.
00:01:15.360 A few people, you guys are good. Now, how many believe this is false? Okay, yeah, because you're in a talk called 'Rails Insecure Defaults.' At least you're paying attention to what room you're walking into. Rails is actually very secure by default. Rails does a great job in this regard; it's probably one of the most secure web application frameworks you can pick off the shelf and code with today. There's a lot of functionality that you're not going to get if you're programming with frameworks in other languages. Even if you're using Sinatra, which is much more bare bones, it doesn't provide much built-in protection for you. You get a lot of protection against SQL injection vulnerabilities via the Active Record API.
00:02:24.800 You get protection against cross-site request forgery attacks in the Action Pack layer that's been around since Rails 2, and protection against cross-site scripting attacks was introduced in Rails 3. You get a lot of protection against those attacks out of the box with Rails. The people working on Rails security care deeply about making sure your app stays safe. However, today I want to talk about insecure defaults. What I mean by that is not the groundbreaking Rails vulnerabilities that will become headlines on Hacker News. Instead, I want to discuss some areas where I believe Rails could have more secure behaviors, raising awareness about the issues involved.
00:02:50.320 When you're coding your applications, you want to ensure you don't fall into these pitfalls, which may inspire discussion within the community about whether Rails should change some of these behaviors to be more secure. Ideally, if someone writes a pull request to fix something I cover in my presentation, I'd love to hear about it. Let's start with some small, simple security risks that I believe Rails has out of the box.
00:03:23.520 First, there's a verbose server header. HTTP responses include a server header that usually refers to the software responsible for generating the response. In this case, it's Webrick 1.3.1. It also includes information about the Ruby version, for example, Ruby 1.9.3, along with a patch level. Your server header essentially reveals which Ruby version and patch level are running on that server. Now, who cares? Security by obscurity is not a valid form of security, so why would I worry about revealing the Ruby version I am using? Well, giving away this information can ease the path for attackers using specific scanning tools.
00:03:57.200 In many cases, when an attack payload is crafted, it needs to be customized based on the software being targeted. If vulnerabilities exist in different software versions, those vulnerabilities often require distinct exploitation methods. By exposing your Ruby version information, you provide attackers with the details they need to tailor their attacks specifically against your server. We should avoid using Webrick in production anyway, as it's not recommended. Use servers like Passenger, Unicorn, Thin, or Puma instead. However, Heroku users might not realize that, by default, Webrick could be the server running if no other option is chosen.
00:04:38.639 To fix this, Rails could configure Webrick to exclude that information in the header by passing an option during its setup. This would be a simple one-liner. Next, Rails binds to `0.0.0.0`, which means it listens on all interfaces rather than just localhost. This poses problems in both production and development environments. For instance, in development mode, you might have a laptop where a colleague loaded production data to help debug something, and they later connect their laptop to a public Wi-Fi in a coffee shop in San Francisco. You can easily imagine what could happen if attackers start scanning public networks for vulnerable applications.
00:05:34.479 In production mode, Rails is known to be unsafe when running in an unproxied configuration. If you ask the Rails core team, they will tell you that you need to run a proxy in front of Rails to prevent issues such as IP forgery attacks. Running an unprotected Rails instance makes it trivial for an attacker to forge IP addresses by manipulating headers. Therefore, running on `0.0.0.0` can lead to exposure to malicious users who might access your application in a way you never intended.
00:06:03.600 The best practice is to use the `-b` option to bind to localhost instead of `0.0.0.0` and to avoid loading real data in your development environment to mitigate risks. If you do load real data, delete it as soon as you're done. The proposed fix is for Rails to change the default behavior so that it binds to localhost rather than all interfaces. This way, if developers truly need their applications to bind to all interfaces, they can add the `-b` flag as needed.
00:06:59.440 Moving on to logging SQL values, Rails has a nice feature called filtered parameter logging, which prevents sensitive information, such as passwords, from being logged in your `production.log` files. However, if SQL logging is turned on, that SQL string is still logged without any filtering. An example of this is creating a user and logging the password digest, which then appears in the log files. Anyone who has access to read the log files can see the password digest and potentially brute force it.
00:07:46.240 You might argue that we don't run that logging level in production, which is not the default. However, server maintenance can lead team members to temporarily increase the log level, and changes made can inadvertently lead to sensitive data being captured in logs. Best practices suggest being very aware of what you log in production—both in your default log level and any log levels you use for debugging. If you need to raise the log level temporarily, ensure you remove any sensitive data from the logs afterward. It would be beneficial if Rails could introduce a config filter logs value that also affects SQL statements in addition to HTTP parameters, redacting SQL statements that reference sensitive fields.
00:09:08.480 Now that we've warmed up, let's move on to the more severe issues that can arise if you're not careful with how Rails operates. One major issue is the secret tokens used by Rails. The `secret_token.rb` file is generated by Rails when you create a new application, and it stores a secure random value in your config initializers directory. The problem arises when this value ends up being committed to version control and deployed to production, making many developers unaware of its importance.
00:09:31.600 This secret token is essentially your application's root key. If someone possesses it, they can easily forge any session they want, allowing them to take over others' privileges and bypass application-level security controls. If that secret token exists on 50 developers' laptops, it significantly increases the chances of it being compromised. As a best practice, you need to use a different secret token in production than in development. You can inject this value via environment variables or utilize a service like Heroku, which simplifies this process.
00:10:40.560 Rails could help mitigate this vulnerability by ensuring that the `secret_token.rb` is included in the `.gitignore` by default in the generated application skeleton. Additionally, Rails could introduce the concept of a secret store that would help secure secrets across the Rails ecosystem. This way, library authors could use a standard method for managing sensitive values, making it easier for developers to keep their secrets out of version control.
00:11:18.800 Next is the issue of off-site redirects. This is common in applications where you redirect users to specific destinations after an action, such as logging in or signing up. The problem is that an attacker can control the destination parameter and redirect users to any URL they choose, which could even be a malicious site. This poses a significant phishing risk since users may not notice they have been redirected to an unintended URL. Unprotected redirects have made it to the OWASP Top 10 list of critical web application security risks, emphasizing how dangerous they can be.
00:12:35.200 To protect against this, Rails should only allow redirects within the same domain by default. This is the typical case; most applications redirect users within their own domain. For rare circumstances where external redirects are needed, a flag could be passed to allow that behavior, making it an opt-in feature rather than the default.
00:13:04.320 Another security concern is utilizing link_to with user input directly. For example, if a social network allows users to specify their public URL, they could enter a string starting with 'javascript:' and execute arbitrary code when other users click on that link. Rails' built-in XSS protection does not apply here, so this is a significant cross-site scripting risk. A best practice is to sanitize input used in `link_to` to ensure that it does not involve potentially malicious protocols.
00:13:44.399 Rails could improve this by only allowing safe protocols such as HTTP, HTTPS, or mailto links by default in its `link_to` helper. This would reduce the potential for harmful behavior while allowing developers the option to opt-in for less secure functionality if absolutely necessary.
00:14:24.000 Speaking of SQL injection, it’s crucial to note that Rails is not a silver bullet against SQL injection vulnerabilities. Many developers mistakenly believe that using Active Record guarantees safety from SQL injection. For example, the `pluck` method permits raw SQL fragments, so if an attacker can control the inputs to `pluck`, they could exploit this. Even methods based on making queries may unexpectedly expose vulnerabilities.
00:15:05.120 As Active Record apis are designed, if users can influence the SQL fragments sent, problems can arise. This could even allow attackers to access sensitive data such as user passwords by creatively crafting requests. Developers must be cautious and utilize the safest query methods available while also implementing input whitelisting when feasible.
00:15:53.200 To improve security, Rails should restrict the use of SQL fragments to APIs where they are common and expected. For example, methods like `pluck` should accept exclusively valid column names instead of arbitrary SQL. By doing this, Rails can ensure that developers are more frequently protected from potential security oversights.
00:16:45.920 Next, let’s address YAML serialization. In this security talk, we would not be complete without mentioning it. Rails provides helpers such as `serialize` and `store` that allow data to be stored in a single column. However, this introduces risks. YAML can be vulnerable to code execution attacks because deserializing it can lead to arbitrary code execution. It's crucial to educate developers on the dangers of using YAML inappropriately, especially when errors may lead to unexpected exposure and exploitation.
00:18:36.080 Developers should be careful of where and how they store YAML data. Instead, they should consider using JSON as the serialization format for these macros and serialize data with care. It could be more secure for Rails to change the default serialization format from YAML to JSON, making the latter the safer choice and allowing YAML as an option rather than the default.
00:19:31.760 As we wrap up, I hope this talk serves as a springboard for discussions in the Ruby community regarding Rails and its behavior. Many developers might recognize that certain behaviors present risks but haven't felt motivated to address them. However, the stakes are high, and our goal should be to create the most secure framework possible to enhance the ability of developers to create applications that are less prone to security risks.
00:20:48.920 My name is Bryan. I work at Code Climate. Thank you for your time and attention. I'm happy to take some questions.
00:21:37.840 So, does Code Climate help with any of these issues? Yes, Code Climate provides functionality that can help identify where your application's security might be weaker than it should be. We have a feature called Security Monitor, which scans your source code looking for vulnerable dependencies. If you're using a vulnerable Rails version, for instance, we will notify you so you can address the concerns quickly.
00:22:03.360 Besides, Code Climate can warn you about potential vulnerabilities as soon as they appear in your code base before they reach production, thus raising awareness. I encourage you to try Code Climate if you haven't already. It's not a magic bullet, but it can assist in flagging significant issues and creating awareness of potential risks.
00:23:18.240 In closing, if you have more questions about input validation or other security practices, feel free to ask. There’s always more to discuss on how Rails can improve and adapt to meet security challenges.
00:23:55.200 There's also a potential issue with input validation in terms of types. Strong parameters have indeed become an integral part of parameter management in Rails. They afford protection against mass assignment and can help ensure that the expected types are received in parameters, but there's always room for improvement. Continuous dialog around how Rails can be more secure is vital.
00:24:29.600 Thank you again for your attention. I'll be available for questions, so please feel free to approach me after the talk.
00:25:25.760 Also, Code Climate is offering free application security checkups at the exhibit hall tomorrow and Wednesday during the breaks. Bring your application, and we'll run automated scans against it to see where your focus should be. I'll be there along with some knowledgeable folks to help you identify critical issues and discuss strategies for moving forward securely. Thank you very much for your time!