标签:
本文和大家分享的主要是编写SQL时PHP开发人员常犯的一些错误,一起来看看吧,希望对大家学习php有所帮助。
杜绝使用MySQL API的旧版本
使用PHP开发时有好几种方法可以连接MySQL数据库。最常见的是MySQL API、MySQLi API和PDO API(PHP数据对象)。与MySQL API旧版本相比,后面两种方法支持更多的功能,并且更加安全。如果你使用的是旧的“mysql_”函数,那么你应该马上放下手上的工作,然后开始学习新的PDO API。这些旧的 mysql函数被弃用 ,并且PHP 7.x以后的版本也不会再支持了。
糟糕的实践:
<?php
$con = mysql_connect("localhost", "root", "mypass") or
die("Could not connect: " . mysql_error());
mysql_select_db("tutorials");
$result = mysql_query("select * from tutorials"); echo "
"; 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($result as $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的信息)。另外,你应该经常在PHP和MySQL中使用utf8mb4,以获得更好和更标准的多语言支持。
代码样例:
$dsn = ’mysql:host=example.com;dbname=testdb;port=3306;charset=utf8mb4’;
来源: 极客头条
标签: