人工制作 / whitelist-html
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
至少与其他转义函数在同一数量级。
使用此库
使用此库的步骤有两个
- 将此库作为git子模块添加。
- 在使用之前加载
clean-html.php
。我们建议在mu-plugins
中加载,但你也可以通过wp-config.php
加载它,如果你希望它更早加载。
完成。开始使用该函数。