如果您是编写 HTML/CSS/JS 的 WordPress 开发人员(这包括 100% 的主题开发者和 99% 的插件开发者),那么您需要了解 WordPress 前端安全的基础知识。WordPress 提供了所有必要的工具,让您可以 使您的主题或插件安全。您只需要知道如何以及何时使用每个工具。
例如,作为前端开发人员,您的一项重大责任是防止未转义的内容打印到页面上。
安全是您的责任
在我们讨论具体细节之前,我想消除一个我(以前)用来为“不太严格”的前端安全观点辩护的想法。
“如果黑客已经能够更改代码/数据库/内容,那么我的前端代码是否安全有什么区别?难道他们不能造成更大的损害吗?”
是的,如果黑客已经控制了代码或数据库,那么他们可能并不在乎输出的安全程度(他们可能无论如何都可以更改它)。
即便如此,您仍然有责任使前端代码安全。以下是一些原因:
- 适当的前端安全还可以防止用户错误导致重大问题。如果用户意外地在不应输入的字段中输入了特殊字符,页面就不会崩溃。
- 某些攻击是有限的。也许黑客的控制权很小,只能更改数据库中的单个内容片段。您可以防止这种狭窄的攻击变得更大。
- 安全就像洋葱。最外层(通常不可食用)是前端显示。良好的安全实践使黑客稍微难以利用网站。
打鸡血的话就说到这里了。让我们来谈谈如何保护我们的 WordPress 主题和插件。
我们担心什么?
前端开发人员的一个主要关注点是避免跨站点脚本(简称 XSS,因为“CSS”会导致各种问题。双关语和妙语欢迎。)。
XSS 漏洞允许坏人(“黑客”)窃取信息。通常这意味着窃取 cookie 和会话信息。如果坏人可以将您的活动会话发送回自己(因此有了“跨站点”部分),他们可以使用它登录到您的帐户并执行您可以执行的任何操作(坏消息)。
什么是转义?
在计算机科学中,“转义”一词具有特殊的含义。
将字符或字符串转换为在特定上下文中按字面解释,通常是为了防止这些字符被解释为代码。
换句话说,在 WordPress 前端开发的上下文中:转义将可能存在恶意的内容转换为安全的内容。
这里最大的危险通常是<script>
标签和其他执行 JavaScript 的方法(例如onclick="javascript:"
)。如果可以在页面上输出并执行<script>
,那将非常危险。转义意味着将其转换为<script>,这是安全的。
为什么需要转义:一个例子
如果您不熟悉 XSS,一个简单的例子将展示风险。
假设您的主题有一个字段可以添加阅读链接。“阅读更多”链接,如果可以这样说。在 WordPress 仪表板上,它可能如下所示:

在您的主题中,您希望在文章底部显示此链接,如下所示:

因此,您打开single.php
(负责显示博客文章的文件)并在底部附近添加以下内容:
<?php
$read_more_link = get_post_meta(
get_the_ID(),
'read_more_link',
true
);
?>
<!-- Don't do this -->
<a href="<?php echo $read_more_link; ?>">Read More</a>
假设有人恶意地将以下文本输入到您的自定义字段中:

当您访问页面时,您将看到以下内容:

