fix: NinjaFirewall 相容性 — 保護 WAF 設定選項不被重導向
評估 NinjaFirewall (WP Edition) 4.9 的相容性,結論是兩者可共存且
不需要開發 AddOn(該外掛全 codebase 零個 apply_filters('nfw_*') /
do_action('nfw_*'),官方相容手段全在部署層)。但核心有一個隱患必須補。
TMDO_Options_Manager::register_settings_group() 以 pre_update_option_{key}
回傳 $old_value,讓選項不再落地 wp_options、改存專屬設定表。而
NinjaFirewall 的 Full WAF 走 auto_prepend_file,在 WordPress 載入前就以
原生 mysqli 直查 wp_options 取 nfw_options / nfw_rules。一旦這些鍵被
重導向,WAF 會讀不到設定而靜默停止防護 —— 不報錯、不寫 log。
nfw_rules 約 77KB 且 autoload=auto,正是 autoload 瘦身最誘人的目標,
因此這條路徑並非理論風險。
Added
- PROTECTED_OPTIONS 常數與註冊守衛(nfw_options / nfw_rules / nfw_checked),
命中時發出 _doing_it_wrong()。守衛置於方法開頭,全部鍵都被擋時提前返回,
不再建立空的設定表。
- tests/unit/OptionsManagerProtectedTest.php(4 tests / 10 assertions),
鎖住「受保護鍵絕不會被掛上 pre_option_* / pre_update_option_* 攔截」。
- docs/WAF-COMPATIBILITY.md:模式差異、symlink 多租戶部署、WP SaaS 開站
流程與驗證清單、三條開發約束、實測風險矩陣。
Changed
- Migration Wizard 輪詢 500ms → 2s,與四個 stress-test 面板一致。
原本 2 req/s 打同一 REST endpoint,易觸發 WAF rate-limit 與 bot 偵測。
autoload 最佳化不受影響:optimize_autoload() 只改 autoload 欄位、不刪列,
而 Full WAF 的 SELECT * 不看 autoload。
驗證:591 tests / 1166 assertions 通過,PHPCS 零違規,版本一致性 1.0.2。
dev30 於 Full WAF 與 WP WAF 兩種模式下實測,firewall log 中 TMDO 相關
攔截 0 筆。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdjXAU473eekjPBB8vPVRS
This commit is contained in:
@@ -46,6 +46,22 @@ final class TMDO_Options_Manager {
|
||||
'wpb_backup_options',
|
||||
);
|
||||
|
||||
/**
|
||||
* 禁止重導向的選項名稱清單
|
||||
*
|
||||
* 這些選項會被「WordPress 載入之前」執行的元件以原生 SQL 直查 wp_options
|
||||
* (NinjaFirewall Full WAF 走 auto_prepend_file,以 mysqli 讀取 nfw_options
|
||||
* 與 nfw_rules)。一旦被 register_settings_group() 重導向至專屬設定表,
|
||||
* 該元件會讀不到設定而靜默停止運作 —— 不報錯、不寫 log。
|
||||
*
|
||||
* 註:autoload 最佳化不受此限,因為那些元件的 SELECT 不看 autoload 欄位。
|
||||
*/
|
||||
private const PROTECTED_OPTIONS = array(
|
||||
'nfw_options',
|
||||
'nfw_rules',
|
||||
'nfw_checked',
|
||||
);
|
||||
|
||||
/** autoload 合計閾值(MB),超過則警告 */
|
||||
private const AUTOLOAD_WARNING_THRESHOLD_MB = 1;
|
||||
|
||||
@@ -202,6 +218,22 @@ final class TMDO_Options_Manager {
|
||||
public static function register_settings_group( string $group_name, array $option_keys ): void {
|
||||
global $wpdb;
|
||||
|
||||
// 受保護的選項不得重導向,否則會讓 WordPress 載入前讀取它的元件靜默失效
|
||||
foreach ( array_intersect( $option_keys, self::PROTECTED_OPTIONS ) as $protected_key ) {
|
||||
_doing_it_wrong(
|
||||
__METHOD__,
|
||||
esc_html( "選項 {$protected_key} 由 WordPress 載入前的元件以原生 SQL 直讀 wp_options,重導向會使其靜默失效,已略過。" ),
|
||||
'1.0.2'
|
||||
);
|
||||
}
|
||||
|
||||
$option_keys = array_diff( $option_keys, self::PROTECTED_OPTIONS );
|
||||
|
||||
// 全部都被擋下就不必建表
|
||||
if ( empty( $option_keys ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = $wpdb->prefix . TMDO_TABLE_PREFIX . 'settings_' . sanitize_key( $group_name );
|
||||
|
||||
// 建立設定專屬表
|
||||
|
||||
Reference in New Issue
Block a user