2026年10月27日 星期二

校網 PHP 緊急防護教學:CVE-2026-109618/109619 檢查、升級與限制登入來源

更新日期:2026-10-27|對象:學校網站管理員、委外維護廠商

本篇說明如何檢查 PHP 漏洞 CVE-2026-109618、CVE-2026-109619,安排修補、降低升級前暴露風險,並限制登入來源。範例僅使用文件專用位址 192.0.2.10、192.0.2.0/24 與 school.example.org,不代表任何學校的真實環境;實際操作前必須替換。

一、先了解:修補 PHP 才是完整處理方式

PHP 官方於 2026-10-21 公布兩個可能導致未經驗證遠端程式執行的重大漏洞。CVE-2026-109618 涉及記憶體不足時的資料處理;CVE-2026-109619 涉及跨請求殘留狀態。Apache mod_php 的已展示攻擊風險尤其高,PHP-FPM 也不能直接當成安全。

上游修補基準為各分支的 8.5.12、8.4.27、8.3.36、8.2.35。應採用所選分支當下最新的安全版本,或 Linux 發行商明確公告包含這兩案修補的回補套件。以下防護不是漏洞修補,也不能清除已存在的後門。

二、盤點:網站或主機是否使用 PHP?

WordPress、Drupal、Joomla、XOOPS 等系統通常使用 PHP。只看副檔名或 HTTP 標頭不足以判斷,應同時確認服務、設定、容器及網站程式。以下為 Linux 唯讀盤點範例:

cat /etc/os-release
command -v php
php -v
ps -eo user,pid,ppid,args | grep -E 'php-fpm|apache2|httpd|nginx'
systemctl list-units --type=service | grep -E 'php|nginx|apache|httpd'
sudo ss -lntp

# Ubuntu/Debian 套件
 dpkg-query -W 'php*' 2>/dev/null
# RHEL 系列另用:rpm -qa | grep -i php

# 根目錄請依實際環境修改;不輸出設定檔密碼
sudo find /var/www -type f -name 'wp-config.php' -print
sudo find /var/www -type f -name 'configuration.php' -print
sudo find /var/www -type f -name 'settings.php' -print
sudo find /var/www -type f -name 'mainfile.php' -print

# Nginx 設定可能含內部位址;僅在管理端查看,勿直接公開
sudo nginx -T 2>&1 | grep -E 'server_name|root |fastcgi_pass|PHP_VALUE|PHP_ADMIN_VALUE'
# Apache 可另查:sudo apachectl -M

若有 Docker、Podman、多個虛擬主機或不同 FPM pool,要逐一盤點。PHP CLI 與網站使用的 PHP 可能不同,不能只執行 php -v 就結案。依 Nginx 的 fastcgi_pass 或 Apache 模組設定,找到實際執行的版本;FPM 可使用對應的 php-fpm8.3 -i 檢查。不要在公開網站長期放置 phpinfo()。

三、確認版本與供應商回補

Ubuntu/Debian 可檢查已安裝與候選套件版本(版本名稱請依盤點替換):

dpkg-query -W php8.3-fpm php8.3-common php8.3-cli
apt-cache policy php8.3-fpm
zgrep -iE 'CVE-2026-109618|CVE-2026-109619' /usr/share/doc/php8.3*/changelog* 2>/dev/null

本機套件索引可能過期,changelog 沒找到編號也不是最終判定;須核對發行商對兩個 CVE 的公告及實際安裝版本。截至本文更新日,Ubuntu 公告列出的修補版本包括:Ubuntu 24.04 的 8.3.6-0ubuntu0.24.04.13、22.04 的 8.1.2-1ubuntu2.28,以及 18.04 的 7.2.24-0ubuntu0.18.04.17+esm14(需對應 Ubuntu Pro 服務)。版本看起來低於上游基準,不代表沒有回補;反之,僅有 ESM 字樣也不能證明已修補。

