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 路由與代理架構調整,修補狀態以操作當日官方公告為準。

2026年8月24日 星期一

Google Workspace 雖正常寄信,但 SPF 驗證沒有成功

 SPF 快速檢查

1. 查詢公網 DNS TXT Record

PowerShell 執行:

curl.exe "https://cloudflare-dns.com/dns-query?name=csps.tyc.edu.tw&type=TXT" `
-H "accept: application/dns-json"

2. 確認 DNS wire-format

找到 SPF 的 data 欄位。

✅ 正確:單一完整字串

"v=spf1 include:_spf.google.com ~all"

Cloudflare JSON 中通常會看到:

\"v=spf1 include:_spf.google.com ~all\"

 

❌ 錯誤:被拆成多個字串

"v=spf1" "include:_spf.google.com" "~all"

Cloudflare JSON 中會看到類似:

\"v=spf1\" \"include:_spf.google.com\" \"~all\"

 

此格式會將各段直接串接,可能形成:

v=spf1include:_spf.google.com~all

造成 Gmail 無法正確辨識 SPF,可能顯示:

SPF: NONE

3. 修正後驗證

修正 DNS TXT 後再次執行步驟 1。

確認變成:

"v=spf1 include:_spf.google.com ~all"

再寄一封測試信至 Gmail,於「顯示原始郵件」確認:

SPF: PASS
DKIM: PASS
DMARC: PASS
 

一、問題現象

2026/08/24 發現學校 @csps.tyc.edu.tw 帳號寄送郵件至 Gmail 時,部分郵件遭 Gmail 退信,錯誤訊息如下:

550 5.7.1 Gmail has detected that this message is likely unsolicited mail.

表示 Gmail 將郵件判定為疑似垃圾郵件/未經請求郵件,因此直接拒收。


二、初步檢查結果

檢查退信原始郵件 Header:

  • SPF:NONE
  • DKIM:PASS
  • DMARC:PASS

其中 Gmail 顯示:

spf=none (google.com: xxx@csps.tyc.edu.tw does not designate permitted sender hosts)

表示 Google Workspace 雖正常寄信,但 SPF 驗證沒有成功。


三、DNS 排查過程

檢查 csps.tyc.edu.tw DNS:

SPF 設定

原設定內容:

v=spf1 include:_spf.google.com ~all

DNS 權威伺服器:

  • ns1.tyc.edu.tw
  • ns2.tyc.edu.tw

內部 DNS 10.255.4.1、Cloudflare 1.1.1.1 及兩台權威 DNS 均可查到 SPF 紀錄。

但進一步檢查 DNS 原始 TXT 回應時,發現 SPF 被存成三段:

"v=spf1" "include:_spf.google.com" "~all"

由於 TXT 多段字串在解析時會直接串接,造成 SPF 實際內容可能變成:

v=spf1include:_spf.google.com~all

因此 Gmail 無法正確辨識 SPF,回傳 SPF: NONE。


四、修正方式

將原 SPF TXT Record 修改為「單一完整字串」:

修正前:v=spf1 include:_spf.google.com ~all
將字串加上""

修正前:"v=spf1 include:_spf.google.com ~all"

修正後,Cloudflare DNS 查詢結果變成:

"v=spf1 include:_spf.google.com ~all"

確認 SPF 已以單一 TXT 字串正常公開。

DKIM 與 DMARC 均未修改。


五、修正後驗證結果

重新由 @csps.tyc.edu.tw 寄送測試郵件至 Gmail。

Google 原始郵件驗證結果:

  • SPF:PASS
  • DKIM:PASS
  • DMARC:PASS

Header 顯示:

spf=pass (google.com: domain of gavin@csps.tyc.edu.tw designates 209.85.220.41 as permitted sender)

確認 Google Workspace 寄信來源已被 SPF 正確授權。


六、目前狀態

DNS 與郵件驗證目前均正常:

  • SPF:PASS
  • DKIM:PASS
  • DMARC:PASS
  • Google Workspace 寄信:正常
  • Gmail 已可正常收件

但部分測試郵件目前仍可能被 Gmail 分類至「垃圾郵件」,推測與先前 SPF 長期異常造成的寄件網域信譽、垃圾郵件判定歷史有關。

後續建議暫時避免短時間大量寄送相同內容郵件,並持續觀察 Gmail 收件分類及 Google Postmaster Tools 的 Domain Reputation、Spam Rate 與 Authentication 狀況。


七、維護重點

日後若再次發生 Gmail 退信,建議依序檢查:

  1. Gmail 原始郵件中的 SPF、DKIM、DMARC 是否皆為 PASS。
  2. SPF TXT 是否仍為單一完整字串。
  3. ns1.tyc.edu.tw、ns2.tyc.edu.tw 是否回傳一致紀錄。
  4. 公網 DNS 是否可正常查詢。
  5. 若三項驗證皆 PASS,但郵件仍進垃圾郵件,再檢查 Gmail Domain Reputation 與 Spam Rate。

本次主要故障原因:SPF TXT Record 被 DNS 系統拆成多個未保留空白的字串,造成 Gmail SPF 驗證失敗。

 

 

2026年8月13日 星期四

Google Workspace 網域郵件 SPF、DKIM、DMARC 認證設定 SOP

出納組改用學校網域的帳號,遇到了被退信的問題。

所以我重新把設定檢查一次,順便記錄下來,原因出在對方那邊封鎖住了網域。

適用情境:自有網域使用 Google Workspace / Gmail 收發郵件,例如:

user@csps.tyc.edu.tw

完成後應具備三項寄件驗證:

SPF  + DKIM  + DMARC 

一、先確認 Gmail / MX 已正常運作
二、設定 SPF
(前兩個步驟都已經正常運作了,此SOP主要是做電子郵件排除被列為垃圾郵件的驗證)
三、設定 DKIM 


1. 進入 Google 管理控制台

登入:Google Admin Console

依序進入:

應用程式→ Google Workspace→ Gmail→ 驗證電子郵件

選擇要設定的網域。


 


2. 產生 DKIM 記錄

Google 會產生一組:

DNS 主機名稱

例如:

google._domainkey

以及:

TXT 值

類似:

v=DKIM1; k=rsa; p=MI...

其中 p= 後面是一長串公開金鑰。

不可自行修改此內容。


 


3. 到 DNS 新增 TXT Record

新增:

Name

google._domainkey

完整網域會變成:

google._domainkey.csps.tyc.edu.tw

Type

TXT

Value

使用 Google 管理控制台產生的完整內容:

v=DKIM1; k=rsa; p=...


 

4. 回 Google Admin 啟動 DKIM

DNS Record 建立並生效後,回到:

Google 管理控制台→ Gmail→ 驗證電子郵件

按:

開始驗證

正常完成後應看到:

正在使用 DKIM 驗證電子郵件

代表 Google Workspace 寄出的郵件會加入:

DKIM-Signature

例如:

d=csps.tyc.edu.tw;
s=google;

 

四、設定 DMARC

DMARC 必須建立在:

_dmarc.你的網域

例如:

_dmarc.csps.tyc.edu.tw

建議先完成 SPF 與 DKIM,再設定 DMARC。


1. 初次導入先使用監控模式

建議第一階段:

v=DMARC1; p=none;

p=none 代表:

執行 DMARC 驗證,但暫時不要因 DMARC 驗證失敗就直接拒收或隔離郵件。

這很適合剛開始導入的學校或機關網域。


2. DNS 建立 TXT Record

新增:

Name

_dmarc

完整名稱:

_dmarc.csps.tyc.edu.tw

Type

TXT

Value

v=DMARC1; p=none;

 

五、外部 DNS 驗證

完成後要從外部 DNS 驗證,而不是只看 DNS 管理介面。

因為教育局有鎖定無法使用外部DNS,

建議可以先聯手機網路進行測試。


Windows CMD 可使用:

SPF

nslookup -type=TXT csps.tyc.edu.tw 8.8.8.8

應看到:

v=spf1 include:_spf.google.com ~all

DKIM

nslookup -type=TXT google._domainkey.csps.tyc.edu.tw 8.8.8.8

應看到:

v=DKIM1; k=rsa; p=...

DMARC

nslookup -type=TXT _dmarc.csps.tyc.edu.tw 8.8.8.8

應看到:

v=DMARC1; p=none;

本次的問題排除

從信件的原始檔來看,找出問題點不在於設定有問題,而是被對方的信件伺服器擋住。




 

 另外寄送到一般Gmail被退信原因,一次寄送太多,觸發垃圾信機制。

建議薪資系統廠商應該要加入延遲發信的功能,避免同一時間發送大量信件。 

2026年5月15日 星期五

Ubuntu + XOOPS 網站弱掃改善紀錄

 Nginx CVE、CSP 缺失、PHP-FPM 504、MySQL ESM 更新處理流程

下班後接到通知

資安掃描出現兩個主要警示:

Detected CVEs for Nginx 1.14.0 with CVSS above 7.0
No Content-Security-Policy configuration detected on applicable website

這是運作的學校網站,目前還有重要任務。

1. 不影響 XOOPS 前後台運作
2. 不直接升級整個 Ubuntu 版本
3. 先套用 Ubuntu Pro / ESM 安全修補
4. 補上網站安全標頭
5. 更新 PHP / MySQL 時保留完整備份 

處理前先確認系統版本

lsb_release -a
nginx -v
apt-cache policy nginx
不過目前使用的這個版本已經結束標準支援,所以建議啟用 Ubuntu Pro / ESM。 
 

啟用 Ubuntu Pro / ESM

若系統沒有 pro 指令,先安裝工具:

sudo apt update
sudo apt install ubuntu-advantage-tools

確認:

pro version
pro status

補充:Ubuntu Pro 個人版說明

Ubuntu Pro 是 Canonical 提供的延伸安全維護服務,

可讓 Ubuntu LTS 在標準支援結束後繼續取得 ESM 安全更新。

Ubuntu Pro 並不是把系統升級到新版 Ubuntu,

而是針對原系統套件提供官方 backport 安全修補。

目前 Ubuntu Pro 對個人用途提供免費方案,

最多可用於 5 台機器。

使用時需登入 Ubuntu / Canonical 帳號取得 token,

並在主機上執行 pro attach 綁定。

Token 不應公開,。
對於暫時無法立即升級的舊站,

例如 Ubuntu 18.04 + XOOPS、PHP 7.2、MySQL 5.7,Ubuntu Pro / ESM 

可以作為過渡期的安全修補方案。

 

如果尚未綁定 Ubuntu Pro:

sudo pro attach 你的_TOKEN

啟用 ESM:

sudo pro enable esm-infra
sudo pro enable esm-apps
sudo apt update

查看可更新套件:

sudo apt list --upgradable

注意:

正式網站不要直接執行:

sudo apt upgrade -y

建議分批更新。

 

更新前先備份

1. 備份 Nginx、PHP、MySQL 設定

sudo cp -r /etc/nginx /etc/nginx.bak.$(date +%Y%m%d-%H%M)
sudo cp -r /etc/php /etc/php.bak.$(date +%Y%m%d-%H%M)
sudo cp -r /etc/mysql /etc/mysql.bak.$(date +%Y%m%d-%H%M)

2. 備份網站目錄

請將 /var/www/html 改成自己的網站目錄:

sudo tar -czvf /root/webroot-backup-$(date +%Y%m%d-%H%M).tar.gz /var/www/html

3. 找出 XOOPS 資料庫設定

新版 XOOPS 的資料庫設定不一定在 mainfile.php,可能會放在:

xoops_data/data/secure.php

可用:

sudo grep -n "secure.php" /var/www/html/mainfile.php
sudo find /var/www -path "*xoops_data/data/secure.php" -print

查看資料庫名稱與帳號時,不要公開密碼:

sudo grep -n "XOOPS_DB_HOST\|XOOPS_DB_USER\|XOOPS_DB_NAME" /var/www/xoops_data/data/secure.php

請勿截圖或公開:

XOOPS_DB_PASS

4. 備份資料庫

假設資料庫名稱為:

你的資料庫名稱

備份:

mysqldump -u root -p --single-transaction --routines --triggers 你的資料庫名稱 | gzip > /root/db-backup-$(date +%Y%m%d-%H%M).sql.gz

檢查備份檔:

ls -lh /root/*.sql.gz
gzip -t /root/*.sql.gz

gzip -t 沒有錯誤訊息,代表備份檔正常。

分批更新套件

第一批:Nginx

sudo apt install --only-upgrade nginx nginx-common nginx-core

確認:

apt-cache policy nginx nginx-core nginx-common

如果看到:

Installed: 1.14.0-0ubuntu1.11+esm1

代表已套用 Ubuntu Pro / ESM 安全修補。

注意:
nginx -v 仍可能顯示:

nginx/1.14.0

這是 Ubuntu backport 的正常現象,不能只看 nginx -v。


隱藏 Nginx 版本資訊

編輯:

sudo nano /etc/nginx/nginx.conf

在 http { ... } 裡確認:

server_tokens off;

不要是:

# server_tokens off;

測試並重新載入:

sudo nginx -t
sudo systemctl reload nginx

確認:

curl -I https://你的網站網域

理想結果:

Server: nginx

不要再出現:

Server: nginx/1.14.0 (Ubuntu)

補上 Content-Security-Policy 與安全標頭

找到網站設定檔:

sudo grep -R "server_name 你的網站網域" /etc/nginx/sites-available /etc/nginx/sites-enabled

編輯對應設定檔,例如:

sudo nano /etc/nginx/sites-available/default

在對應的 server { ... } 裡加入:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self';" always;

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

套用:

sudo nginx -t
sudo systemctl reload nginx

確認:

curl -I https://你的網站網域

應看到:

Content-Security-Policy: default-src 'self'; ...
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()

若 XOOPS 是舊系統,CSP 一開始不要設太嚴格,否則後台編輯器、模組、圖片上傳可能會壞。


更新 PHP 7.2

更新 PHP 7.2 ESM 安全修補:

sudo apt install --only-upgrade \
php7.2-cli php7.2-common php7.2-curl php7.2-fpm \
php7.2-gd php7.2-json php7.2-mbstring php7.2-mysql \
php7.2-opcache php7.2-readline php7.2-soap \
php7.2-xml php7.2-zip

重啟:

sudo systemctl restart php7.2-fpm
sudo systemctl reload nginx

確認:

systemctl status php7.2-fpm --no-pager
apt-cache policy php7.2-fpm

若 XOOPS 後台出現 504 Gateway Time-out

如果 PHP 更新後,XOOPS 後台進入 admin.php 出現:

504 Gateway Time-out

查看 log:

sudo tail -n 80 /var/log/nginx/error.log
sudo tail -n 80 /var/log/php7.2-fpm.log

若看到:

server reached pm.max_children setting (5), consider raising it

代表 PHP-FPM 處理程序太少。

編輯:

sudo nano /etc/php/7.2/fpm/pool.d/www.conf

將:

pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

調整為保守版:

pm = dynamic
pm.max_children = 15
pm.start_servers = 4
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500
request_terminate_timeout = 180s

檢查與重啟:

sudo php-fpm7.2 -t
sudo systemctl restart php7.2-fpm
sudo systemctl reload nginx

進入 XOOPS 後台後,建議執行:

清除快取

包含 XOOPS cache / templates_c / smarty compile 類型的快取。
清完後,後台通常會明顯變快。


更新 MySQL 5.7

確認資料庫備份已存在:

ls -lh /root/*.sql.gz
gzip -t /root/*.sql.gz

更新:

sudo apt install --only-upgrade \
mysql-client-5.7 \
mysql-client-core-5.7 \
mysql-server \
mysql-server-5.7 \
mysql-server-core-5.7

確認版本:

mysql --version
apt-cache policy mysql-server-5.7
systemctl status mysql --no-pager

成功後應看到:

Distrib 5.7.44
Installed: 5.7.44-0ubuntu0.18.04.1+esm1
active (running)

測試 XOOPS:

前台首頁
登入
後台管理
模組管理
文章 / 最新消息
圖片上傳
表單或常用模組

最後驗證弱掃問題是否改善

1. 驗證 Nginx CVE 修補與版本隱藏

apt-cache policy nginx nginx-core nginx-common
curl -I https://你的網站網域

合格條件:

Installed: 1.14.0-0ubuntu1.11+esm1
Server: nginx

2. 驗證 CSP

curl -I https://你的網站網域

合格條件:

Content-Security-Policy: default-src 'self'; ...