Tuesday, November 26, 2013

Securing Rails, Part III - Direct Access

In this third an final section on securing rails, we get to the heart of the matter and the original reason I started writing this security summary. It seems there are two critical security issues that Rails has that require developer intervention on a case by case basis. Mass Assignment (well known and discussed everywhere) and Primary Key Exposure (hardly a peep from the web on this one).

For the Mass Assignment problem, a raft of articles have been written about this. Here's a great one. Please note that this falls under one of OWASP's top ten list, specifically 2013's A7. The articles previously referenced contain solutions for mass assignment, so I won't repeat it here. If you're using Rails 4.0.0 and Ruby 2.0.0 or later, you should be covered. If not, Michael Hartl (of Rails Tutorial fame) has written a Mass Assignment detector plug-in. Automatic problem detection fits right in with TDD. If you give that a try, leave a comment regarding how you like it.

A note about Mass Assignment and Authorization: it isn't enough to restrict assignment to whitelisted attributes, attribute assignment must happen only within the proper context. For example, a user's password may be changed, so it's password (and password_confirmation) attributes are on the whitelist. However, for security purposes, we may choose to allow a password to be changed only after the user has correctly entered the current password. This state transition must be checked, otherwise an attacker may by-pass the security protocol.

My greatest concern with Rails, however, is its Primary Key Exposure problem. This security vulnerability is so prevalent, it's completely ignored by Rails developers as a feature and not a bug. Some systems swap the Primary Key value for a search engine friendly value in the URI. Often times, these friendly URIs retain the same security problem as they allow for even more easily guessed values. When a user wishes to expose information publicly a friendly URI is a boon. In that case, consider this gem, friendly_id.

In the default case, when the Rails system transforms object references into web pages (and JSON structures), references to objects use the object's Primary Key, the data value used by the underlying database. Why is this a Bad Thing? Primary Keys are almost always created in order and start with 1 (unique, monotonically increasing value). This means that object references are easily guessable. If your authorization model is poor, non-existent or simply has a bug, an attacker has access to users and/or their data. OWASP places this as item A4 on their 2013 top ten. Furthermore, an attacker can compound security holes using exposed Primary Keys. For example, a SQL injection attack becomes easier because the attacker has a rich supply of object IDs or, at least, knows how to form them. If the attacker knows a time interval within which a user has signed up for your service, they can bound the user IDs they need to guess that correspond to that user.

A proper, Defense in Depth strategy, recommends swizzling these Primary Keys into large, random and, therefore, hard to guess values. The sparse range of object IDs makes it more difficult for an attacker to locate a valid ID, let alone locate a particular object's ID. The controller uses the swizzled Primary Key passing it to the view for distribution to a web client or other application. This means changing the Model's to_param() method. It also requires a method to do the reverse - convert back into an object from the external ID. A recommended approach is to create a from_param() method. In addition, you need to add a new attribute to your model, for example, OID.

To generate a 120 bit random value (120 fits in 20 url safe bytes), use the following code:
self.oid = SecureRandom.urlsafe_base64(20*3/4)
Putting it all together, add this code to your <model>.rb file

  before_validation :check_oid

  MinOIDLength = 20
  validates :oid, length: { minimum: MinOIDLength }
  validates_uniqueness_of :oid

  def to_param
    oid
  end

  def self.from_param(param)
    find_by_oid(param)
  end

  def check_oid
    if !self.oid
      self.oid = SecureRandom.urlsafe_base64(MinOIDLength*3/4)
    end
  end



This allows the oid attribute to be changed, when really it should be read-only, however, this code works. If you have a better suggestion for how to implement an automatically added and complex external ID, leave it in the comments.

Securing Rails, Part II - Authentication and Authorization

Authentication (identifying users) and Authorization (restricting which actions a user performs) create the foundation of every system's security infrastructure.

A system must not only authenticate its users, but provide a session management infrastructure that prevents a user from changing (faking) who they are as well as prevents others from hijacking a legitimate session. The security literature is rife with examples of users being able to flip a bit to upgrade authority (admin=true) or simple asserting they are a different user (current_user="mary"). To hijack session, we find all sorts of attacks, mostly through the theft of browser cookies.

