2013-03-11 45 views
1

我一直在为视频网站开发一个项目。它从数据库中提取信息并在需要的地方插入细节。PDO实现,MySQL,SQL注入

到目前为止,一切都很完美,但我刚刚完成了SQL注入测试,并且所有内容都完全打开。我一直在寻找答案来关闭它,并使事情变得更加安全。

我试图实现PDO的声明,但我不能得到我的头。我只在本月为php/sql工作,所以我非常新。

任何帮助或其他的解决方案将是惊人的,下面的代码是我的,我相信主要页面的连接点,也是最脆弱的部分

<?php 
$username="********"; 
$password="*******"; 
$database="*******"; 

$id = $_GET['id']; 
$badchars = array("\"", "\\", "/", "*", "'", "=", "-", "#", ";", "<", ">", "+", "%"); 
$myid = str_replace($badchars, "", $id); 
mysql_connect('localhost',$username,$password); 
@mysql_select_db($database) or die("Unable to select database"); 
$result = mysql_query("SELECT * FROM Videos WHERE id='$id'"); 
while($row = mysql_fetch_array($result)) { 
    $title=mysql_result($result,0,"title"); 
    $url=mysql_result($result,0,"url"); 
    $id=mysql_result($result,0,"id"); 
    $description=mysql_result($result,0,"description"); 
    $source=mysql_result($result,0,"source"); 
    $type=mysql_result($result,0,'type'); 
} 
?> 
+3

***不要试图让你自己的SQL更清洁,使用提供给你的。 'mysql_real_escape_string'。 – 2013-03-11 19:44:24

+1

您尝试过的PDO代码是什么? – 2013-03-11 19:45:52

+0

'mysql_fetch_array'给你所有的字段,你不需要使用'mysql_result' *也*。 – 2013-03-11 19:49:51

回答

2

下面是您的示例重写为使用PDO和解释。

<?php 
$username="********"; 
$password="*******"; 
$database="*******"; 

try { 
    $pdo = new PDO("mysql:host=localhost;dbname=$database", $username, $password); 
} catch (PDOException $e) { 
    error_log("PDO connection error: " . $e->getMessage()); 
    header("Location: http://www.example.com/error.php"); 
    exit; 
} 

您可以将GET参数强制转换为int,该参数只会使用数字部分并剥离其他任何东西。

$id = (int) $_GET['id']; 

在要替换动态值的查询中留下一个占位符。您可以使用位置参数与?符号,或命名参数与冒号前缀语法。

$sql = "SELECT * FROM Videos WHERE id = :id"; 

在每次调用prepare()或execute()后测试错误都很重要。

如果错误不是简单的die(),最好让浏览器保持白屏,但如果可能的话应该恢复,否则至少会显示一个友好的“哎呀!”。页面,以便用户可以继续使用您的网站。

$stmt = $pdo->prepare($sql); 
if ($stmt === false) { 
    $err = $pdo->errorInfo(); 
    error_log("PDO prepare error: " . $err[2]); 
    header("Location: http://www.example.com/error.php"); 
    exit; 
} 

传递一个参数值数组以替代execute()的参数。在命名参数的情况下,它是一个关联数组。在位置参数的情况下,使用简单的序数组。

if ($stmt->execute(array(":id"=>$id)) === false) { 
    $err = $stmt->errorInfo(); 
    error_log("PDO execute error: " . $err[2]); 
    header("Location: http://www.example.com/error.php"); 
    exit; 
} 

然后你可以从语句的结果集读取每行关联数组:

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
    extract($row); 
} 

注意我发现使用extract(),这是一个创建变量$冠军的PHP内置函数,$ url等等,基于关联数组$ row的键。但我这样做只是为了匹配你的代码;通常我只是将这些字段引用为$row["title"]等等。

+0

OP的注意事项:所有'try..catch'和'$ stmt-> errorInfo()'块这里没用,使代码臃肿,没有理由没用。在真实项目中使用此代码时,请将其全部清除。 – 2013-03-11 20:58:35

+0

@YourCommonSense,张贴您自己的答案,因为切线设计问题而投票下达别人的是轻率和粗鲁的。 – 2013-03-11 21:00:38

+0

感谢您抽出时间回答问题,并对每个部分给出了非常详细的解释,正是我所需要的 当我回到笔记本电脑时,我会尝试一下,希望我可以把它放在头上。 不好意思,但是,可悲的是我无法对此投票,因为我需要+15的声望才能这样做 – Stewart 2013-03-11 21:10:33

-1
$result = mysql_query("SELECT * FROM Videos WHERE id='" . mysql_real_escape_string($_GET['id']) . "'"); 

...你可能还需要考虑使用mysql_fetch_assoc()而不是mysql_fetch_array(),这将大大简化结果值。那些对mysql_result()的调用根本不需要。