PHP 8.1 以前:PHP 專案已不提供例行維護。若供應商仍有支援且明確回補兩案,可作短期過渡;長期仍應遷移受支援版本。官方提供的部分舊分支來源回補不等同恢復完整維護,更不能跨版本亂套補丁。

四、最安全的升級順序

  1. 盤點 OS、Web 服務、PHP、擴充套件、CMS、外掛/模組、佈景及資料庫;確認管理主控台與 SSH 不會被鎖住。
  2. 建立 VM/磁碟快照,另存設定、網站、日誌與一致性資料庫備份,實際測試還原。不要只複製執行中的資料庫目錄。
  3. 在隔離測試站升級 CMS/模組與 PHP;舊站從 7.x 跨到 8.x,先查相容性,不能直接覆蓋正式站。
  4. 同分支供應商回補通常變動較小,但仍需檢查套件交易、測試及維護時段。過舊 OS 建議建立乾淨新主機再搬遷。
  5. 測試登入、權限、消息非同步載入、搜尋、分頁、圖片、中文附件、下載、郵件及排程。
  6. 切換後重啟真正承接網站請求的所有 PHP worker,再確認套件及 Web 實際版本,移除臨時探針。
  7. 若發現後門,先保存證據、隔離並從可信來源重建;單純升級 PHP 不等於完成除惡。

以下只示範 Ubuntu 24.04/PHP 8.3 同分支更新流程。先確認官方套件來源與所需擴充,再決定交易內容,不適合直接套用於其他版本:

sudo apt-get update
apt-cache policy php8.3-fpm php8.3-common
sudo apt-get -s install --only-upgrade php8.3-fpm php8.3-common php8.3-cli
# 檢閱模擬結果、完成備份與測試後才執行
sudo apt-get install --only-upgrade php8.3-fpm php8.3-common php8.3-cli
sudo php-fpm8.3 -t
sudo nginx -t
sudo systemctl restart php8.3-fpm
sudo systemctl reload nginx

上例不包含所有擴充套件。實際需將已安裝且受影響的 PHP 套件一併更新;Apache mod_php 或容器也要採用其對應重啟方式。

五、升級前怎麼保護?優先避免公開請求進入舊 PHP

最保守是由防火牆、反向代理或 Nginx 暫停對外動態服務,改由獨立靜態頁提供公告。CMS 內建關站若仍執行 PHP,或只有首頁顯示維護中,仍可能被直接呼叫其他 PHP 路徑繞過。不要一併停用必要 SSH/遠端管理通道。

若網站已停止更新,可規劃經審查的靜態封存。若仍保留 PHP 供閱讀,以下只是降低暴露風險。所有修改都先備份:

sudo cp -a /etc/nginx /root/nginx-backup-$(date +%Y%m%d-%H%M%S)
sudo cp -a /etc/php /root/php-backup-$(date +%Y%m%d-%H%M%S)

5-1 關閉不需要的 PHP 上傳

以下以 PHP 8.3 FPM 為例,先確認版本與路徑,勿直接改到錯誤的 CLI 設定。若 pool 有更高優先設定,也須一併確認。

sudo tee /etc/php/8.3/fpm/conf.d/99-school-protection.ini >/dev/null <<'EOF'
file_uploads = Off
session.upload_progress.enabled = Off
post_max_size = 1M
upload_max_filesize = 1M
display_errors = Off
expose_php = Off
EOF
sudo php-fpm8.3 -t && sudo systemctl restart php8.3-fpm

session.upload_progress.enabled 必須在請求解析前生效並重啟 worker,不能只靠程式內 ini_set()。官方另列 memory_limit=-1 的部分緩解,但可能增加記憶體耗盡風險,須配合資源隔離與專業評估,不建議直接盲目套用。

5-2 封鎖上傳目錄 PHP 與不需要的資料庫管理入口

以下放在實際網站的 server 區塊內,且在一般 PHP 正規表示式 location 前。已有相同 location 或 ^~ 規則時須合併檢查;上傳路徑也須依 CMS 調整。

