插件开发文档

国际化安全

💡 云策文档标注

概述

本文档讨论了在 WordPress 国际化过程中常被忽视的安全问题,强调了对翻译内容进行安全检查的重要性,包括防范恶意字符串、转义输出和使用占位符等关键措施。

关键要点

  • 检查翻译内容中的垃圾或恶意字符串,可使用 Google Translate 回译进行对比验证。
  • 转义国际化字符串,避免恶意代码注入,例如使用 esc_html_e() 替代 _e()。
  • 在字符串中使用占位符(如 printf() 或 sprintf())替代直接嵌入 URL,防止恶意翻译者篡改链接。
  • 自行编译 .mo 二进制文件,避免使用翻译者提供的 .mo 文件,以确保其基于正确的 .po 文件生成。

代码示例

// 不安全示例
_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' );

// 安全示例
esc_html_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' );

// 不安全示例
_e(
    'Please <a href="https://login.wordpress.org/register"> register for a WordPress.org account</a>.',
    'your-text-domain'
);

// 安全示例
printf(
    esc_html__( 'Please %1$s register for a WordPress.org account %2$s.', 'your-text-domain' ),
    '<a href="https://login.wordpress.org/register">',
    '</a>'
);

注意事项

  • 可依赖翻译验证机制(如 WordPress Polyglots 团队的编辑角色)来增强安全性,但转义仍是基础防护。
  • 使用命令行工具(如 msgfmt)编译 .mo 文件,而非依赖 PoEdit,以避免覆盖 .po 文件头信息。

📄 原文内容

Security is often overlooked when talking about internationalization, but there are a few important things to keep in mind.

Check for Spam and Other Malicious Strings

When a translator submits a localization to you, always check to make sure they didn’t include spam or other malicious words in their translation. You can use Google Translate to translate their translation back into your native language so that you can easily compare the original and translated strings.

Escape Internationalized Strings

You can’t trust that a translator will only add benign text to their localization; if they want to, they could add malicious JavaScript or other code instead. To protect against that, it’s important to treat internationalized strings like you would any other untrusted input.

If you’re outputting the strings, then they should be escaped.

Insecure:

_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' ); 

Secure:

esc_html_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' );

Alternatively, some people choose to rely on a translation verification mechanism, rather than adding escaping to their code. One example of a verification mechanism is the editor roles that the WordPress Polyglots team uses for translate.wordpress.org. This ensures that any translation submitted by an untrusted contributor has been verified by a trusted editor before being accepted.

Use Placeholders for URLs

Don’t include URLs in internationalized strings, because a malicious translator could change them to point to a different URL. Instead, use placeholders for printf() or sprintf().

Insecure:

_e(
	'Please <a href="https://login.wordpress.org/register"> register for a WordPress.org account</a>.',
	'your-text-domain'
);

Secure:

printf(
	esc_html__( 'Please %1$s register for a WordPress.org account %2$s.', 'your-text-domain' ),
	'<a href="https://login.wordpress.org/register">',
	'</a>'
);

Compile Your Own .mo Binaries

Often translators will send the compiled .mo file along with the plaintext .po file, but you should discard their .mo file and compile your own, because you have no way of knowing whether or not it was compiled from the corresponding .po file, or a different one. If it was compiled against a different one, then it could contain spam and other malicious strings without your knowledge.

Using PoEdit to generate the binary will override the headers in the .po file, so instead it’s better to compile it from the command line:

msgfmt -cv -o /path/to/output.mo /path/to/input.po