我刚刚在我的webstats中看到有人将大量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);
我的问题是: 我的代码安全吗? 我如何检查这些查询的结果是什么?我的意思是我的页面只回显了我要求的变量。但攻击者当然希望看到他/她所查询的内容。
答案 0 :(得分: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);
答案 1 :(得分:2)
您正在从错误的一端解除此日志。
无关紧要,数据来自哪里,是URL,JSON对象,还是其他任何文件。
但重要的只是目的地。因此,通过预处理语句进行查询的所有内容都是绝对安全的。只是因为这是准备好的陈述的目的。
因此,您的大多数预防措施都过于冗余,整个代码只能是2行
$stmt = $con->prepare("SELECT * FROM mytable WHERE ID = ?");
$row = $stmt->execute([$_GET['id']])->fetch();
答案 2 :(得分:0)
你实际上有两条防线,非常好。
第一个是intval()
,对于非数字输入,它将返回0
。
第二个是实际准备好的陈述。你正在使用的那个很好,就这样保持它。
然而,使用prepare()的 会自动使代码免受SQL注入的影响。您需要做的是使用占位符准备一个常量SQL字符串。 例如,考虑这样的代码:
$stmt = $con->prepare("SELECT * FROM mytable WHERE $cond"); // NEVER DO THIS!
其中$cond
是一个字符串,可能包含任意数据,包括危险数据。
(有时, 对于能够动态构造SQL查询的一部分很有用,这就是为什么写上面的例子可能会如此诱人。但即使在这种情况下你也必须从脚本中的硬编码查询部分创建一个常量SQL,为任意数据文字添加占位符,但这不是一项简单的任务。一些数据库抽象框架可以提供帮助方法,让您更轻松,更安全地执行此操作。)
实际上 使代码免受SQL注入的影响是永远不要将任意数据文字插入SQL代码,而只是通过占位符。准备语句的目的是允许以这种方式运行查询,方法是让您使用占位符并将值绑定到它们。从安全角度来看,这就是它们如此有用的原因。
所以,回顾一下:只要没有任意数据文字进入你的SQL语句,你应该安全地从SQL注入。在您的示例中,您的SQL语句是一个常量字符串(带有任意数据的PDO占位符),所以您没问题。