不受信任的数据来自许多来源(用户、第三方网站,甚至您自己的数据库!),所有数据在使用前都需要进行检查。请记住:即使管理员也是用户,用户也难免会故意或无意地输入错误数据。保护用户免受自身数据侵害是您的责任。
验证输入是根据预定义的模式(或多个模式)测试数据的过程,并得出明确的结果:有效或无效。与清理相比,验证是一种更具体的方法,但两者都有各自的作用。
简单验证示例:
检查必填字段是否留空
检查输入的电话号码是否仅包含数字和标点符号
检查请求的字符串是否是五个有效选项之一
检查数量字段是否大于 0
数据验证应尽早进行。这意味着在执行任何操作之前验证数据。
关于如何进行验证,存在几种不同的理念。每种理念都适用于不同的场景。
仅接受来自已知和可信值的有限列表的数据。
将不受信任的数据与安全列表进行比较时,务必确保使用严格的类型检查。否则,攻击者可以精心设计输入,使其能够通过安全列表,但仍能产生恶意影响。
$untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons if ( 1 === $untrusted_input ) { // == would have evaluated to true, but === evaluates to false echo '<p>Valid data'; } else { wp_die( 'Invalid data' ); }
$untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons $safe_values = array( 1, 5, 7 ); if ( in_array( $untrusted_input, $safe_values, true ) ) { // `true` enables strict type checking echo '<p>Valid data'; } else { wp_die( 'Invalid data' ); }
$untrusted_input = '1 malicious string'; // will evaluate to integer 1 during loose comparisons switch ( true ) { case 1 === $untrusted_input: // do your own strict comparison instead of relying on switch()'s loose comparison echo '<p>Valid data'; break; default: wp_die( 'Invalid data' ); }
拒绝来自已知不可信值的有限列表中的数据。这很少是一个好主意。
测试数据格式是否正确。只有格式正确才接受。
if ( ! ctype_alnum( $data ) ) { wp_die( "Invalid format" ); } if ( preg_match( "/[^0-9.-]/", $data ) ) { wp_die( "Invalid format" ); }
接受大多数数据,但删除或更改危险部分。
$trusted_integer = (int) $untrusted_integer; $trusted_alpha = preg_replace( '/[^a-z]/i', "", $untrusted_alpha ); $trusted_slug = sanitize_title( $untrusted_slug );
假设我们有一个输入字段用于接受美国邮政编码:
<input type="text" id="wporg_zip_code" name="my-zipcode" maxlength="10" />
这里我们告诉浏览器最多只允许输入十个字符……但对于输入的字符没有限制。他们可以输入11221或eval()。
这就是验证的作用所在。处理表单时,我们编写代码来检查每个字段的数据类型是否正确,如果不正确,则将其丢弃。
例如:要检查my-zipcode字段,我们可能会执行以下操作:
/** * Validate a US zip code. * * @param string $zip_code RAW zip code to check. * * @return bool true if valid, false otherwise. */ function wporg_is_valid_us_zip_code( string $zip_code ):bool { // Scenario 1: empty. if ( empty( $zip_code ) ) { return false; } // Scenario 2: more than 10 characters. // The `maxlength` attribute is only enforced by // the browser, so we still need to validate the // length of the input on the server to protect // against a manual submission. if ( 10 < strlen( trim( $zip_code ) ) ) { return false; } // Scenario 3: incorrect format. if ( ! preg_match( '/^d{5}(-?d{4})?$/', $zip_code ) ) { return false; } // Passed successfully. return true; }
然后,在处理表单时,您的代码应该检查wporg_zip_code字段并根据结果执行操作:
if ( isset( $_POST['wporg_zip_code'] ) && wporg_is_valid_us_zip_code( $_POST['wporg_zip_code'] ) ) { // $_POST['wporg_zip_code'] is valid; carry on }
请注意,此特定示例检查的是所提供的数据格式是否正确,而不是检查所提供的格式正确的数据是否为有效的邮政编码。为此,您需要第二个函数来与有效的邮政编码列表进行比较。
假设您的代码将查询数据库中的帖子,并且您希望允许用户对查询结果进行排序。
$allowed_keys = array( 'author', 'post_author', 'date', 'post_date' ); $orderby = sanitize_key( $_POST['orderby'] ); if ( in_array( $orderby, $allowed_keys, true ) ) { // $orderby is valid; carry on }
此示例代码通过将传入的排序键(存储在orderby 输入参数中)与允许的排序键数组进行比较来检查其有效性。这可以防止用户传入任意且潜在的恶意数据。
在将传入的排序键与数组进行校验之前,该键会被传入 WordPress 内置函数 sanitize_key()
。该函数会确保(除其他事项外)键为小写,这正是我们想要的,因为in_array()
搜索时会区分大小写。
传入true第三个参数 in_array()
可以启用严格类型检查,这告诉函数不仅要比较值,还要比较值类型。这使得代码可以确定传入的排序键是字符串,而不是其他数据类型。
大多数验证都是在自定义代码中完成的,但也有一些辅助函数。这些函数是“净化”页面上列出的函数的补充。
balanceTags( $html )
或者force_balance_tags( $html )
– 尝试确保 HTML 标签平衡,以便输出有效的 XML。
count()
用于检查数组中有多少个项目
in_array()
用于检查数组中是否存在某个对象
is_email()
将验证电子邮件地址是否有效。
is_array()
用于检查某个东西是否是数组
mb_strlen()
或者strlen()
检查字符串是否具有预期的字符数
preg_match()
,strpos()
用于检查某些字符串是否出现在其他字符串中
sanitize_html_class( $class, $fallback )
– 清理 HTML 类名,确保其仅包含有效字符。将字符串精简为 AZ、az、0-9、'-'
,如果结果为空字符串,则返回提供的替代值。
tag_escape( $html_tag_name )
– 清理 HTML 标签名称(无论函数名称如何,都不会转义任何内容)。
term_exists()
检查标签、类别或其他分类术语是否存在。
username_exists()
检查用户名是否存在。
validate_file()
将验证输入的文件路径是否为真实路径(但不是文件是否存在)。
请查看WordPress 代码参考,了解更多类似的函数。搜索名称类似的函数:*_exists()
、*_validate()
和 is_*()
。并非所有这些函数都是验证函数,但很多都很有帮助。
在 WordPress 插件开发中,安全验证数据主要涉及数据验证、管理员身份验证以及双因素身份验证 (2FA) 等安全机制。以下是详细说明:
数据验证是确保插件安全的关键步骤。它检查用户或外部来源输入的数据,以确保其有效性和安全性。在 WordPress 插件开发中,数据验证可以通过以下方式实现:
使用内置 PHP 函数:isset()、empty()、mb_strlen()、strlen()、preg_match()、strpos()、count() 和 in_array() 等函数可用于执行基本数据验证。
利用 WordPress 核心函数:WordPress 提供了许多实用的数据验证函数,例如用于验证电子邮件地址的 is_email()、用于检查标签或类别是否存在的 term_exists() 以及用于验证用户名的 username_exists()。
自定义验证函数:开发人员可以根据特定的数据验证需求编写自己的 PHP 和 JavaScript 函数。这些函数应根据数据是否有效返回布尔值(true 或 false)。
验证管理员身份对于防止未经授权访问敏感插件功能至关重要。在 WordPress 插件开发中,管理员身份验证可以通过以下方法实现:
用户名和密码验证:最基本的方法,要求管理员输入用户名和密码来验证其身份。
双因素身份验证 (2FA):这通过要求管理员除了用户名和密码之外,还提供第二个验证因素(例如移动验证码、指纹识别或硬件密钥)来提供额外的安全保障。许多 WordPress 插件(例如 Two-Factor、WP 2FA 和 miniOrange 2-Factor Authentication)都支持 2FA。
IP 地址过滤:可以将插件配置为仅允许来自特定 IP 地址范围的访问,从而降低潜在的安全风险。
除了数据验证和管理员身份验证之外,WordPress 插件还可以实现各种安全机制来增强安全性:
JSON Web Token (JWT) 身份验证:对于与 WordPress REST API 交互的插件,可以使用 JWT 身份验证来提供安全高效的用户身份验证方式。WP REST API 插件的 JWT 身份验证就是一个示例,它介绍了如何利用 JWT 身份验证机制来增强 API 安全性。
安全标头:插件可以设置各种安全标头,例如 Content-Security-Policy、X-Content-Type-Options 和 X-Frame-Options,以增强网站安全性。
输入和输出清理:插件应清理所有用户输入和输出,以防止跨站点脚本 (XSS) 攻击和其他安全漏洞。esc_html()、sanitize_text_field() 和 wp_kses() 等函数可用于此目的。
OTP 验证插件通过在注册、登录和提交联系表单时发送的 OTP(一次性密码)来验证用户的电子邮件 ID 和手机号码。这确保只有真实用户才能注册,同时防止虚假注册和重复账户。发生错误。
为此,您可以安装并激活“禁用管理员电子邮件验证通知”插件。激活后,转到 WordPress 信息中心的“设置”选项卡,然后点击“禁用电子邮件验证通知”。这将从您的管理界面中删除该提示。
Easy Basic Authentication 插件提供了一种简单的方法,可为您的 WordPress 网站添加基本身份验证。您可以通过设置自定义用户名和密码,为整个网站或仅为管理区域启用基本身份验证。通过仅限授权用户访问来保护您的网站安全。
扫描 WordPress 网站的源代码,检查是否存在恶意链接、重定向、iframe、JavaScript 或垃圾邮件,可以帮助您判断 WordPress 网站是否安全。使用 SiteCheck 运行网络安全检查,扫描特定 URL 中是否存在病毒或恶意软件。
WordPress 插件更新清单(手动或自动)
始终备份您的网站。
检查变更日志以了解重大变更。
等待主要插件更新几天(除非是安全修复)
在暂存环境中测试更改(Cloudways 使用 SafeUpdates 自动执行此操作)
使用回滚工具,例如 WP Rollback。