PHP Sql注入漏洞

问题描述:

我写了下面的脚本作为我有史以来第一个php mysql应用程序。我自学成才,代码按预期工作。我的主机认为它可能容易受到sql注入攻击,但无法告诉我为什么或者应该改变什么以使其更好。我敢肯定,它不是那么干净,但如果任何人有任何建议或见解,我一定会很感激。PHP Sql注入漏洞

<form method="post" action="search.php?go" id="searchform"> 
     <?php 
     $db=mysql_connect ("server", "*", "*") or die ('I cannot connect to the database because: ' . mysql_error()); 
    $mydb=mysql_select_db("*"); 
$category_sql="SELECT distinct category FROM Members"; 
$category_Options=""; 
$category_result=mysql_query($category_sql) or die ('Error: '.mysql_error()); 
while ($row=mysql_fetch_array($category_result)) { 

    $category=$row["category"]; 
    $category_Options.="<OPTION VALUE=\"$category\">".$category.'</option>'; 
} 
?> 
    <p> 
      <SELECT NAME="category"><OPTION VALUE=0>Choose<?=$category_Options?></SELECT> 

    </p> 
<input name="submit" "id="submit" type="submit" value="submit" /> 
    </form> 


<?php 
    if(isset($_POST['submit'])){ 
    if(isset($_GET['go'])){ 
    $category=$_POST['category']; 
    $category=mysql_real_escape_string($category); 
    $sql="SELECT category, company, address, city, state, zip, phone, web, addescription, image 
    FROM Members 
    WHERE category LIKE '$category'"; 
$result=mysql_query($sql); 
    while($row=mysql_fetch_array($result)){ 
     $category2=$row["category"]; 
     $company=$row["company"]; 
     $address=$row["address"]; 
     $city=$row["city"]; 
     $state=$row["state"]; 
     $zip=$row["zip"]; 
     $phone=$row["phone"]; 
     $web = $row["web"]; 
     $addescription = $row["addescription"]; 
     $image = $row["image"]; 
    echo "<blockquote>"; 
    if(@file_get_contents($image)) 
{ 
    echo "<img src='".$image ."' class='image'/>\n"; 
} 
else 
{ 
} 
    echo "<p>\n"; 
    echo "</br>".$category2 . "\n"; 
    echo "</br><b>".$company . "</b>\n"; 
    echo "</br>".$address . "\n"; 
    echo "</br>".$city . ", ".$state. " ".$zip . "\n"; 
    echo "</br>".$phone . "\n"; 
    echo "</br><a href=http://".$web .">".$web ."</a>\n"; 
    echo "</br>".$addescription . "\n"; 
    echo "</br><a href=http://www.printfriendly.com style=color:#6D9F00;text-decoration:none; class=printfriendly onclick=window.print();return false; title=Printer Friendly and PDF><img style=border:none; src=http://cdn.printfriendly.com/pf-button.gif alt=Print Friendly and PDF/></a>\n"; 
    echo "</p>"; 
    echo "</blockquote>" 
    ; 
} 


    } 
    else{ 
    echo "<p>Please select a Category</p>"; 
    } 
    } 
mysql_close($db) 
?> 
+3

你是否检查了这篇文章(http://stackoverflow.com/questions/60174/how-to-prevent-sql-injection-in-php)?它几乎涵盖了它。 –

+1

有很多文章来防止SQL注入。为什么不谷歌;) – tonoslfx

+0

请注意,'mysql_xxx()'函数已被弃用,并被认为已过时多年。如果你从使用它们的教程中学到了东西,那么你几乎肯定会做错事情,因为足够老的推荐使用这些函数的教程也会足够长,以至于不能再使用其他不好的做法。我建议找到一个网站有更多最新的教程来学习。 – Spudley

不推荐使用MySQL函数。使用MySQLi函数和预准备语句是防止SQL注入攻击的更好方法。

$stmt = $mysqli->prepare('SELECT category, company, address, city, state, zip, phone, web, addescription, image FROM Members WHERE category LIKE ?'); 
$stmt->bind_param('s', $category); 

的问题是在你的代码

$sql = "SELECT category, company, address, city, state, zip, 
      phone, web, addescription, image 
     FROM Members 
     WHERE category LIKE '$category'"; 
$result=mysql_query($sql); 

如果参数$类别从GET或POST参数读取follwoing部分,它应该是escaped

$sql = "SELECT category, company, address, city, state, zip, 
      phone, web, addescription, image 
     FROM Members 
     WHERE category LIKE '" . mysql_real_escape_string($category) . "';"; 

如果你这样做,变量不能用于SQL Injection

顺便说一下(就像Matthew Johnson所说的那样),程序化的mysql扩展从PHP 5.5开始已经被弃用了。您最好使用MysqliPDO

的OOP方式(强烈推荐)看起来像:

$pdo = new PDO($dsn, $user, $password, $options); 
$statement = $pdo->prepareStatement(
    "SELECT category, company, address, 
      city, state, zip, phone, web, 
      addescription, image 
    FROM Members 
    WHERE category LIKE :category;"); 
$statement->bindParam(':category', $category, PDO::PARAM_STR); 
$statement->execute(); 
$categories = $statement->fetchAll(); 
+0

这是十五年前PHP如何完成的,是时候人们停止这样做了。 – tadman

+1

就像我在我的文章中提到的:程序化的方式被剥夺了。我已经添加到PDO的使用。 –

+0

用正确的方法做了很多改进。 – tadman

我带你去一个PDO连接,以及如何与它来查询的执行。它在这里! 首先我们用你的数据库凭证创建连接变量。我们将在$db中存储此连接。

$username = "root"; 
$password = ""; 
$host = "localhost"; 
$dbname = "my_database"; 

$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); 

try{ 
    $db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8"; $username, $password, $options); 
}catch(PDOException $ex){ 
    die("Failed to connect: ".$ex->getMessage()); 
} 

现在,你必须存储在一个$db PDO连接,您可以查询通过。如果你不使用PHP 5.4,你可能想要考虑magic quotes,所以记住这一点。

否则,创建您的查询语句,像这样..

$query = "SELECT category, company, address, city, state, zip, phone, web, addescription, image FROM Members WHERE category LIKE :category" 

之后,你想从$_POST['category']变量的值绑定(或$category因为你创建的)的参数:category。做到这一点,像这样:

$query_params = array(':category' => $category); 

最后,现在你有语句和参数,使用以前创建$db变量来准备和执行该语句。

$statement = $db->prepare($query); 
$result = $statement->execute($query_params); 

由于我们SELECT荷兰国际集团的数据在可能返回多行(假设你有一个类别中的多个行),我们需要考虑这一点。抓住该语句返回类似这样的行:

$rows = $statement->fetchAll(); 

现在,你可以通过使用一个foreach语句是指列标题的数据库表的各$row内。

$citiesArray = array(); 
foreach($rows as $row){ 
    if(isset($row['city'])){ 
     $citiesArray[] = $row['city']; 
    } 
} 

希望有帮助!

只要记住永不相信用户的黄金法则。切勿接受任何原始用户输入并将其插入到数据库中,因为您有可能因安全问题而自行放弃。

你的代码似乎很好。但是请注意,从PHP 5.5.0开始不推荐使用MySQL,而应该使用MySQLiPDO扩展,从而提供更高的安全性。

也许这就是你的主机说这样的事情的原因,但从快速浏览你的代码看起来对我来说很好。

干杯。