# XOOPS 範例;WordPress 通常另有 /wp-content/uploads/
location ~* ^/uploads/.*[.](php[0-9]*|phtml|phar|inc)(/|$) {
    return 403;
}
location ~* ^/(pma|phpmyadmin|install|upgrade|setup)(/|[.]|$) {
    return 403;
}

不要直接封鎖所有含「點」的目錄,否則合法的 .thumbs 圖片或 .well-known 憑證路徑可能失效。封鎖上傳目錄 PHP 只阻止直接 HTTP 存取,不能阻止其他受害程式在主機內 include 後門。

5-3 純閱讀站可阻擋寫入方法,但先測試 AJAX

以下是「完全禁止登入/提交」模式,與下一節需要登入 POST 的模式不可直接同時使用。GET 也可能被舊模組拿來刪除資料,所以方法限制並不是資料庫唯讀保證。

# 放在網站 server 區塊
if ($request_method !~ ^(GET|HEAD)$) { return 405; }
if ($http_content_length !~ ^(0)?$) { return 413; }
if ($http_transfer_encoding != "") { return 413; }

若最新消息卡在「載入中」,先在瀏覽器 Network 查是否 POST 被擋。確認端點確實只讀、支援 GET 後,才將該 AJAX 改為 GET 並清除對應模板快取;不可將所有 $.post 全站取代,也不要為了修畫面全面重新開放 POST。搜尋、分類、分頁、下載須一起測試。

六、限制登入「來源網段」:一般訪客可讀,指定 IP 才能登入

這裡的限制是來源 IP/網段,不是校網網址或電子郵件網域。用 Referer、Host 或網址文字判斷登入來源並不可靠。示範 192.0.2.10/32 只代表單一文件用 IP;192.0.2.0/24 代表整個示範網段,實際優先採最小範圍。

以下是 Nginx+XOOPS 範例;WordPress 須改成 wp-login.php、wp-admin 等路徑,並評估 admin-ajax.php、REST、XML-RPC 的公開需求;Drupal、Joomla 也需依路由重寫與登入端點另訂規則。限制來源仍不能取代密碼、MFA、權限與修補。

6-1 建立來源與路徑判斷

