SQL注入 - 这个查询安全吗?

时间:2013-11-02 19:30:17

标签: php sql security sql-injection

我有一个页面,它将不同的参数附加到用于查询的URL。

例如

http://www.example.com/search.php?category=Schools&country[]=Belgium&country[]=Czech+Republic

我的代码就像这样

if(isset($_GET['country'])){
$cties = "'" . implode("','", $_GET['country']) . "'";
}
else {
$cties = "'Albania','Andorra','Austria','Belarus','Belgium','Bosnia & Herzegovina','Bulgaria','Croatia','Czech Republic','Denmark','Estonia','Faroe Islands','Finland','France','Germany','Gibraltar','Great Britain','Greece','Hungary','Iceland','Ireland','Isle of Man','Italy','Latvia','Liechtenstein','Lithuania','Luxembourg','Macedonia','Malta','Moldova','Monaco','Montenegro','Netherlands','Norway','Poland','Portugal','Serbia','Romania','San Marino','Slovakia','Slovenia','Spain','Sweden','Switzerland','Ukraine','United Kingdom'";           
}
if(isset($_GET['category'])){
$cat = $_GET['category'];
}
else{
$cat = " ";
}

try{
// create the Prepared Statement

$stmt = $con->prepare("SELECT * FROM MyTable 
WHERE MyDate >= DATE(NOW()) 
AND (Category=:cat or '' = :cat) 
AND Country IN ($cties)
ORDER BY MyDate ASC");
$stmt->bindValue(':cat', $cat, PDO::PARAM_STR);
$stmt->execute();

我想知道这个查询是否安全,如果没有,我做错了什么。 提前谢谢!

我终于明白了(感谢你的常识):

if(isset($_GET['country'])){
$arr = $_GET['country']; 
}
else {          
$arr = array('Albania','Andorra','Austria','Belarus','Belgium','Bosnia & Herzegovina','Bulgaria','Croatia','Czech Republic','Denmark','Estonia','Faroe Islands','Finland','France','Germany','Gibraltar','Great Britain','Greece','Hungary','Iceland','Ireland','Isle of Man','Italy','Latvia','Liechtenstein','Lithuania','Luxembourg','Macedonia','Malta','Moldova','Monaco','Montenegro','Netherlands','Norway','Poland','Portugal','Serbia','Romania','San Marino','Slovakia','Slovenia','Spain','Sweden','Switzerland','Ukraine','United Kingdom');
}
if(isset($_GET['category'])){
$cat = $_GET['category'];
}
else{
$cat = " ";
}
// create the Prepared Statement
$in  = str_repeat('?,', count($arr) - 1) . '?';

$sql = "SELECT * FROM MyTable WHERE MyDate >= DATE(NOW()) 
    AND Country IN ($in)
    AND (Category=? or '' = ?) 
    ORDER BY MyDate ASC";
$stmt  = $con->prepare($sql);
$arr[] = $cat;  // adding category to array
$arr[] = $cat;  // we need it twice here
// finally - execute
$stmt->execute($arr);

2 个答案:

答案 0 :(得分:2)

是的,现在我看到了你的问题。那么,PDO对于这样的任务来说不是一个方便的库。所以,首先我会告诉你如何使用我自己的库来完成它:

$sql = "SELECT * FROM MyTable WHERE MyDate >= CURDATE() 
          AND (Category=?s or '' = ?s) 
          AND Country IN (?a)
          ORDER BY MyDate ASC"
$data = $db->getAll($sql, $cat, $cat, $_GET['country']);

但我完全意识到你们都倾向于采用熟悉的方法。好吧,让我们用丑陋的PDO详细说明

首先,目标是什么?目标是

  1. 创建包含所有数据占位符的查询。我会坚持使用位置占位符,因为它们更容易实现。
  2. 创建一个包含所有必须绑定到占位符的变量的数组
  3. 似乎我们需要两个占位符用于类别和一些未知数量的城市。好的,这一行将创建一串占位符:

    $in   = str_repeat('?,', count($arr) - 1) . '?';
    

    我们将要插入到查询中。

    // $arr is array with all the vars to bind. at the moment it contains cities only
    $arr = $_GET['country']; 
    // creating string of ?s
    $in  = str_repeat('?,', count($arr) - 1) . '?';
    // building query
    $sql = "SELECT * FROM MyTable WHERE MyDate >= DATE(NOW()) 
                  AND Country IN ($in)
                  AND (Category=? or '' = ?) 
                  ORDER BY MyDate ASC";
    $stm  = $db->prepare($sql);
    $arr[] = $_GET['category'];  // adding category to array
    $arr[] = $_GET['category'];  // we need it twice here
    // finally - execute
    $stm->execute($arr);
    $data = $stm->fetchAll();
    

答案 1 :(得分:0)

不,可以在$_GET['country']参数中注入SQL代码。你不能在任何地方逃避它。

请参阅PHP PDO: Can I bind an array to an IN() condition?