php 防止sql注入
Q:如果把用户输入的没有任何改动的放到SQL的查询语句中,很有可能会导致SQL注入,比如说下面的例子:
$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
为什么会有注入漏洞呢?因为用户可以输入value'); DROP TABLE table;--
然后查询语句就变成了这样
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
A:通过使用预编译语句(prepared statements)和参数化查询(parameterized queries)。
有两种方式去完成这个:
1. 使用PDO对象(对于任何数据库驱动都好用) $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name));
2. 使用MySqli $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); $stmt->execute();
================
通常有一下几种方法:
(1)输入验证和过滤
(2)预处理Sql语句
(3)采用存储过程
(4)输入白名单
(5)一般的简单过滤,直接用php的addslashes函数即可。
全面防注入:
function inject_check($sql_str) { return eregi('select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile', $sql_str); // 进行过滤 } function verify_id($id=null) { if (!$id) { exit('没有提交参数!'); } // 是否为空判断 elseif (inject_check($id)) { exit('提交的参数非法!'); } // 注射判断 elseif (!is_numeric($id)) { exit('提交的参数非法!'); } // 数字判断 $id = intval($id); // 整型化 return $id; }
function str_check( $str ) { if (!get_magic_quotes_gpc()) { // 判断magic_quotes_gpc是否打开 $str = addslashes($str); // 进行过滤 } $str = str_replace("_", "\_", $str); // 把 '_'过滤掉 $str = str_replace("%", "\%", $str); // 把 '%'过滤掉 return $str; }
function post_check($post) { if (!get_magic_quotes_gpc()) { // 判断magic_quotes_gpc是否为打开 $post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤 } $post = str_replace("_", "\_", $post); // 把 '_'过滤掉 $post = str_replace("%", "\%", $post); // 把 '%'过滤掉 $post = nl2br($post); // 回车转换 $post = htmlspecialchars($post); // html标记转换 return $post; }
/** * 转义需要插入或者更新的字段值 * * 在所有查询和更新的字段变量都需要调用此方法处理数据 * * @param mixed $str 需要处理的变量 * @return mixed 返回转义后的结果 */ public function escape($str) { if (is_array($str)) { foreach ($str as $key => $value) { $str[$key] = $this->escape($value); } } else { return addslashes($str); } return $str; }
使用实例:
public function _saveWithWhere($tableName, $row, $where, $sync = false) { // 生成要插入/更新的字段的SQL字符串 $values = ''; foreach ($row as $searchKey => $val) { $values .= "`{$searchKey}` = '{escape($val)}',"; } $values = trim($values, ","); // 有itemId的话就UPDATE没有的话就INSERT if (trim($where)) { $sql = "UPDATE {$tableName} SET {$values} WHERE {$where} "; }else { $sql = "INSERT INTO {$tableName} SET {$values}"; } $this->saveLog($sql); // lib_DB->update 只返回 boolean 当 insert 的时候需要获取 last_id 就不行 return $this->_update($sql, $sync); }
其他重要:
1. http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php
每天一小步,人生一大步!Good luck~