先確認 /etc/nginx/conf.d/*.conf 是在 nginx.conf 的 http 區塊被 include。以下以新檔建立,若檔案已存在請先檢查,勿覆蓋其他設定。

sudo nano /etc/nginx/conf.d/school-login-access.conf
geo $school_allowed_ip {
    default 0;
    192.0.2.10/32 1;
    # 若確定需要整段,再改用:192.0.2.0/24 1;
}
map $uri $school_login_path {
    default 0;
    ~*^/user[.]php(/|$) 1;
    ~*^/admin([.]php|/|$) 1;
    ~*^/modules/[^/]+/admin([.]php|/|$) 1;
}
map "$school_allowed_ip:$school_login_path" $school_block_login {
    default 0;
    "0:1" 1;
}

6-2 在提供網站的 server 區塊加入

if ($school_block_login = 1) {
    return 403;
}

此方式在伺服器層先判斷,不會以一個不完整的 PHP location 取代現有 FastCGI 設定。多個網址、HTTP/HTTPS 或其他對外入口須逐一納管。若現有 location 已一律 return 403,加入白名單不會自動解除它,須將登入/後台的既有封鎖整合為來源判斷。

登入 POST 注意:本節不要求全站禁止 POST。若先前啟用第 5-3 節,須先設計精確例外:僅白名單來源的登入端點允許必要 POST、限制本文大小與格式,其他寫入/上傳維持封鎖。不要只移除 POST 禁令卻保留其他不完整保護;後台若只供檢視,也不要順便開放修改表單。

代理注意:上述 geo 預設依 Nginx 看到的來源位址判斷。若前面有 CDN/反向代理,先核對可信代理清單與 real_ip 設定,避免全部被當成代理 IP。不能信任任何訪客自行提交的 X-Forwarded-For,也不能把所有網路都設為可信代理。IPv6 需另加經確認的來源範圍。

6-3 檢查與驗證

sudo nginx -t && sudo systemctl reload nginx
curl -I https://school.example.org/user.php
curl -I https://school.example.org/admin.php
curl -I -H 'X-Forwarded-For: 192.0.2.10' https://school.example.org/user.php

必須分別從允許及不允許的實際網路測試;curl 加上 X-Forwarded-For 不會真的改變來源。非白名單應為 403,偽造標頭也不能繞過。允許來源應能取得登入頁,並由管理員驗證實際登入、重新導向及後台;只看到 200 不代表登入成功。再測首頁消息、篩選、分頁、縮圖與附件,避免防護誤擋閱讀。

七、如何檢查入侵跡象?

先保留程序、連線與日誌,必要時在隔離前後記錄時間與雜湊。不要先刪除疑似後門,也不要用瀏覽器開啟或執行可疑 PHP。

date -Is
sudo ss -ntup
ps -eo user,pid,ppid,lstart,args
last -ai | head -30
sudo ls -lh /var/log/nginx/ /var/log/auth.log* /var/log/php* 2>/dev/null
sudo crontab -l
sudo ls -la /etc/cron.d /etc/systemd/system
awk -F: '$3==0 {print $1,$3,$6,$7}' /etc/passwd

# 最近修改的 PHP:正常快取/更新也可能命中
sudo find /var/www -type f -name '*.php' -mtime -30 -print
# 上傳區程式候選:路徑依實際調整
sudo find /var/www/html/uploads -type f -iname '*.php*' -print
sudo find /var/www/html/uploads -type f -iname '*.phtml' -print
sudo find /var/www/html/uploads -type f -name '.user.ini' -print
# 僅做候選篩選,eval/base64 也可能出現在正常程式
sudo grep -RIlF -e 'eval(' -e 'base64_decode(' /var/www/html/uploads 2>/dev/null
# 對確認要保存的個別檔案計算雜湊,不要執行
sudo sha256sum /path/to/suspicious-file.php

應同時查網站管理員帳號異動、資料庫、SSH key、排程、systemd、auto_prepend_file、外連與檔案完整性。陌生亂數檔名、加密載入器、外部輸入交給 eval、異常程序值得追查,但單一關鍵字不能直接定罪。

日誌出現掃描請求只證明有人嘗試;回應 200 可能是首頁回退,不一定是外洩。SIGTERM 可能來自正常重啟;檔案時間可能被修改,不能據此認定攻擊日期或歸因特定 CVE。沒有命中也不能宣稱未入侵:日誌可能輪替、缺少 POST 內容,或攻擊者已移除痕跡。

若確認後門:啟動校方事件通報流程、保留證據、隔離、調查範圍,從乾淨映像與可信程式重建;在乾淨端輪替憑證並撤銷工作階段,審查後才匯入資料。不要把整份被入侵網站程式原封不動還原上線。

八、交給維護廠商或 AI 助手的檢查指令

請在已授權的網站主機進行唯讀盤點,確認所有 Web PHP、CMS、容器與版本,核對 CVE-2026-109618/109619 的上游或供應商回補公告。提出備份、還原測試、相容性與升級方案。若需暫時防護,先辨識登入、AJAX、搜尋及下載入口,保留正常閱讀;登入來源使用本校確認的最小 IP 範圍,不信任偽造代理標頭。檢查後門、帳號、排程、外連與日誌,保留證據,不執行疑似後門。報告必須區分已確認、待確認及未測試項目;對外分享前移除真實 IP、帳密、內部路徑與日誌個資。

官方參考資料

本文指令為教學範例,未包含任何學校的真實 IP、網站網址、帳密或入侵日誌。實際設定須依作業系統、CMS 路由與代理架構調整,修補狀態以操作當日官方公告為準。

沒有留言:

張貼留言