如何防止 PHP 中的代码注入攻击?
Posted
技术标签:
【中文标题】如何防止 PHP 中的代码注入攻击?【英文标题】:How to prevent code injection attacks in PHP? 【发布时间】:2010-11-15 09:47:22 【问题描述】:我有点迷茫,php中有这么多函数,有的用这个,有的用那个。有些人使用:htmlspecialchars()
、htmlentities()
、strip_tags()
等
哪个是正确的,你们通常用什么?
这是正确的吗(如果有的话,请给我一个更好的建议):
$var = mysql_real_escape_string(htmlentities($_POST['username']));
这一行可以防止MySQL注入和XSS攻击??
顺便说一句,除了 XSS 攻击和 MySQL 注入之外,我还有什么需要注意的吗?
编辑
总结:
如果我想将字符串插入数据库,我不需要使用htmlentities
,只需使用mysql_real_escape_string
。显示数据的时候用htmlentities()
,是这个意思吗??
总结:
mysql_real_escape_string
插入数据库时使用
htmlentities()
输出数据到网页时使用
htmlspecialchars()
什么时候用过?
strip_tags()
什么时候用过?
addslashes()
什么时候用过?
有人可以填写问号吗?
【问题讨论】:
strip_tags() 可能不安全 securiteam.com/unixfocus/5UP0C15DFI.html 你可能关心 CSRF 和目录横向;修复目录横向的简单方法是basename(realpath($path))
。
【参考方案1】:
看看这个网站PHP Security Consortium。我发现它是一个很好的网站,可以全面了解 PHP 安全性(包括 SQL 注入和 XSS)。
【讨论】:
那个网站现在已经严重过时了【参考方案2】:您只需要在插入数据库时使用 mysql_escape_string() 并在显示 HTML 时使用 htmlentites。如果您想防止简单的注入攻击,这就足够了,但毫无疑问,在开发 Web 应用程序时您应该注意许多其他安全问题,另一个主要问题是跨站点请求伪造。
【讨论】:
很高兴您声明这足以防止简单的代码注入。对于敏感的财务和医疗信息,我会更进一步,建议使用 PDO 或 Mysqli 扩展。理想情况下,您希望使用准备好的语句和参数化查询。看到这个答案:***.com/questions/60174/…【参考方案3】:仅在数据进入系统需要对其进行编码的位置对数据进行编码 - 否则您将遇到需要操作真实数据的情况。
对于 SQL 注入 - 使用 How can I prevent SQL injection in PHP? 中描述的绑定变量(它谈到准备好的语句,但它是为您提供保护的绑定,而不是准备)。
对于 XSS - 如果您在指定 HTML 或文本的位置写入 HTML。在生成文档时使用 htmlentities。我会避免以这种形式将数据存储在数据库中(除非可能在 CPU 性能/磁盘访问时间正在变成和问题的写入罕见读取系统中 - 然后我会有一个 raw_ 和一个 html_ 版本的列... 或者只使用 memcached 或类似的)。
如果您让用户输入 URL,那么您需要更加小心,因为javascript:do_evil()
是一个有效的 URI,它将执行(例如,作为单击链接的 href 或(在某些浏览器中)图像的 src刚刚加载)。
【讨论】:
【参考方案4】:在将数据插入数据库或查询数据库时,我不会使用 htmlentities()。如果您数据库中的数据存储为实体,则该数据仅对理解 html 实体的东西有用。
您必须对不同类型的输出使用不同的转义机制,例如SQL - mysql_real_escape_string(),HTML - htmlentities() 或 htmlspecialchars(),shell - escapeshellarg()。这是因为“危险”字符对于每个字符都是不同的 - 没有一种神奇的方法可以让任何数据对任何输出媒体都安全。
【讨论】:
【参考方案5】:mysql_real_escape_string
插入数据库时使用htmlentities()
输出数据到网页时使用htmlspecialchars()
什么时候用过?strip_tags()
什么时候用过?addslashes()
什么时候用过?
htmlspecialchars() 什么时候使用?
htmlspecialchars
与htmlentities
大致相同。区别:字符编码。
两者都对用于打开标签等的<
、>
、&
等控制字符进行编码。htmlentities
还对来自其他语言的字符进行编码,如变音符号、欧元符号等。如果您的网站是 UTF,请使用 htmlspecialchars()
,否则使用 htmlentities()
。
strip_tags() 什么时候使用?
htmlspecialchars
/ entities
对特殊字符进行编码,因此它们显示但不解释。 strip_tags
删除它们。
实际上,这取决于您需要做什么。
举个例子:您编写了一个论坛,并为用户提供了一个文本字段,以便他们可以发布内容。恶意者试试看:
pictures of <a href="javascript:void(window.setInterval(function () window.open('http://evil.com');, 1000));">kittens</a> here
如果您不执行任何操作,则会显示该链接,并且单击该链接的受害者会收到大量弹出窗口。
如果你 htmlentity/htmlspecialchar 你的输出,文本将按原样存在。如果你 strip_tag 它,它只是删除标签并显示它:
pictures of kittens here
有时您可能想要混合,在其中留下一些标签,例如<b>
(strip_tags
可以在其中留下某些标签)。这也是不安全的,所以最好使用一些成熟的库来对抗 XSS。
添加斜杠
引用old version of the PHP manual:
在需要在数据库查询等中引用的字符之前返回一个带有反斜杠的字符串。这些字符是单引号 (')、双引号 (")、反斜杠 () 和 NUL(NULL字节)。
addslashes() 的一个示例用法是在您将数据输入数据库时。例如,要将名称 O'reilly 插入数据库,您需要对其进行转义。强烈建议使用 DBMS 特定的转义函数(例如 MySQL 的 mysqli_real_escape_string() 或 PostgreSQL 的 pg_escape_string()),但是如果您使用的 DBMS 没有转义函数并且 DBMS 使用 \ 来转义特殊字符,您可以使用这个功能。
current version 的措辞不同。
【讨论】:
感谢 stefs - 对我来说,我需要一个简单的解决方案,因为更广泛的安全复杂性使我无法生成代码。我正在尝试使用一个简单的脚本来读取 curl 并取出特定的图像标签和 url - 连同一个 wordpress rss 提要,一些新闻条目已创建好供本地站点使用。这是在网页上工作的,但我想从一个脚本中做到这一点,突然间没有我的 cms 框架,我担心我在我们的服务器上制造了一个大漏洞以供利用。你知道是否可以在不暴露 api 端点 /get/news ty 的情况下从我的服务器执行此操作【参考方案6】:htmlspecialchars()
将&amp;
、'
、"
、<
和 >
转换为 HTML 实体格式(&amp;
、&quot;
等)
htmlentities()
将所有适用的字符转换为它们的 HTML 实体格式。
strip_tags()
删除所有 HTML 和 PHP 标记。
htmlspecialchars()
和 htmlentities()
都采用一个可选参数,指示应如何处理引号。见
具体的 PHP 手册。
strip_tags()
函数需要一个
可选参数指示什么标签
不应该被剥离。
$var = strip_tags ($var, '<p><br />');
strip_tags()
函数将删除
甚至是无效的 HTML 标签,这可能
造成问题。例如,
strip_tags()
将抽出所有
它认为是 HTML 标记的代码,甚至
如果格式不正确,比如
<b I forgot to close the tag.
【讨论】:
【参考方案7】:我想到了这个快速清单:
始终使用 HTTPS,如果没有 HTTPS,您的网站将完全未加密。不,客户端加密和发送它们是行不通的,想想看。 无效的 HTTPS 证书也会使您容易受到 MITM 攻击。如果您买不起证书,只需使用 Let's Encrypt。 始终在 PHP 代码的任何输出(即包含用户输入或包含用户输入)上使用htmlspecialchars()
。大多数模板引擎可以帮助您轻松做到这一点。
在您的 php.ini
中使用 HTTP-only 标志来防止脚本访问您的 cookie
防止与会话相关的问题
切勿将用户的PHPSESSID
(会话 ID)暴露在 cookie 之外,如果有人知道其他人的会话 ID,他们可以简单地使用它来登录自己的帐户
对Remember me
函数要非常小心,可能会显示一点警告。
在用户登录时刷新会话 ID(或任何适当的)
超时非活动会话
从不信任 cookie,它可以随时由脚本/用户更改、删除、修改和创建
防止与 SQL 相关的问题
始终使用准备好的语句。准备好的语句导致单独传递用户输入并阻止SQL Injection
让您的代码在失败时抛出异常。有时您的 SQL 服务器可能由于某种原因而关闭,PDO
之类的库默认会忽略该错误,并在日志中记录警告。这会导致您从数据库中获取的变量为空,具体取决于您的代码,这可能会导致安全问题。
像PDO
emulate 之类的一些库已准备好语句。将其关闭。
在您的数据库中使用UTF-8
编码,它允许您存储几乎任何字符并避免与编码相关的攻击
切勿将任何内容连接到您的查询。 $myquery = "INSERT INTO mydb.mytable (title) VALUES(" . $user_input . ")"
之类的内容几乎意味着您面临着巨大的 SQL 注入安全风险。
以随机、无扩展名的文件名存储上传的文件。如果用户上传带有.php
文件扩展名的文件,那么每当您的代码加载该文件时,它就会执行它,并使用户能够执行一些后端代码
确保您不会受到CSRF attack 的攻击。
始终更新您的 PHP 副本以确保最新的安全补丁和性能改进
【讨论】:
【参考方案8】:我知道这是一个老问题,但现在投票最多的答案可能会误导初学者。
截至 2017 年
你永远不应该使用 mysql_real_escape_string。甚至 mysqli_real_escape_string 也太弱了,无法保护您的数据库免受 SQL 注入。取而代之的是,您应该使用 PDO 和类似的技术。 (见that guide)
XSS(这里我的意思是:strip_tags()
、addslashes()
、htmlspecialchars()
、htmlentities()
) - 这里投票最多的答案仍然是正确的,但我建议阅读this article
【讨论】:
年份与问题关系不大。您的标题应该是“截至 PHP x.x”,替换为在主机系统上运行的 PHP 版本。并非所有主机都在运行最新版本的 PHP。以上是关于如何防止 PHP 中的代码注入攻击?的主要内容,如果未能解决你的问题,请参考以下文章