sandal edited this page Dec 6, 2011 · 16 revisions

While security is something we don't necessarily think about day to day as Ruby programmers, it is an important aspect of writing quality software. Because frameworks like Rails tend to do most of the work for us when it comes to preventing the most common vulnerabilities, it is relatively easy to get complacent and assume that it is someone else's job to keep our users out of harm's way. This kind of thinking is dangerous even within the relatively safe environment that frameworks provide, and can be even more risky when it comes to writing general purpose Ruby programs.

The CWE/SANS list of the 25 most dangerous software errors provides a good checklist for things that you might be doing wrong in your software. I've been guilty of introducing several of these errors into my own code before, with OS Command Injection being the most recent one. See if you can spot the problem in the simple twitter bot shown below:"@seacreature") do |status|
 `say "#{status.text}"`

If you guessed that the problem is that I wasn't escaping the text in the tweets, you guessed correctly. This security hole allows for arbitrary command execution, which is pretty dangerous. While a tweet like '@seacreature: "; echo "I'm in ur shell, writing your files" > hacked;' would be enough to demonstrate the problem in a gentle way, it doesn't take an evil genius to imagine far more nasty attacks via this vector.

Making this code safer is easy, we can either manually use the Shellwords.shellescape method from the shellwords standard library, or use the array form of IO.popen, which handles shell escaping automatically. The latter approach is shown below, and it's the one I've been using by default lately whenever I need to execute a dynamic shell command."@seacreature") do |status|
  IO.popen(["say", status.text])

This problem and the solution shown here came up in real code that Jordan and I wrote as a part of live demonstration for an intro to software development session we were teaching. We caught the issue before demonstrating the code in front of the class, but did not really think about it in our initial testing. The experience was a bit of an eye opener for me because it made me realize how often such basic security flaws must come up in everyday code, and how much more often they're likely to appear in examples that are constructed primarily for educational purposes.

While there is no substitute for independent external security audits, establishing a few good practices about the way you secure your applications can't hurt. If you integrate with any third party systems, or if you accept user input of any kind, odds are that there are at least some potential areas of vulnerability in your code. Before you put your users at risk, be sure to check your code for the obvious things that could go wrong. While no one will thank you for it, it may help you avoid some very difficult conversations down the line.

Turn the page if you're taking the linear tour, or feel free to jump around via the sidebar.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.