现在很多地方都用上数据库系统, 有一些是检查用户名称及密码的登入系统, 但如果没有对用户输入进行过滤, 会有很多潜在危除, 例如以下程式码:
my $sth = $dbh->prepare(“select * from user where user=’$user’ and pass=’$pass'”);
以上这句 SQL 会检索 user 资料表, 找出 user 及 pass 与用户输入匹配的纪录, 有回传便可以登入, 没有回传便登入失败, 这个很容易理解。但如果用户的输入包括了一些特定的 sql 指令, 那便有问题了, 例如用户将 $pass 输入成:
“‘ or user=’user'”
那么程式处理的 sql 语句会是:
“select * from user where user=’$user’ and pass=’$pass’ or user=’user'”
即使密码错误, 只要用户名与 user 匹配也可以进入。另一个做法是输入 SQL 语句中表示结束的 “;” 符号, 那么除了登入系统外, 也可以进行 update, delete, drop table 等语句。
PHP 可以用 mysql_real_escape_string() 处理, 而 Perl 用做法有点不同, DBI 已经内置防止 SQL Injection 功能, 会处理传入的所有特殊字符, 例如引号及分号, 用回上面的例子, 做法如下:
my $sth = $dbh->prepare(“select * from user where user=’?’ and pass=’?'”);
my $sth = $dbh->prepare( $sql );
$sth->execute( $user, $pass );
可以看到 SQL 语句用了 ? 替代要传入的 $user 及 $pass, 而在 $sth->execute() 才传入 $user 及 $pass, DBI 会自动将 execute 传入的参数, 顺序填补到 prepare “?” 的位置, 这样就可以预防 SQL Injection 攻击了.