For authentication infrastructure, your best bet is to use a gem that has already been well-tested and reviewed by others rather than rolling your own. The Rails Authentication sub-category has plenty of gems for this area. We are going to try Devise + OmniAuth. I hope to report in a later post our experience with these two gems.

A good authorization framework presents a much larger challenge. There are many reasons for this. First, developers are very creative people. We devise complex code, data and functional models. We devise complex authority hierarchies, roles, permissions. The right to touch a page, a function or a member on an object may be easily determined or based upon a SQL query. There's really no good way to build a gem, DSL or class add-on that presents a one size fits all approach. At least, I've yet to see one. 

Nonetheless, a lot of developers have tried. Check out the Rails Security, Authorization page to see some gems that may suit your needs. In my search, I found the following authorization discussions helpful.
  1. Ryan Bates (of Rails Casts fame) discusses his gem CanCan.
  2. Tim Morgan tried CanCan and argues for the Authority gem, written by Nathan Long and Adam Hunter.
  3. Elabs also tried CanCan and argues for a roll-your-own approach, then supplies Pundit.
No matter the approach, a proper Authorization framework must be implemented for good security. Don't rely on users not being able to boost their authority because they cannot "see" a function. We'll touch on two ways this can happen in the next post on this topic.

Securing Rails, Part I - Web Application Security

Every organization must secure their web application irrespective of the technology platform and whether it serves HTML, JSON or XML. All web applications suffer from the same kinds of broken security. We see these security problems over and over again, so much so that those of us in the security industry have strong confidence in our career choice. Mind you, we would like to be put out of business, it just doesn't seem likely. Just look at the 150MM user account and password leak from Adobe this past summer. Why were the passwords encrypted and not hashed? Please don't mix the two concepts or misuse the two words - encrypt means you can decrypt. You cannot de-hash in Order(1) time.

I highly recommend reviewing OWASP's website and their tri-yearly top ten security issues list. If you go back over the top-ten lists since 2004, you'll find that problems trade places, but rarely drop off - code injection (backend server (SQL, OS, etc.) or web server (XSS - HTML, JS)), broken authentication/sessions (login protocol, session handling, Cross Site Forgery (CSRF), Redirects), broken authorization (direct object references, no function ACLs, private data exposed), misconfigured security.

Every web developer should familiarize herself with these common security vulnerabilities.

Rails has a specific security page that discusses common security pitfalls and how to fix them in the Rails platform. This covers session protection, code injection and security configuration.

Additionally, under the Ruby Toolbox, Security section, you may find a number of gems useful for protecting your application. I have not reviewed these in detail, so cannot make recommendations based upon experience. That said, there are a few gems that look promising.

Under Security Tools, developers have contributed some interesting gems. I'm a big fan of analyzers, they're cheap to run and, if they provide useful information, are great at catching problems. Their downside is they tend to generate a lot of chaff and very little wheat, so a vigorous analysis is often required. Brakeman and Tarantula look promising. Check the others out, too.

In addition, there are Captcha, Spam Detection and Encryption gems. I like the first two, Captcha tech is great for protecting user accounts from brute force attacks. Spam Detection, well, if you've got email, no need to explain that one. I would encourage you to take care with Encryption, mostly because it's easy to do it wrong and make yourself believe your more secure than you really are. Encryption is not a magic security dust to be sprinkled atop data and everything gets +24 Securons. Please consider this as a last resort and, preferably under an knowledgable engineer's direction.

Developers must hone their security expertise. Most security holes come from ignorance and a lack of creativity on the software author's part. Read some great security blogs. Educate yourself.

Monday, November 25, 2013

Securing Rails, Overview

I very much enjoy developing applications on the latest platform technology. Gone are the days when building a company to support a great new idea required hardware purchases, IT consultant support, and hiring a raft of developers to build infrastructure. The need to hire a raft of developers hasn't gone away, but now we all get to focus (for the most part) on building out tech to directly support the idea and the company. However, one really, really important item has not gone away - the proper understanding and application of security.

At Route Vu, we are building a mobile application that also requires backend server and web server support. In this app, we have a number of unique privacy issues (for a social application) we wish to address, so security becomes even more critical for us. Personally, I'm new to Rails. Why should you trust three blog posts about securing a Ruby on Rails application? Fair question. In a prior life I worked for the world's second largest software company securing their database and applications, helping secure their on-line applications and crafting their security response team.

