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.

Friday, July 5, 2013

Background Timer

I have not yet tried this code from Mike Ash, however, his background timer MABGTimer appears to be quite useful for clean up tasks both of internal data structures, caches and server synchronization. I especially like the thought of using this code in conjunction with a cache of networked data.

Tuesday, October 9, 2012

Swapping in an SSD for an HDD

Following this blog post and a great SSD from Other World Computing, I was able to install an SSD into my Macbook Pro, giving it new life, boosting its speed and expanding its storage space.  In addition, OWC sells a CD frame replacement in which your old HDD can be installed. This is great, however, it creates a complex situation.  Your HDD needs to be copied to your SSD and that means either going through an external drive (USB case), and that can run slowly, or you can build your Macbook Pro up with the new drive configuration and get it all done at once.

Being a bit adventurous and wishing to make the fewest copies possible, I elected for the latter. Of course, this created more work for me because of some difficulties I ran into, but I learned a little bit about unix drives and UUIDs.

If you're going to change your Mac's HDD to an SSD and move your HDD into the CD drive bay, here's how to do it:

  1. Backup your Computer
  2. Hardware Change
    Follow breakdown and installation instructions for SSD swap for HDD and HDD placement in the CD bay. NOTE: (if most Macbooks are similar) your HDD has two pairs of stubby bolts that hold it in position in the main drive bay. Be sure to remove them and move them to the SSD. Put the HDD into the CD replacement frame and install both the HDD and the SSD.
  3. Boot to Single User Mode
    When you power up the Mac, hold down the Option key until the screen displays a choice of drives from which to boot. Before selecting the drive, hold down COMMAND-S. Continue to hold down CMD-S while selecting the drive. This puts the computer in single user mode and makes the HDD read only. You're about to copy that drive, you don't want a lot of extraneous processes running and modifying the filesystem. Even better, read only prevents changes to the drive. Try running "ps -elf" and you should see only a couple of processes.
  4. Copy the Drive
    Follow the instructions at link above for copying the drive. Note: author makes a comment about not copying empty drive space (0s for HDD v. 1s for SSD being important). I don't know how important this is.
    Be sure you know which drive is which. Most likely, you HDD is /dev/disk1 and your SSD is /dev/disk0. This has everything to do with which hardware SATA link they are connected to and not which drive was used for booting the OS (first, mount the drive, then read it, then boot the OS, so /dev/disk* order is deterministic).
    Copy command looks like: dd if=/dev/disk1 bs=1024 count=### of=/dev/disk0
  5. Change UUID
    At this point, the drive is an exact copy, which creates a problem. If you reboot now, your machine will not work. Both drives look exactly the same to the system because of the shared UUIDs. Using hsf.util, change the UUIDs on the new SSD (there are most likely two of them) before reboot. This program lives in /System/Library/Filesystems/hfs.fs/.
    hsf.util -k rdisk0s2 ## Shows UUID for rdisk0s2, if it has one.
    hsf.util -s rdisk0s2 ## Generates new UUID for rdisk0s2.
  6. Reboot
That's it. You should be done. Leave your machine in this configuration for a week or so until you decide that you're happy with the new hardware configuration and the system feels stable. If you plan carefully and you still have Snow Leopard on your machine, you can leave your HDD with Snow Leopard and install Lion or Mountain Lion on the SSD. Then, you can dual boot your Mac using both drives, with Mountain Lion being your preferred OS and Snow Leopard your occasional.

Why do this? You might have many reasons, like certain applications that work only on Snow Leopard. If you're building OSX ARC applications and you want to debug that ARC app on Snow Leopard, either you need a second machine (running 10.6.8) or you can boot your Macbook off of the second drive.

Good luck with your hardware upgrades.

PS: I also received great help from superuser exchange.