Locking Ruby in the Safe
Walter Webcoder has a great idea for a portal site: The Web Arithmetic
Page. Surrounded by all sorts of cool mathematical links and banner
ads that will make him rich is a simple central frame, containing a
text field and a button. Users type an arithmetic expression into the
field, press the button, and the answer is displayed. All the world's
calculators become obsolete overnight, and Walter cashes in and retires to
devote his life to his collection of car license plate numbers.
Implementing the calculator is easy, thinks Walter. He accesses the
contents of the form field using Ruby's CGI library, and uses
the
eval
method to evaluate the string as an expression.
require 'cgi'
cgi = CGI::new("html4")
# Fetch the value of the form field "expression"
expr = cgi["expression"].to_s
begin
result = eval(expr)
rescue Exception => detail
# handle bad expressions
end
# display result back to user...
|
Roughly seven seconds after Walter puts the application online, a
twelve-year-old from Waxahachie with glandular problems and no real
life types ``
system("rm *")
'' into the form and, like his
application, Walter's dreams come tumbling down.
Walter learned an important lesson:
All external data is
dangerous. Don't let it close to interfaces that can modify your
system. In this case, the content of the form field was the
external data, and the call to
eval
was the security breach.
Fortunately, Ruby provides support for reducing this risk. All
information from the outside world can be marked as
tainted. When running in a safe mode, potentially dangerous
methods will raise a
SecurityError
if passed a tainted object.