外觀
佈景主題
來源:佈景主題架構
需要注意
共 25 項 — 8 高 / 9 中 / 8 低
XSS:使用者個資未跳脫直接輸出到 JavaScript
- 位置:
footer.php:185-189 - 說明: <?=
$memberId?>, <?=$memberEmail?>, <?=$memberPhone?>, <?=$memberName?> 使用 PHP 短標籤直接輸出到 JavaScript 字串中,未經esc_js()處理。如果使用者名稱含有引號或特殊字元,可能破壞 JS 結構或注入惡意程式碼。 - 建議調整: 所有輸出到 JS 的 PHP 變數必須使用
esc_js()或wp_json_encode()跳脫 - 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
XSS:商品資料未跳脫直接輸出到 JavaScript
- 位置:
footer.php:219-221 - 說明: <?=
$product_name?>, <?=$product_categories?>, <?=$product_price?> 直接輸出到 JS。商品名稱若含引號(如 8" 等)會破壞 JavaScript 語法或造成 XSS。 - 建議調整: 使用
esc_js()跳脫,或改用 wp_localize_script 傳遞資料 - 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
XSS:affiliates_trank 函數 order_total 未跳脫
- 位置:
functions.php:142-146 - 說明:
$order_total直接拼接到 JavaScript 字串中($trank_code.= ...$order_total...)。雖然 order_total 通常是數字,但未做型別檢查或跳脫。 - 建議調整: 使用 esc_js(
$order_total) 跳脫輸出 - 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
XSS:Facebook 驗證碼未使用 esc_attr 輸出
- 位置:
functions.php:846 - 說明:
$fb_verification_str直接插入 meta tag content 屬性,未使用esc_attr()。雖然經過 strip_tags 和 preg_replace,但這不是完整的 XSS 防禦。 - 建議調整: 改為 echo "<meta name='facebook-domain-verification' content='" . esc_attr(
$fb_verification_str) . "' />"; - 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
歡迎郵件使用 Cloudways staging URL
- 位置:
ultimate-member/email/welcome_email.php:13 - 說明: 郵件中的商品連結指向 woocommerce-1571150-6121372.cloudwaysapps.com 而非正式網域 letsharu.com。新註冊會員收到的歡迎信連結指向錯誤的網址。
- 建議調整: 將 URL 改為 https://letsharu.com/product/
- 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
允許匯出外掛執行任意 PHP 程式碼
- 位置:
functions.php:1405 - 說明: woe_user_can_add_custom_php 過濾器回傳 __return_true,允許在 Advanced Order Export 外掛中執行自訂 PHP 程式碼。若 admin 帳號被入侵,攻擊者可直接在伺服器上執行任意程式碼。
- 建議調整: 評估是否真的需要此功能。如需保留,應限制僅特定角色可使用,並加入稽核日誌
- 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
第三方 CDN 資源未使用 SRI(Subresource Integrity)
- 位置:
functions.php:755-756 - 說明: jquery-confirm 3.3.2 的 CSS 和 JS 從 cdnjs.cloudflare.com 載入,未加 integrity 屬性。若 CDN 被入侵可注入惡意程式碼到所有結帳頁面。
- 建議調整: 加入 integrity 和 crossorigin 屬性,或將資源下載到本地
- 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
GPT AJAX 未登入可呼叫且無速率限制(成本/資源濫用)
- 位置:
functions.php:1616-1617 - 說明: wp_ajax_nopriv_gpt_handle_request 允許未登入使用者無限呼叫 OpenAI API,無 nonce、無 rate limit、無 IP 節流,任何人可燒 API 配額
- 建議調整: 若 GPT 功能已停用,移除 AJAX handler 註冊。若需保留,加入 nonce 傳送和速率限制
- 影響等級: 高
- 驗收: 修改完成後重跑掃描,該項目不再出現
生產環境殘留大量 console.log(含 emoji)
- 位置:
functions.php:497-677 + 1835-2171 - 說明: 結帳相關的 inline JavaScript 中有超過 60 個 console.log 語句,包含 emoji 圖示(如 console.log('🔍 地址欄位判斷...'))。內部邏輯可透過瀏覽器開發者工具檢視,並略微影響效能。
- 建議調整: 移除所有生產環境的 console.log,或改為可開關的 debug 模式
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
300+ 行父主題函數完整覆寫僅為加入 5 行程式碼
- 位置:
functions.php:866-1164 - 說明: woodmart_page_title 函數複製了約 300 行父主題程式碼,僅為了在 line 989-993 加入
bcn_display()麵包屑。父主題更新時此覆寫不會同步,可能造成功能缺失或顯示異常。 - 建議調整: 改用 woodmart_after_header action hook 或其他 filter 注入麵包屑,移除完整函數覆寫
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
訂單狀態判斷依賴訂單備註文字比對
- 位置:
functions.php:151-277 - 說明: newebpay_cvscom_fix_status 和 newebpay_cvscom_manual_update 用 strpos 比對訂單備註中的「藍新金流交易序號」和「付款時間」文字來判斷是否已付款。如果藍新外掛更新備註格式(如改用英文或不同措辭),超商取貨付款流程可能不再正確運作。
- 建議調整: 改為檢查訂單 meta data(如 _nwpPayTime)而非備註文字內容
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
硬編碼 email 地址和使用過時的 WooCommerce API
- 位置:
functions.php:1308-1357 - 說明: check_linepay_success_handler 中硬編碼了 4 個 email 地址,使用 get_post_meta 而非
$order->get_meta()(不相容 HPOS),使用 newWC_Order()而非wc_get_order()。 - 建議調整: email 改為 WordPress option 或環境變數。改用
wc_get_order()和$order->get_meta()以相容 HPOS - 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
WooCommerce 範本版本極舊(1.6.4)
- 位置:
woocommerce/single-product.php - 說明: single-product.php 標記為 @version 1.6.4,這是非常舊的版本。WooCommerce 可能在後續版本中修改了此範本的結構,導致覆寫的範本無法正確運作。
- 建議調整: 對照當前 WooCommerce 版本的範本結構更新此檔案
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
未經 sanitize 的 $_POST 資料直接用於比較
- 位置:
functions.php:709-733 - 說明: wps_select_checkout_field_process 中
$_POST['billing_state']和$_POST['billing_city']未經 sanitize_text_field 處理直接用於字串比較。雖然 WooCommerce 的 checkout 流程有內建保護,但最佳實踐是先 sanitize。 - 建議調整: 對所有
$_POST值使用sanitize_text_field()後再比較 - 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
未經 sanitize 的 $_SERVER['REQUEST_URI']
- 位置:
functions.php:1293 - 說明: setNoindexIfEn 函數直接讀取
$_SERVER['REQUEST_URI']用於 str_contains 比較。雖然只用於比較不用於輸出,風險較低,但仍不符合最佳實踐。 - 建議調整: 使用 esc_url_raw(
$_SERVER['REQUEST_URI']) 或wp_parse_url() - 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
viewport meta 禁止使用者縮放
- 位置:
header.php:9 - 說明: user-scalable=no, maximum-scale=1.0 阻止使用者縮放頁面,違反 WCAG 2.1 無障礙標準(Success Criterion 1.4.4)。低視力使用者需要放大頁面才能閱讀。
- 建議調整: 移除 maximum-scale=1.0 和 user-scalable=no
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
使用 HPOS 不相容的訂單列表 hook
- 位置:
functions.php:280-327 - 說明: manage_shop_order_posts_custom_column hook 在 WooCommerce HPOS(High-Performance Order Storage)模式下不會觸發。如果啟用 HPOS,後台訂單列表的「需出貨」欄位將不再顯示。
- 建議調整: 增加 manage_woocommerce_page_wc-orders_custom_column hook 以相容 HPOS
- 影響等級: 中
- 驗收: 修改完成後重跑掃描,該項目不再出現
備份檔案留在可存取的目錄中
- 位置:
260119_functions.php + _style.css + js/241129_main.js + js/241129_main.min.js - 說明: 4 個備份檔案留在主題目錄中。PHP 備份檔如果可直接存取(web server 未阻擋),可能洩漏程式碼邏輯和內部資訊。
- 建議調整: 將備份檔案移出 web 可存取目錄,或移到版本控制系統中管理
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
大量硬編碼的運送方式 ID 和地區名稱
- 位置:
functions.php:62-86 + 707-733 - 說明: flat_rate:4, flat_rate:6, flat_rate:16, newebpay_cvscom 等 ID 硬編碼在多處。台北市各行政區名稱也硬編碼。任何後台運送方式設定變更都需要同步修改程式碼。
- 建議調整: 將可配置的值抽出為 WordPress option 或常數
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
多組追蹤碼 ID 硬編碼
- 位置:
functions.php:90-149 + 792-858 - 說明: GA4 ID (G-Z5C8WK0J0F)、GTM ID (GTM-PC8K325)、LINE Tag ID (7873c94a-...)、Tagtoo ID (1973)、Omnichat appkey 等全部硬編碼。更換服務商或更新 ID 需修改程式碼。
- 建議調整: 集中管理於 WordPress option 或自訂設定頁面
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
error_log 留在生產環境
- 位置:
functions.php:1355 - 說明: check_linepay_success_handler 和其他多處使用 error_log 記錄偵錯訊息到伺服器日誌,部分含 print_r 輸出。
- 建議調整: 移除偵錯用的 error_log,或改為 WooCommerce Logger (
wc_get_logger()) - 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
WooCommerce email 範本版本可能過舊
- 位置:
woocommerce/emails/*.php - 說明: 所有 email 範本基於 WooCommerce 3.7.0。如果站台使用更新的 WooCommerce,可能顯示「範本已過期」警告或功能異常。
- 建議調整: 在 WooCommerce > Status > Templates 檢查是否有過期範本警告,並與最新版本對照更新
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
未使用的程式碼:已停用的自動取消訂單功能
- 位置:
functions.php:1167-1232 - 說明: ctk_order_stay_too_long_daily_cron 和 ctk_check_order_stay_too_long 函數的排程已註解,但函數定義仍存在。增加維護複雜度。
- 建議調整: 若確定不再使用,移除整段程式碼並加入 git commit 說明
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
GPT AJAX 呼叫缺少 nonce 參數
- 位置:
js/main.js:160-166 - 說明: main.js 的 GPT 按鈕點擊事件呼叫 AJAX 時未傳送 nonce 參數,但 functions.php 的 handler 會用 check_ajax_referer 驗證。這會導致 AJAX 請求直接被拒絕。
- 建議調整: 在 AJAX 呼叫中加入 nonce: gpt_ajax.nonce 參數
- 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
學生折價券前綴檢查過於寬鬆
- 位置:
functions.php:1446 - 說明: strpos(
$coupon_code, 'st-') !== false 會匹配任何包含 'st-' 的折價券(如 'best-deal', 'fast-shipping'),不僅僅是以 'st-' 開頭的。 - 建議調整: 改為 strpos(
$coupon_code, 'st-') === 0 確保僅匹配前綴 - 影響等級: 低
- 驗收: 修改完成後重跑掃描,該項目不再出現
驗收
修改完成後重跑佈景主題掃描,所有高/中風險項目清除。
