Age-Old Problem

Suppose you want to authenticate user from the login/password entered on the web from [ruby] user = User.first(:conditions => "login = '#{ login }' AND password = '#{ password }'") [/ruby] Such authentication code as we know can be easily fooled with the SQL injection. Thankfully in Rails there are parameterized queries and the above can be rewritten in at least 3 injection safe ways [ruby] User.find_by_login_and_password(login, password) # or User.first(:conditions => ["login = ? AND password = ?", login, password]) # or User.first(:conditions => ["login = :login AND password = :password", { :login => login, :password => password }]) [/ruby]

Many Solutions (Haskell Included)

Parameterized queries cover most of the cases but what if you have large query with multiple parameters? You can quickly lose track of all the question marks and order in which parameters appear. Most likely you will prefer the latter, hash-based notation.

Side note: This stuff is actually analyzed in depth by Jim Weirich in his The Building Blocks of Modularity presentation where he talks about the connascence in software.

Back to our topic what we really want is just to write SQL queries injecting properly quoted values where needed. In other words we would like to be able to customize the way string interpolation works. In cool languages like Haskell this concept is natively supported and called Quasiquotation. While not really on par with such rigorous achievements it can be simulated everywhere where eval is available. Here is for example the solution from the Google Caja team.

Hack For Better Future

There is eval in Ruby and there is also one peculiar feature about it. You can pass binding to it, and when the block is created it's binding is captured and therefore can be used from anywhere (providing access to the lexical scope captured by the block). Let's illustrate that [ruby] ruby-head > def m local = 42 proc {} # return empty block to get binding from it later end ruby-head > eval("local", m.binding) # binding gives access to the scope where block was created => 42 [/ruby]

Using that feature we can hide eval and implement our own safe interpolation routines like I did in safe_interpolate.rb. Use it like [ruby] ruby-head > require 'dolzenko/safe_interpolate' ruby-head > include SafeInterpolate ruby-head > login = "' or 1=1" ruby-head > sql_interpolate { 'login = #{ login }' } => "login = ''' or 1=1'" # single quote got turned into double and the whole expression is quoted itself [/ruby] HTML and URI escaping are also provided [ruby] ruby-head > content = "" ruby-head > html_interpolate { '

#{ content }

' } => "

<script>alert(1)</script>

" # injection prevented! ruby-head > query = "&admin=1" ruby-head > uri_interpolate { 'http://example.com?q=#{ query }' } => "http://example.com?q=%26admin%3D1" [/ruby]

Further Reading

A type-based solution to the "strings problem": a fitting end to XSS and SQL-injection holes? by Tom Moertel. This article got me interested in the subject.
Haskell features I'd like to see in other languages by Tim Carstens. Check the «Quasi-quoting» section for collection of Haskell quoting related links.