Perl's taint mode to the rescue
by Andy Lester
The three most common types of security vulnerabilities in 2005 were cross-site scripting (16.0%), SQL injection (12.9%) and buffer overflows (9.8%). So far in 2005, buffer overflows has lost the #3 place to PHP remote includes.
The good news is that Perl has long had capabilities in the language and its most common libraries that effectively shut down many of these attacks.
It's not surprising that buffer overflows are on the way out. Perl programmers have long been able to not worry about buffer overflows. Dynamic strings mean no buffer overruns. Fortunately, all the new dynamic languages like Ruby, Python and PHP have dynamic strings as well, leaving only C and C++ programmers having to worry about the size of their malloc buffers.
Where Perl shines in web security is with its built-in "taint mode". When taint mode is enabled, all data from an external source, such as from a web input form, is assumed to be untrusted and tainted. If a user types in her name, the resulting string is marked internally as tainted. Most of the time, this effect is invisible.
Perl will print out the the user's name, because no matter what $name is, it doesn't present a security risk. However, consider this common rookie programmer mistake.print "Hello, $name, glad to see you.\n";
That works fine for values of $name like "Bob Smith", but consider a string like:$dbh = ... code to make a database connection ...; $dbh->do( "insert into visitors (name) values ('$name')" );
Your SQL expands out into'); drop table visitors;
That results in three statements, separated by semicolons: One inserts an empty value in the "visitors" table, the second deletes the "visitors" table, and the third a syntax error. The effect is that one well-crafted string from a miscreant means you've lost your data table. The possibilities are endless.insert into visitors (name) values (''); drop table visitors;')
Taint mode to the rescue!With Perl's taint mode, and DBI's TaintIn attribute enabled, SQL injection attacks can't happen. Perl's DBI module sees the tainted data, since any data created from tainted data is also tainted, and refuses to execute the command. In effect, DBI says "You don't know that the SQL command you're passing me is trustworthy, so I won't run it."
Of course, DBI handles the safe way of doing SQL calls, using placeholders:
The data is passed to DBI, but entirely separately from the command. The command is not created using tainted data, so is safe for DBI to execute.$sth = $dbh->prepare( "insert into visitors (name) values (?)" ); $sth->execute( $name );
SQL injection prevention is just the beginning of the value of taint mode to Perl programmers. Tainted data also can't be used for executing system commands or reading source code, as in the PHP remote include exploits. For a more thorough discussion of how taint mode works, and why you want it on in every web program you write, see the perlsec documentation for Perl with perldoc perlsec, or online at http://perldoc.perl.org/perlsec.html
I hope that other dynamic languages continue to borrow Perl's features and add explicit taint-mode checking to their bags of tricks. Modern web development demands it.
|Ruby's got that ($SAFE, tainting & friends). Can somebody say if Python does it too?|
|Hopefully, people would never have their CGIs connect to the database as a user with drop privs :-)|
|Even without DROP privs, how about DELETE FROM tablename, good enough?|
|Taint mode is nifty, but in the context of "modern web development" it's far from enough. Your very first example, if it's on a CGI script, is an XSS/CSRF attack waiting to happen!|
A flaw in the taint mode...
|Short, precise and useful article on the use of Perl Taint mode and DBI TaintIn attribute. Thanks for it.|