$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $var = $pdo->quote("' OR 1=1 /*");not only escapes the literal, but also quotes it (in single-quote ' characters)
$stmt = $pdo->query("SELECT * FROM test WHERE name = $var LIMIT 1");
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection)
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(["' OR 1=1 /*"]);
if (isset($_GET['id'])) {
$id = $_GET['id'];
settype($id, 'integer');
$result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
# now use the result
}
Do you call external shell commands using exec() or system() functions, or to the backtick operator? 如果是这样,除了SQL注入和XSS之外,您可能还需要解决一些问题,即在您的服务器上运行恶意命令的用户 . 如果您想要转义整个命令OR escapeshellarg以逃避单个参数,则需要使用escapeshellcmd .
18 回答
要解决XSS问题,请查看HTML Purifier . 它相当可配置,并具有良好的跟踪记录 .
至于SQL注入攻击,请确保检查用户输入,然后通过mysql_real_escape_string()运行它 . 但是,该函数不会破坏所有注入攻击,因此在将数据转储到查询字符串之前检查数据非常重要 .
更好的解决方案是使用预准备语句 . PDO library和mysqli扩展支持这些 .
绝不信任用户数据 .
trim()
函数从字符串的两边删除空格和其他预定义字符 .stripslashes()
函数删除反斜杠htmlspecialchars()
函数将一些预定义字符转换为HTML实体 .预定义的字符是:
有过滤器扩展(howto-link,manual),它适用于所有GPC变量 . 这不是一件神奇的事情,但你仍然必须使用它 .
这是一种常见的误解,即用户输入可以被过滤 . PHP甚至有一个(现已弃用的)“功能”,称为魔术引号,它 Build 在这个想法的基础之上 . 这是无稽之谈 . 忘记过滤(或清洁,或任何人称之为) .
为了避免出现问题,你应该做的很简单:每当你在国外代码中嵌入一个字符串时,你必须根据该语言的规则来逃避它 . 例如,如果在某些SQL目标MySql中嵌入字符串,则必须为此目的使用MySql函数转义字符串(
mysqli_real_escape_string
) . (或者,对于数据库,如果可能,使用预准备语句是更好的方法)另一个例子是HTML:如果在HTML标记中嵌入字符串,则必须使用htmlspecialchars对其进行转义 . 这意味着每个
echo
或print
语句都应该使用htmlspecialchars
.第三个例子可能是shell命令:如果要将字符串(如参数)嵌入外部命令,并使用exec调用它们,则必须使用escapeshellcmd和escapeshellarg .
等等等等 ...
您需要主动过滤数据的唯一情况是,您是否接受预先格式化的输入 . 例如 . 如果您允许用户发布HTML标记,那么您计划在网站上显示 . 但是,你应该不惜一切代价避免这种情况,因为无论你如何过滤它,它都将是一个潜在的安全漏洞 .
使用MySQL和PHP的现代版本 .
明确设置charset:
手册
手册
手册
手册
[在PHP 5.5.0中已弃用,在PHP 7.0.0中已删除] .
使用安全字符集:
选择utf8,latin1,ascii ..,不要使用易受攻击的字符集big5,cp932,gb2312,gbk,sjis .
使用空间化功能:
mysql_real_escape_string [在PHP 5.5.0中已弃用,在PHP 7.0.0中已删除] .
mysqli_real_escape_string转义字符串中的特殊字符以在SQL语句中使用,同时考虑连接的当前字符集 . 但是建议使用Prepared Statements,因为它们不仅仅是转义字符串,一个语句提出了一个完整的查询执行计划,包括它将使用哪些表和索引,它是一种优化的方式 .
在查询中的变量周围使用单引号(' ') .
检查变量包含您期望的内容:
使用Filter Function filter_var() - 使用指定的过滤器过滤变量:
more predefined filters
preg_match() - 执行正则表达式匹配;
编写您自己的验证功能 .
避免清理输入和转义数据时出错的最简单方法是使用PHP框架,如Symfony,Nette等,或者是该框架的一部分(模板引擎,数据库层,ORM) .
像Twig或Latte这样的模板引擎默认情况下输出转义 - 如果您根据上下文(网页的HTML或Javascript部分)正确转义输出,则无需手动解决 .
框架自动清理输入,你不应该直接使用$ _POST,$ _GET或$ _SESSION变量,而是通过路由,会话处理等机制 .
并为数据库(模型)层有像Doctrine这样的ORM框架或者像Nette Database这样的PDO包装器 .
你可以在这里阅读更多相关信息 - What is a software framework?
使用PHP清理用户输入的最佳BASIC方法:
只是想在输出转义的主题上添加它,如果你使用php DOMDocument来制作你的html输出,它将在正确的上下文中自动转义 . 属性(value =“”)和<span>的内部文本不相等 . 为了安全抵御XSS,请阅读:OWASP XSS Prevention Cheat Sheet
PHP现在有了新的漂亮的filter_input函数,例如,当你有一个内置的FILTER_VALIDATE_EMAIL类型时,你可以解放你找到'最终的电子邮件正则表达式'
我自己的过滤器类(使用javascript来突出显示错误的字段)可以由ajax请求或普通表单发布 . (见下面的例子)
当然,请记住,您需要进行sql查询转义,具体取决于您使用的数据库类型(例如,mysql_real_escape_string()对于SQL Server无用) . 您可能希望在适当的应用程序层(如ORM)自动处理此问题 . 另外,如上所述:输出到html使用其他php专用函数,如htmlspecialchars;)
对于真正允许带有类似剥离类和/或标记的HTML输入,取决于其中一个专用的xss验证包 . 不要将自己的注册内容写入PARSE HTML!
如果您正在使用PostgreSQL,可以使用pg_escape_string()转义PHP的输入
从文档(http://php.net/manual/es/function.pg-escape-string.php):
在你有一个像
/mypage?id=53
这样的页面并且在WHERE子句中使用id的特定环境中,有一个技巧可以帮助确保id肯定是一个整数,如下所示:但当然这只会削减一个特定的攻击,所以阅读所有其他答案 . (是的,我知道上面的代码不是很好,但它显示了具体的防御 . )
不可以 . 如果没有任何上下文,您无法对数据进行一般过滤 . 有时您希望将SQL查询作为输入,有时您希望将HTML作为输入 .
您需要过滤白名单上的输入 - 确保数据符合您期望的某些规范 . 然后,您需要在使用它之前将其转义,具体取决于您使用它的上下文 .
转义SQL数据的过程 - 防止SQL注入 - 与转换(X)HTML数据的过程非常不同,以防止XSS .
PHP 5.2引入了 filter_var 函数 .
它支持大量的SANITIZE,VALIDATE过滤器 .
http://php.net/manual/en/function.filter-var.php
没有任何功能,因为有许多问题需要解决 .
查看(The only proper) PDO tutorial了解您需要了解的有关PDO的所有信息 . (真诚地感谢顶级SO贡献者@YourCommonSense,关于这个主题的优秀资源 . )
XSS - Sanitize data on the way in...
HTML Purifier已经存在了很长时间,并且仍然在积极更新 . 您可以使用它来清理恶意输入,同时仍然允许大量可配置的标签白名单 . 适用于许多WYSIWYG编辑器,但对于某些用例可能很重要 .
在其他情况下,我们根本不想接受HTML / Javascript,我发现这个简单的函数很有用(并且已经针对XSS进行了多次审核):
/* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }
XSS - Sanitize data on the way out... 除非您在将数据添加到数据库之前保证数据已正确清理,否则在将其显示给用户之前需要对其进行清理,我们可以利用这些有用的PHP函数:
当您调用
echo
或print
以显示用户提供的值时,请使用htmlspecialchars除非数据已正确清理并且允许显示HTML .json_encode是一种从PHP提供用户提供的值到Javascript的安全方法
Do you call external shell commands using exec() or system() functions, or to the backtick operator? 如果是这样,除了SQL注入和XSS之外,您可能还需要解决一些问题,即在您的服务器上运行恶意命令的用户 . 如果您想要转义整个命令OR escapeshellarg以逃避单个参数,则需要使用escapeshellcmd .
不,那里没有 .
首先,SQL注入是一个输入过滤问题,XSS是一个输出转义问题 - 所以你甚至不能在代码生命周期中同时执行这两个操作 .
基本的经验法则
对于SQL查询,绑定参数(与PDO一样)或对查询变量使用驱动程序本机转义函数(例如
mysql_real_escape_string()
)使用
strip_tags()
过滤掉不需要的HTML使用
htmlspecialchars()
转义所有其他输出并且是注意这里的第二和第三参数 .你在这里描述的是两个独立的问题:
清理/过滤用户输入数据 .
转义输出 .
1)应始终假定用户输入不好 .
使用预准备语句,或/和使用mysql_real_escape_string进行过滤绝对是必须的 . PHP还内置了filter_input,这是一个很好的起点 .
2)这是一个很大的主题,它取决于输出数据的上下文 . 对于HTML,有像htmlpurifier这样的解决方案 . 根据经验,总是逃避你输出的任何东西 .
这两个问题都太大了,无法在一篇文章中介绍,但有很多帖子更详细:
Methods PHP output
Safer PHP output
你永远不会消毒输入 .
您始终清理输出 .
您应用于数据以使其安全包含在SQL语句中的转换与您申请包含在HTML中的转换完全不同,您应用于Javascript中的转换完全不同于您申请包含在LDIF中的转换完全不同与您在CSS中包含的内容完全不同,与您在电子邮件中包含的内容完全不同....
无论如何validate input - 决定是否接受它进行进一步处理或告诉用户这是不可接受的 . 但是,在数据即将离开PHP之前,不要对数据的表示应用任何更改 .
很久以前有人试图发明一种适用于转义数据的单一尺寸的机制,我们最终得到了“magic_quotes”,它没有正确地逃避所有输出目标的数据,导致不同的安装需要不同的代码才能工作 .
不要试图通过清理输入数据来阻止SQL注入 .
相反, do not allow data to be used in creating your SQL code . 使用使用绑定变量的Prepared Statements(即使用模板查询中的参数) . 这是防止SQL注入的唯一方法 .
有关阻止SQL注入的更多信息,请参阅我的网站http://bobby-tables.com/ .