menu
more_vert
编写SQL时PHP开发人员所犯的5个常见错误

作者:dayu

mysql_select_db("tutorials");

$result = mysql_query("select * from tutorials"); echo"

Here is a list of the topics:

"; while($row = mysql_fetch_array($result)) {

echo$row[’name’]."
";

}

mysql_close($con); ?>

优秀的实践:

require_once(’includes/conn.inc.php’);

$sql= "SELECT name, age FROM employees WHERE company_id = 10";

$stmt = $pdo->query($sql);

$row = $stmt->fetch(PDO::FETCH_ASSOC);echo$row[’name’];echo$row[age];

不要使用转义函数处理客户端输入的内容

使用mysql_real_escape_string对查询变量进行手工转义是不安全的,原因有两个:

1.

如果经常使用这个方法,你难免会弄错一次。只要有一个漏洞,黑客就可以将代码注入到SQL查询中。

2.

3.

在使用字符串变量时,你应该记住使用引号,很多人都没有这个意识。

4.

mysql_real_escape_string的替换者就是prepared statements (参见下面的更多信息)

不要假设预处理在PHP中总是安全的

Prepared statements预处理的目标是将查询与数据分离,以便将数据正确地插入到查询的参数中,而不需要任何操作选项。在大多数情况下,预处理的语句应该是非常安全的,它被认为是为查询注入用户输入参数的最佳实践技巧。

代码样例:

require_once(’includes/conn.inc.php’);

$sql= "SELECT * FROM employees";

$stmt = $pdo->prepare($sql);

$stmt->execute();

$result = $stmt->fetchAll();foreach($resultas$row){

echo"

{$row[’employeeName’]}

";

}

那么,预处理在PHP中有什么不足呢?在将用户输入的参数值注入到查询语句这种情况下,就会有问题,因为预处理不支持这种注入。例如,MySQL PDO不支持在LIMIT情况中注入参数(使用占位符“?”)。此外,用户输入的内容不能在查询中插入表名或列名。如果你在这些情况下使用预处理,你应该手动地对数据进行人工处理,或者比这更好的方式就是找一个已经测试过的库,自动替你去做这些事。

不要假设ORM框架不会受到SQL注入攻击

使用ORM框架是非常棒的(尽管我敢肯定)。虽然这么说,这并不意味着它不会出现SQL注入攻击的情况。的确,在一个ORM生成的查询中想注入代码是很困难的,但是如果程序员不小心犯了个错误,这将会打开一个漏洞。在大多数情况下,在不使用预处理的情况下,将用户输入的值连接到ORM查询时,被注入的SQL语句就会执行。是的,像Doctrine这样的ORM框架提供了使用预处理的功能,所以使用它。从不将字符串连接到查询,无论是ORM查询还是原始SQL查询。

当然,遵守这些规则是不够的——为了避免给任何SQL注入留有一丝喘息的机会,确保你在编码之后一定要测试ORM用法和实现。

糟糕的实践:

在下面的代码示例中,你可以看到从用户输入的一个参数被连接到Doctrine DQL,它将应用程序暴露给SQL注入。

<?php

// INSECURE

$dql = "SELECT u

FROM MyProject\\Entity\\User u

WHERE u.status = ’" . $_GET[’status’] . "’

ORDER BY " . $_GET[’orderField’] . " ASC";

糟糕的实践:

正如推荐给非ORM用户一样,在使用ORM框架(Doctrine)时,推荐使用预处理语句。

<?php

$orderFieldWhitelist =array(’email’, ’username’);

$orderField = "email";

if(in_array($_GET[’orderField’], $orderFieldWhitelist)) {

$orderField = $_GET[’orderField’];

}

$dql = "SELECT u

FROM MyProject\\Entity\\User u

WHERE u.status = ?1

ORDER BY u." . $orderField . " ASC";

$query = $entityManager->createQuery($dql);

$query->setParameter(1, $_GET[’status’]);

样例的源码地址:Doctrine文件

不要低估字符编码的力量

根据OWASP(开放式Web应用程序安全项目),不使用utf8mb4会导致你的应用程序暴露给各种类型的攻击(你可以阅读更多关于encoding bypassing的信息)。另外,你应该经常在PHPMySQL中使用utf8mb4,以获得更好和更标准的多语言支持。

代码样例:

$dsn = ’mysql:host=example.com;dbname=testdb;port=3306;charset=utf8mb4’;

来源:极客头条

编写SQL时PHP开发人员所犯的5个常见错误