人工制作/whitelist-html

此软件包已被废弃,不再维护。作者建议使用humanmade/clean-html软件包代替。

WordPress的安全HTML。添加esc_*()-样函数以允许某些HTML。

1.0.0 2020-01-28 11:10 UTC

This package is auto-updated.

Last update: 2020-06-09 13:18:25 UTC


README

当需要允许某些HTML时,引入一个类似于esc_*()的函数。

理由

背景

在处理任何类型的数据时,最佳实践是尽可能晚地转义输出。值通常不知道它们将被用于何处,因此您需要根据您输出的上下文进行转义。这些包括用于HTML属性值的esc_attr()、用于HTML中的文本的esc_html()等。

即使值能知道它们的输出上下文,如果转义不当,用户仍然可以构建恶意的输出。因此,您需要在输入上进行清理(以确保您的值是正确的),以及输出上进行转义(以确保值正确地输出了到上下文中)。

目前,在每一个WordPress网站上,都有一个明显的转义漏洞,因此也存在安全漏洞。

在翻译WordPress字符串时,最常用的函数是__()(翻译并返回)或_e()(翻译并输出)。在可能的情况下,这些也需要转义,以确保翻译不会意外地破坏您的输出。因此,提供了如esc_html_e()esc_attr_e()等便利函数。

然而,当您需要在翻译中包含HTML时,这就会失效。翻译最佳实践表明,在翻译字符串时,应尽可能包含尽可能多的信息。这意味着在字符串中包含HTML标签,以便翻译者可以理解句子是如何形成的。

可以通过占位符进行“聪明的”黑客攻击来解决这个问题,例如

$text = sprintf(
	esc_html__( 'This is some text %1$swith a link%2$s'),
	'<a href="http://example.com/">',
	'</a>'
);

但请注意,这对翻译者来说更难理解,因为他们不能直观地了解情况,除非检查代码。即使有翻译者注释,仍然更难理解。还有没有保证这是安全的。你可以交换占位符,或者省略部分。最佳实践指出,我们应该做的是以下内容

$text = sprintf(
	esc_html__( 'This is some text <a href="%1$s">with a link</a>'),
	'http://example.com/'
);

目前,政策基本上是 treating translated strings with HTML as trusted. 这不仅将负担转移到了GlotPress的翻译验证器,而且还意味着您不再控制输出。这是一个等待被利用的攻击向量。

我们如何解决这个问题?

WordPress包含专门设计来帮助解决这个问题功能的函数。毕竟,人们可以提交包含HTML的评论或帖子,但WP可以很好地处理这个问题。WordPress通过一个名为kses的库来处理这个问题,它将HTML清理为一个小型、安全的HTML子集。帖子可以包含比评论更多的HTML标签,因为它们通常是半受信任的用户。

kses很棒,但通常不用于大型HTML块之外,如帖子或评论内容。原因通常被表述为性能。众所周知,kses很慢,因为它必须基本上分解HTML,然后用允许的标签重建它。

然而,Zack Tollman写了一篇精彩的帖子,对kses性能的这种公认知识提出了质疑。Zack的研究表明,虽然kses在处理较长的内容(如文章内容)时性能较差,但它在处理短字符串时实际上与其他转义功能相当接近。当将允许的元素从默认值减少到仅需要的元素时,这一点更为明显。

clean_html

这个库提供了一种简单、高效的方法来对翻译后的字符串进行清理。它不需要你处理kses的内部结构,更接近于esc_html等函数。

如果安全措施无法使用,那么它就没有用处。大多数情况下,clean_html可以像开发者使用其他转义函数一样使用。

下面是一个快速示例,演示其易用性

<!-- Previously -->
<p><?php _e( 'This is a terrific use of <code>WP_Error</code>.' ) ?></p>

<!-- Secure version -->
<p><?php print_clean_html( __( 'This is a terrific use of <code>WP_Error</code>.' ), 'code' ) ?></p>

即使恶意翻译者将其更改为包含指向垃圾邮件网站的链接(或者更糟),这也将被clean_html捕获并删除。

以我们上面的原始示例为例,我们可以修改它,只允许a标签

$text = clean_html(
	sprintf(
		__( 'This is some text <a href="%1$s">with a link</a>'),
		'http://example.com/'
	),
	'a'
);

就这么简单。你也可以使用多个元素,使用逗号分隔的字符串或元素列表

$text = clean_html(
	sprintf(
		__( 'This is <code>some</code> text <a href="%1$s">with a link</a>'),
		'http://example.com/'
	),
	'a, code' // or array( 'a', 'code' )
);

如果你需要自定义属性,可以使用kses风格的属性指定符。这些也可以混合使用

$text = clean_html(
	sprintf(
		__( 'This is <span class="x">some</span> text <a href="%1$s">with a link</a>'),
		'http://example.com/'
	),
	array(
		'a',
		'span' => array(
			'class' => true,
		),
	)
);

性能测试

在一个快速测试中,字符串'hello with a <a href="wak://example.com">malicious extra link!<///q><o>b'被分别用clean_html(仅使用a)和esc_html进行了10,000次迭代。虽然这两个函数执行的任务不同,但它们都是转义函数,所以比较性能有助于了解是否可以将这种方法用于生产代码。

在一个非科学的试验中,这给出了clean_html为0.96秒和esc_html为1.07秒的结果,每个都进行了10,000次试验。这表明clean_html至少与其他转义函数在同一数量级。

使用此库

使用此库的步骤有两个

  1. 将此库作为git子模块添加。
  2. 在使用之前加载clean-html.php。我们建议在mu-plugins中加载,但你也可以通过wp-config.php加载它,如果你希望它更早加载。

完成。开始使用该函数。