3

我刚刚在我的 webstats 中看到有人在一个 url 参数上附加了很多 SQL 代码。URL 如下所示:

http://www.example.com/page.php?id=672%3f%20and%28select%201%20from%28select%20count%28*%29%2cconcat%28%28select%20%28select%20concat%280x7e%2c0x27%2cunhex%28hex%28cast%28database%28%29%20as%20char%29%29%29%2c0x27%2c0x7e%29%29%20from%20%60information_schema%60.tables%20limit%200%2c1%29%2cfloor%28rand%280%29*2%29%29x%20from%20%60information_schema%60.tables%20group%20by%20x%29a%29%20and%201%3d1

http://www.example.com/page.php?id=convert%28int%2cdb_name%28%29%29--

http://www.example.com/page.php?id=999999.9%20union%20all%20select%200x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536%2c0x31303235343830303536--

还有一些……

我的代码如下所示:

$myid = intval($_GET['id']);
$stmt = $con->prepare("SELECT *
FROM mytable AS r
WHERE r.ID =:ID");
$stmt->bindValue(':ID', $myid, PDO::PARAM_INT);

我的问题是:我的代码安全吗?我如何检查这些查询的结果是什么?我的意思是我的页面只回显我要求的变量。但攻击者当然希望看到他/她查询的内容。

4

3 回答 3

3

它是安全的。在准备好的语句中,参数值从未实际插入到查询字符串中。查询在参数之前被发送到数据库服务器。因此,没有注射的机会。在您的示例中:

发送到数据库服务器:

$stmt = $con->prepare("SELECT * FROM mytable AS r WHERE r.ID =:ID");

将参数发送到数据库服务器:

$stmt->bindValue(':ID', $myid, PDO::PARAM_INT);

这是除非您使用模拟的准备好的语句。要启用准备好的语句:

$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
于 2013-11-02T12:40:55.907 回答
2

您正在从错误的一端提起此日志。

数据来自哪里并不重要,无论是 URL、JSON 对象还是其他文件。

但重要的是目的地。因此,通过准备好的语句进行查询的所有内容都是非常安全的。仅仅因为这是准备好的陈述的目的。

所以,你的大部分预防措施都太多余了,整个代码可能只有 2 行

$stmt = $con->prepare("SELECT * FROM mytable WHERE ID = ?");
$row  = $stmt->execute([$_GET['id']])->fetch();
于 2013-11-02T14:20:30.843 回答
0

你实际上有两条防线,这非常好。

第一个是intval(),它将返回0非数字输入。

第二个是实际准备好的语句。你用的那个很好,保持原样。

但是,使用 prepare() 不会自动使您的代码免受 SQL 注入的影响。您要做的是准备一个带有占位符的常量 SQL 字符串。例如,考虑如下代码:

$stmt = $con->prepare("SELECT * FROM mytable WHERE $cond");  // NEVER DO THIS!

where$cond是一个字符串,它可能包含任意数据,包括危险数据。

(有时,能够动态构建 SQL 查询的一部分很有用,这就是为什么编写类似上面示例的内容如此诱人的原因。但即使在这种情况下,您也必须使用硬编码查询部分创建一个常量SQL您的脚本,为任意数据文字添加占位符,但这不是一项简单的任务。一些数据库抽象框架可能会提供帮助方法,让您更轻松、更安全地执行此操作。)

实际上使您的代码免受 SQL 注入影响的是永远不要将任意数据文字插入到 SQL 代码中,而只能通过占位符插入。准备好的语句的真正目的是允许您以这种方式运行查询,方法是让您使用占位符并将值绑定到它们。从安全的角度来看,这就是它们如此有用的原因。

因此,回顾一下:只要没有任意数据文字进入您的 SQL 语句,您就应该避免 SQL 注入。在您的示例中,您的 SQL 语句是一个常量字符串(带有用于任意数据的 PDO 占位符),所以您可以。

于 2013-11-02T15:58:04.090 回答