糟糕!如果该错误输入允许坏人执行 JavaScript,他们可以:
- 重定向用户
- 劫持用户的 cookie
- 执行其他恶意操作
为所有内容转义
既然我们知道了转义的重要性,让我们看看 WordPress 提供的转义方法,并为每个方法提供一些上下文。
函数:esc_html
用于:输出绝对不应该在输出中包含任何 HTML 的内容。
作用:将 HTML 特殊字符(例如<
、>
、&
)转换为其“转义”实体(<
、>
、&
)。
一个常见的示例是在主题中显示纯文本自定义字段。
<?php $dog_name = get_post_meta( $post_id, 'dog_name', true ); ?>
<span class="dog-name"><?php echo esc_html( $dog_name ); ?></span>
函数:esc_attr
用于:在 HTML 属性上下文中使用的输出(例如“title”、“data-”字段、“alt”文本)。
作用:与esc_html
完全相同。唯一的区别是不同的 WordPress 过滤器应用于每个函数。
以下是esc_attr
在图像上的使用示例:
<img src="/images/duck.png"
alt="<?php echo esc_attr( $alt_text ); ?>"
title="<?php echo esc_attr( $title ); ?>" >
函数:esc_url
用于:必须是 URL 的输出。例如图像src属性和href值。
作用:比esc_attr
和esc_html
函数更彻底、更具体的转义,它将 URL 中不允许的任何字符删除或转换为其 URL 安全格式。
当您需要输出链接或动态图像路径时,请使用esc_url
。
<a href="<?php echo esc_url( $url ); ?>">Link Text</a>
<img src="<?php echo esc_url( $image_url ); ?>" >
函数:esc_js
用于:打印 JavaScript 字符串,主要用于内联属性,例如onclick
。
作用:转换特殊字符,例如<
、>
、引号——任何可能破坏 JavaScript 代码的内容。
由于以下几个原因,esc_js
可能是最少使用的 esc_ 函数。
- 大多数 JS 加载在单独的文件中。
- 大多数 JS 不是作为属性内联编写的。
- 对于非内联 JS,
json_encode
是更好的选择。
但是,如果您需要转义一些内联 JS,则可以按照以下方法操作:
<?php $message = get_post_meta( get_the_ID(), 'onclick_message', true ); ?>
<a href="/blog/" onclick="alert('<?php echo esc_js( $message ); ?>')">...</a>
函数:json_encode
用于:打印 PHP 变量以供 JavaScript 使用。
作用:将 PHP 变量(对象、字符串、数组等)转换为该 PHP 变量的合理、转义的 JavaScript 表示形式。
尤其对于使用 WP 变量的<script>
代码块很有用。一个简单的例子
<
预设 rel=”PHP”><?php $categories = get_categories(); ?>
<script type="text/javascript">
var allCategories = <?php echo json_encode( $categories ); ?>;
// 在这里对分类进行一些有趣的操作
</script>
函数:wp_kses
用途:需要允许某些 HTML 但不允许所有标签或属性的输出。
功能:去除内容中与传入规则列表不匹配的任何标签或属性。
如果某个上下文允许打印某些标签(例如,像<strong> 和<em> 这样的内联格式化标签)作为 HTML,则使用wp_kses
。
一个基本的例子是显示评论
esc_attr_e
, esc_attr_x
) 的 _e 和 _x 版本是什么?
转义函数 (这些是便捷函数(为了让你的生活更轻松),在打印可翻译字符串时很有用:可以通过 WordPress 翻译文件更改的文本。
如果你正在开发一个主题或插件以供广泛分发(而不是一个一次性的客户端项目),你将希望使每个字符串都支持国际化。这意味着曾经由你控制的 PHP 字符串可以由翻译人员编辑 – 因此需要转义(你不能相信任何人)
Blog
_e
函数的第二个参数是翻译域。翻译人员在编写和生成翻译时会使用它。
_x
函数(如 esc_html_x)基本上与其_e
对应项相同,但增加了一个“上下文”参数来解释单词或短语的使用上下文。对于具有多种含义的单词很有用
esc_attr_e 的 Codex 条目
esc_attr_x 的 Codex 条目
the_title
和 the_content
怎么样?
如果你打开默认的 WordPress 主题(在撰写本文时名为“Twenty Fifteen”),你会看到类似这样的代码输出文章的标题
你还会看到像这样未转义的 the_content
调用
你可能会感到恐慌。为什么这些函数没有转义?!两个原因
1. WordPress 自动转义它们
像 the_title
这样的函数是便捷函数 – 使前端开发更容易的工具。因此,为了使开发人员更轻松,WordPress已经自动转义了the_title
的输出 更新:WordPress不会转义the_title
,请小心!.
2. 上下文:某些内容是 HTML
在 the_content
的情况下,输出预期为未转义的 HTML。当用户在内容中添加
时,我们可以假设他们实际上想要一个
输出到页面 – 而不是转义后的版本。
如果你担心用户能够在 the_content
的输出中添加脚本,你可以使用 wp_kses
从最终输出中去除不需要的标签。这在子域名和共享主机上很有用,而且我非常确定他们在 WordPress.com(一个托管版的 WordPress,用户不允许添加自己的 JavaScript)上使用的是这种方法。
实用技巧:如果你想将 the_title
用作 HTML 属性,请使用 the_title_attibute 来节省转义操作。the_title_attribute
的实际应用
...
转义内容
我使用过很多插件和主题 – 商业的、免费的和自定义构建的 – 我看到了大量未转义的内容(以及由此产生的 XSS 漏洞)。希望本文能为你提供使你的 WordPress 更加安全的基本工具。
我是否忽略了什么?请在评论中告诉我!
我一直认为 WordPress 应该默认转义所有查询 – 并提供一个可选参数来禁用此功能。世界会变得更安全,不是吗?
Ruby on Rails 就是这么做的,是的,这会很好。但我不确定如何在不破坏基本上所有已编写插件的情况下实现它!
现在是 2015 年,我们仍然像 1999 年一样在模板层编写转义调用。这就是我停止使用 WP 的原因之一;编写非常糟糕的代码太容易了。我不想就模板语言的好坏进行辩论,但在使用了像 Twig(在 Craft、Drupal 8 和其他 CMS 中)这样的东西之后,它默认转义变量,这减少了一件设计师/开发人员最终需要担心的事情。
在自定义字段示例中,这是一个 WP 确实需要内置适当的自定义字段支持(例如 ACF 或 Pods)的例子,该支持还可以验证用户的输入(文本/html/图像/链接/等)并在其甚至到达数据库之前净化该输入。
天啊,我想我用过它
<a href="<?php echo $read_more_link; " read more /a
我希望我的网站上不会发生这种情况。感谢您的信息,这对像我这样的初学者非常有用。
喜欢你网站的随意引用。我当然希望我永远不会去那里,因为显然那里充满了安全漏洞。
/s
将你的输出包装在 wp_strip_all_tags() 中怎么样?
https://codex.wordpress.org/Function_Reference/wp_strip_all_tags
如果我必须让某人在我的网站上发布内容而我并不十分了解他们,我总是使用此函数。
我不明白如果攻击者无法访问服务器文件,你如何植入 js 脚本,如果我是攻击者,我会删除所有网站内容和数据库
太棒了!我目前在 Craft CMS 内部工作,并且在研究 Twig 时遇到了此页面:http://bit.ly/1BnRslK。希望它对那些试图在 Craft 中复制这些原则的人有所帮助。
非常感谢。作为一个主要使用 HTML、CSS、JS 的自学成才的设计师/开发人员,这似乎是一个没人谈论的领域(或者也许我不知道在哪里寻找)。确实学到了一些东西。肯定有一些东西需要尽快修复。
遗憾的是,几乎没有哪个插件拥有如此精细且安全的代码。但我希望这种情况会改变!——当我看到“有效代码”或“代码编写良好”时,大多数插件都完全不安全!
就在几周前看看
http://blog.sucuri.net/2014/09/slider-revolution-plugin-critical-vulnerability-being-exploited.html
感谢你的精彩文章!
如果使用htmlspecialchars()会怎样?这是否仍然存在安全漏洞?
在底层,
esc_attr
等使用了htmlspecialchars
。我看到的最大区别是,如果设置了PHP标志,htmlspecialchars
可能会跳过转义引号https://php.ac.cn/htmlspecialchars
有一个错误:
esc_html_e
已经回显了,所以echo esc_html_e
会进行双重回显。在将PHP变量传递给JS的
json_encode()
示例中,“WordPress方式”将是使用wp_localize_script()
代替。一个用于转义可能包含HTML内容的便捷函数是
wp_kses_post()
,它是wp_kses()
函数的快捷方式,并白名单常见HTML标签。更多信息,请查看
wp-includes/formatting.php
感谢你的更正!我太兴奋了,用了echo。
如果我不理解,请见谅,我不是一个后端开发者,而且我很少使用wordpress。我的问题是如何才能将恶意代码放入自定义输入字段?他们难道不需要访问你的仪表盘,这意味着你已经某种程度上被黑了?
如果你是一个前端开发人员,除非你的访客经常登录或拥有除了网站只读权限以外的其他权限,否则XSS在这里不是一个大问题。但请记住,即使XSS没有破坏性,也可能很烦人。黑客不必非要窃取登录详细信息来获得乐趣,在网站被篡改后清理网站并不有趣。
大多数黑客攻击不会直接访问你的仪表盘,而是利用主题和插件中的漏洞。(盗贼可能不会从后门进入,而是注意到地下室里一个容易打开的窗户。)
WP 通过钩子和过滤器具有很强的扩展性,但如果某些内容编写不当,这种强大的功能也可能使你面临安全问题。即使你自己的代码是安全的,生态系统中的其他插件可能不是,你需要小心谨慎。
许多漏洞并非来自有问题的插件本身,而是利用了其他插件的漏洞。(上面提到的幻灯片插件就是一个非常严重的错误的例子。)
Mark Jaquith 曾经做过一个关于这个主题的WordCamp 演讲,可以进一步阅读。