安全与风控
在 WordPress 插件/主题中处理用户输入与输出时…
当你在 WordPress 中处理表单、AJAX、数据库查询或输出动态内容时,按「输入净化、逻辑校验、输出转义」三层防御来编写安全代码。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 WordPress 插件/主题中处理通用
解决思路
- 遵循黄金法则:输入时净化(sanitize)、逻辑上校验(validate)、输出时转义(escape)。
- 处理表单时用 wp_nonce_field('action','name') 生成隐藏 nonce 字段,提交时用 wp_verify_nonce($_POST['name'],'action') 校验,失败则 wp_die。
- 生成删除/操作链接时用 wp_nonce_url($url,'action','nonce_param'),在处理器中用 wp_verify_nonce($_GET['nonce_param'],'action') 校验。
- AJAX 场景用 wp_create_nonce('action') 生成 nonce,通过 wp_localize_script 传给 JS,在处理器中用 check_ajax_referer('action','nonce') 校验,并用 wp_send_json_success/wp_send_json_error 返回。
- nonce 动作名要唯一(如 delete_post_$post_id),始终在 nonce 校验之外再做权限校验,不要复用同一 nonce 动作,不要对只读操作跳过校验。
- 净化输入:单行文本用 sanitize_text_field(),多行用 sanitize_textarea_field(),邮箱用 sanitize_email(),存储用 URL 用 esc_url_raw(),键名用 sanitize_key(),文件名用 sanitize_file_name(),正整数用 absint(),整数用 intval(),浮点用 floatval(),HTML 内容用 wp_kses_post() 或自定义 wp_kses(),纯文本用 wp_strip_all_tags()。
- 数组输入用 array_map 配合对应净化函数(如 array_map('sanitize_text_field', $_POST['tags']))。
- 注册设置时通过 register_setting 的 sanitize_callback 提供自定义净化回调,对 API key 用 preg_replace 限制字符、对复选框转 0/1、对颜色用 sanitize_hex_color、对下拉项用白名单。
- 校验业务逻辑:用 is_email()、is_numeric()、is_int()、is_array()、username_exists()、email_exists() 等内置函数,并检查长度、数值范围、必填项、正则格式。
- 多字段表单编写统一校验函数收集 $errors 数组,全部通过后再处理,否则逐条输出错误。
- 自定义校验:用 parse_url 校验域名白名单、用 DateTime::createFromFormat 校验日期、用 Luhn 算法校验信用卡号。
- 输出转义:HTML 内容用 esc_html(),HTML 属性用 esc_attr(),URL 用 esc_url(),JavaScript 字符串用 esc_js(),textarea 用 esc_textarea(),类名用 sanitize_html_class()。
- 国际化输出用 esc_html__()、esc_attr__(),含变量的翻译用 sprintf 并先转义变量,允许 HTML 的翻译用 wp_kses_post()。
- 避免双重转义、避免用错上下文函数(如 href 用 esc_html)、避免在 JS 中直接拼接未转义变量、避免在存储前转义(应存原始值、输出时转义)。
- 权限校验:用 is_user_logged_in() 确认登录,用 current_user_can('capability') 检查能力,对具体文章用 current_user_can('edit_post',$post_id) 等。
- 完整处理器顺序:检查登录 → 校验 nonce → 检查能力 → 净化输入 → 校验数据 → 处理/更新 → 安全重定向(wp_redirect + wp_get_referer)并 exit。
- 自定义权限用 add_role 注册角色并赋予自定义 capability,再用 current_user_can 检查。
- 防 SQL 注入:所有查询用 $wpdb->prepare() 配合 %s/%d/%f 占位符,写操作优先用 $wpdb->insert/update/delete 并传格式数组,表名用 $wpdb->prefix,禁止字符串拼接和已废弃的 esc_sql()。
- 文件上传:先校验 nonce,用 sanitize_file_name() 处理文件名,用白名单校验 MIME 类型,再用 wp_handle_upload() 处理并检查返回的 error。
- 防路径遍历:对 include 的模板名用白名单 in_array 校验,不要直接拼接用户输入。
- 按安全清单逐项自检:输入侧 nonce/能力/净化/校验/上传白名单,输出侧全部转义、URL 用 esc_url、JS 用 wp_localize_script,数据库侧全部 prepare,会话侧检查登录与角色,代码质量侧禁用 eval/extract、生产关闭 WP_DEBUG、不暴露 phpinfo/var_dump、安全相关 catch 不得为空(失败要关闭并记录)、对用户可控输入的 switch 必须有 fail-closed 的 default。
- 测试安全实现:验证 nonce 过期(等待 24 小时后提交应失败)、用外部表单测试 CSRF、输入 <script> 验证被转义、输入 1 OR 1=1 验证按字面处理、用低权限用户测试能力绕过,并用 WPScan、Sucuri、phpcs(WordPress-Extra/WordPress-VIP-Go)做自动化扫描。
适用边界 · 注意事项
- 非 WordPress 项目(如纯 PHP 框架、其他 CMS)不适用这些专用函数与钩子。
- 仅做静态展示、完全不接收用户输入也不输出动态数据的页面无需完整三层流程。
- 若已有成熟的安全框架或 ORM 统一处理输入输出,重复套用可能造成双重转义。