SQL注入
将用户输入拼接到数据库将要执行的SQL语句中 导致攻击者可以修改原有执行的SQL语句
例子
<?php
include('conn.php');//数据库连接省略
$sql = "SELECT id, name FROM users WHERE id=$_GET['id']";
$result = $mysqli->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - Name: " . $row["name"];
}
} else {
echo "没有查询到结果";
}
?>
正常请求 ?id=123
执行SQL
SELECT id, name FROM users WHERE id=123;
攻击者构造请求: ?id=123 UNION SELECT name,password FROM users;
执行SQL
SELECT id, name FROM users WHERE id=123 UNION SELECT name,password FROM users;
攻击者改变了原有的SQL语句逻辑
常见过滤/防护
addslashes 在单引号(')、双引号(")、反斜线(\)与 NUL前加上反斜线 可用于防止SQL注入
mysqli::real_escape_string mysqli::escape_string mysqli_real_escape_string mysql_real_escape_string SQLite3::escapeString
以上函数会在\x00(NULL), \n, \r, , ', " 和 \x1a (CTRL-Z)前加上反斜线 并考虑了当前数据库连接字符集进行处理
注意: 经过以上函数处理后的字符串不可直接用于sql查询拼接 需要使用引号包裹后拼接到sql语句中 否则仍可导致sql注入
例如 上文中的例子 攻击者输入并没有使用到引号反斜线 逗号可使用其他方法绕过 仍可构成SQL注入
防护方法
<?php
/*强制类型转换*/
$id=intval($_GET['id']); //因查询ID为整数 所以可以强制转换为整数
/*转义特殊字符 加上引号 (字符串类型)*/
$id=$pdo->quote($_GET['name']);
/*预处理语句*/
$stmt =$pdo->prepare("SELECT id, name FROM users WHERE id=?;");
$stmt->execute([$_GET['id']]);//简单的预处理 完整使用方法见PHP手册
?>
PDO::quote 转义特殊字符 并添加引号
PDO::prepare 预处理SQL语句 有效防止SQL注入 (推荐)
intval($input) floatval() floatval() floor() (int)$input num+0
将输入强制转换为整数/浮点 用于整数/浮点类型的输入参数处理 可防止SQL注入
一些执行SQL语句的函数
mysql_query
odbc_exec
mysqli_query
mysql_db_query
mysql_unbuffered_query
mysqli::query
用法
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$mysqli->query();
pg_query
pg_query_params
pg_send_query
pg_send_query_params
sqlsrv_query
pdo::query
$pdo=new PDO("mysql:host=localhost;dbname=phpdemo","root","1234"); $pdo->query($sql);
PDO
SQLite3::query
SQLite3::exec
$db = new SQLite3('mysqlitedb.db'); $db->query('SELECT bar FROM foo'); $db->exec('CREATE TABLE bar (bar STRING)');
最后更新于