Ruby Regular Expressions – Security Risk

This post is a half reminder to elaborate when I have free time… But in short, there is nothing wrong with Ruby regular expressions, except that they behave differently than one might expect (in general and if coming from Perl RegEx).

Here is the dealy, from the Programming Ruby book by Dave Thomas:

The patterns ^ and $ match the beginning and end of a line, respectively. These are often
used to anchor a pattern match: for example, /^option/ matches the word option only if it
appears at the start of a line. The sequence \A matches the beginning of a string, and \z and
\Z match the end of a string.

All sounds good right? Well, it turns out that Ruby will execute code within a regular expression if you can pass multi-line input to the parser. For example… Given

class EmailAttachment < ActiveRecord::Base
validates_format_of :attachment, :with => /^[\w\.\-\+]+$/
end

You can easily pass in

attachment.txt%0A<script>alert('open_sesame')</script>

which is converted (as %0A is a URL encoded new line), by ROR, into

"attachment.txt\n<script>alert('open_sesame')</script>"

You can think about the implications of this, feel free… I have been able to have some fun with my own personal site and getting arbitrary JavaScript and (worse) shell commands to execute. Also, I believe this may cause a larger security whole within routes for Rails (at least 2.1.0). I’ll investigate this more later, as the beginning of this post says.

User Agent inspection: finding the client browser name

Here is a short snippet of Ruby code that I wrote today to detect client browser types. (to override CSS styles based on client browsers..) Hope it helps.

  def client_browser_name(user_agent_string)
    case user_agent_string
    when /msie 6/i
      "IE6"
    when /msie 7/i
      "IE7"
    when /msie 8/i
      "IE8"
    when /konqueror/i
      "Konqueror"
    when /firefox\/2/i
      "FF2"
    when /firefox\/3/i
      "FF3"
    when /applewebkit/i
      "Safari"
    when /gecko/i       #generic case where FireFox is not in String (ie. MindField, BonEcho, GranParadiso)
      "Mozilla"
    when /opera/i
      "Opera"
    else
      "Unknown"
    end
  end