The following three blog posts cover separate topics:
  1. Overall Web Application Security
  2. Authentication and Authorization
  3. Two Security Vulnerabilities Development Must Fix
Honestly, I consider item 3, the two vulnerabilities, the most important post you should read - way to bury the lead, huh? The other two are almost no-brainers in terms of what you should do. Don't get me wrong, you must make plenty of decisions and do a lot of work satisfying the security issues in items 1 & 2. However, after perusing the common Rails programming idioms and finding the Primary Key vulnerability, I felt compelled to write these blog posts (if for no one other than me and my development team).

I hope you find them useful. If you see any complete and utter Ruby or Rails programming Fails, please drop me a line or make comment to correct.

Thursday, November 21, 2013

Supporting JSON and HTML in RAILS

I really enjoy the modern development platforms. We are in the middle of a launching a new mobile application on the iPhone and supported by a backend web server written in Rails. The web server supports users connecting through a browser (.html) and from our phone application (.json). The question then becomes: how do we support both connection APIs with as little effort as possible?

For the HTML browsing, Rails strongly encourages an MVC architecture; the V (View) is critical here. The Model and Controller are internal components, controlled by our company and written by our development staff. The View is Public, accessed by our customers through a (public) standard protocol. Interestingly, despite the fact that our iPhone client is controlled and written by development within our company, it feels and acts more like something accessed by our customers through a (private) standard protocol. It is in this sense, that the JSON api used by our client should be treated as a View level component and handled by that part of the server architecture.

Once we think of JSON as a yet another View, the challenge then becomes how to build Views that support JSON. Enter RABL.

Nathan Esquenazi introduced RABL (Ruby API Builder Language) in his excellent blog post, If you’re using to_json, you’re doing it wrong. RABL provides a Ruby DSL for describing JSON and XML outputs in View files. He makes a great argument that supporting anything other than the simplest of APIs causes knotty code deep down in the Model, exactly where you don't want to support these types of changes (and breaking MVC principles). Here's another blog post in which he describes Building a Platform API on Rails.

Meanwhile, Ryan Bates created three excellent Rails Casts on JSON API creation.
  1. Cast #320 shows how to generate JSON using JBuilder.
  2. Cast #322 shows how to generate JSON using RABL.
  3. Cast #350 shows how to generate multiple JSON (API) versions using RABL.
At first blush, this last piece (API versioning) may seem strange to include as it (versioning) appears orthogonal to API building and generation. I'm quite comfortably stating unequivocally that the moment you publish an API, you will have to create a new version for it in the future. We might as well use a methodology that allows us to modify the API (through versioning) down the road.

With versioning, the question then becomes how the client best tells the server which version it wants/uses and vice-versa (in which version the server responded). To me, the best method (and the one allowing continued commitment to RESTful APIs) uses the Accept: header token to specify the version. Contrast this with placing the version in the URI (.../v1/... vs. .../v2/...). Peter Williams makes an excellent case for a header token in his blog post, VERSIONING REST WEB SERVICES. He uses XML instead of JSON. You can read his entire thoughts on RESTful versioning in his series of blog posts.

One other suggestion to be considered, Daniel Morrison suggests using a subdomain to divide machine requests from human requests (api.domain.com vs. www.domain.com). He shows how to do that at the end of his blog post, Building Awesome Rails APIs: Part 1. Search for "API Subdomain". Note, there is no Part 2. I like this, although I'm not convinced it's necessary and would like some more experience building and using APIs before trying it. If you want to test subdomains on your local machine, try using lve.me or lvho.st.

Finally, this piece represents a compilation of research on dual HMTL/JSON generation and in the context of API (JSON generation) versioning. Having not yet built a full scale system requiring this, I'm loathe to make too many recommendations. Stay tuned for future blog posts confirming which of these techniques works best.

That said, at this point I like the use of the Accept: header token to determine the content type of the View's response. I don't think I like using a subdomain, adding /api/ the URI path or appending .json to the request. For versioning, I favor mixing the version number into the header token over insertion in the URI path. (Thanks to Stephen Bennet for saving me from adding version to subdomains - you're right).

Finally, I plan to write a follow up post, shortly, covering some thoughts about JSON and data model "swizzling" as a security issue.