WordPress 資料庫安全強化的四道防線

資料庫是 WordPress 網站真正的核心。文章、頁面、使用者帳號與密碼雜湊、外掛設定,甚至 WooCommerce 的訂單與客戶資料,全部存在資料庫裡;伺服器上的檔案只放佈景主題和圖片。一旦攻擊者把目標對準資料庫,他要的東西幾乎都在那裡。

更麻煩的是,多數資料庫入侵安靜得可怕。被植入的後門帳號或惡意程式碼,可能在資料庫裡潛伏好幾週都沒有任何外顯異常,等到你發現首頁被導去垃圾網站、或內容被竄改時,攻擊者往往已經來去自如一段時間了。

很多站長把心力全放在強密碼、雙重驗證、外掛更新上,這些都對,但資料庫這一層常常整個被跳過。WordPress 資料庫安全的重點不是單一神奇設定,而是把幾道彼此獨立的防線疊起來:更換預設資料表前綴、把資料庫帳號的權限砍到最低、在跨主機連線時加上加密,再加上保護 wp-config.php 與離線備份。這篇會把每一道防線的原理、實際做法與常見地雷講清楚,動手前請務必先完整備份整站,因為其中幾個步驟會直接改動資料庫,沒有備份很難回頭。

為什麼資料庫是 WordPress 最該優先保護的一層

資料庫之所以是攻擊者的首選目標,原因很單純:值得偷或值得破壞的東西都在裡面。最常見的攻擊手法仍是 SQL 注入(SQL injection),攻擊者透過登入表單、搜尋框,或某個有漏洞的外掛欄位送進精心構造的輸入,如果這段輸入沒有被正確過濾,資料庫就會把它當成指令執行。

注入成功之後,攻擊者可以匯出整個資料庫、新增管理員帳號、把惡意內容塞進你的文章,甚至一次清空所有資料表。對經營商店的人來說,這代表客戶個資、訂單紀錄、付款相關資訊都可能外洩。

wp-config.php 是另一個高價值目標。這個檔案以明碼存放資料庫名稱、帳號、密碼與一組驗證金鑰,攻擊者只要讀到它,根本不需要你的 WordPress 後台帳密,就能直接連進資料庫,完全繞過 WordPress 本身。

理解這幾條攻擊路徑,就能看懂後面每一道防線各自在擋什麼:更換前綴擋的是自動化掃描、限制權限擋的是入侵後的擴大破壞、連線加密擋的是傳輸過程被竊聽、保護 wp-config.php 擋的是憑證外洩。沒有任何一招能單獨解決問題,要的是整體姿態的提升。

更換資料表前綴能擋掉哪些攻擊,又擋不掉什麼

WordPress 預設把每一張資料表都冠上 wp_ 前綴,例如 wp_postswp_userswp_options。針對 WordPress 的自動化 SQL 注入腳本,幾乎都是直接寫死這些表名來打,因為它們假設絕大多數網站都沒改過。

這裡要先把話講清楚,避免被誇大的說法誤導。更換前綴本身不是萬靈丹,WordPress 安全社群很早就指出,「改了前綴就能擋下某類攻擊」是流傳已久的迷思。一個鎖定你的人工攻擊者,有的是辦法先把實際前綴查出來再下手。它真正的價值在於:把你的網站從「自動化工具第一輪掃描就能命中」的名單裡移出去,省下的力氣不多,但確實消滅了一整類低成本的群發式攻擊,而且只花幾分鐘,值得當成整體強化的一環來做。

換前綴有兩種做法。對多數使用者來說,用安全外掛是比較安全的選擇,因為它會自動處理序列化資料(serialized data)。WordPress 有些設定是以序列化的 PHP 字串存在 optionsusermeta 表裡,前綴字串可能藏在這段序列化內容中,純手動的 SQL 取代很容易破壞這種結構,導致網站白屏。像 All-In-One Security 這類外掛內建了前綴更換工具,會一次改好 wp-config.php、重新命名所有資料表,並正確處理序列化參照。

如果你想手動處理,流程大致如下。先用 FTP 或檔案管理員打開 wp-config.php,把 $table_prefix 這一行改成新前綴,只用英文字母、數字與底線:

$table_prefix = ‘site82_’;

接著登入 phpMyAdmin,對每一張資料表執行更名查詢,例如把 wp_posts 改成 site82_posts,12 張核心資料表與所有外掛建立的資料表都要逐一處理。最後還要更新 options 表裡 option_name 欄位、以及 usermeta 表裡 meta_key 欄位中仍引用舊前綴的那幾列,否則使用者權限與部分設定會讀不到。改完先逛一次首頁、再登出登入後台確認都正常;只要有任何地方壞掉,事前的備份就是最快的回復路徑。

把資料庫帳號權限砍到 WordPress 真正需要的範圍

多數主機在安裝 WordPress 時,會給資料庫帳號對整個資料庫的完整管理權限。但 WordPress 日常運作其實只需要四種權限:SELECTINSERTUPDATEDELETE,也就是讀取、寫入、更新、刪除資料列。超出這四項以外的權限,都只是多出來的風險。

差別在攻擊發生時會立刻顯現。假設攻擊者透過某個外掛漏洞拿到了你的資料庫憑證,如果這組帳號只有那四種權限,他頂多能讀寫資料;但如果帳號握有 DROPALTERCREATE 這些結構層級的權限,他就能整張表刪掉、改動結構,破壞範圍完全是兩個層級。最小權限原則(least privilege)擋的就是「入侵後的擴大破壞」。

收緊權限有兩種方式。較簡單的是在 phpMyAdmin 的「使用者帳號」裡找到你的 WordPress 資料庫帳號,點「編輯權限」,把 SELECTINSERTUPDATEDELETE 以外的全部取消勾選後儲存。想要更乾淨的話,也可以另外建立一個專用帳號,只授予這四項權限,再把新憑證寫回 wp-config.php 的 DB_USERDB_PASSWORD

這裡有一個務必記住的眉角:部分外掛安裝、以及 WordPress 核心的大版本更新,會需要 CREATEALTER 權限來新增或修改自己的資料表。如果你砍完權限後某個外掛安裝失敗,正確做法是暫時把這兩項權限加回去、完成安裝、再立刻收回,這本來就是維護最小權限環境的正常一環,不是設定錯誤。WooCommerce 在初次啟用或大改版時尤其常觸發這種需求,因為它會建立與調整訂單、商品相關的多張資料表。

如果你在同一台伺服器上跑多個 WordPress 網站,請替每一站使用獨立的資料庫與獨立的資料庫帳號。這樣即使其中一站被攻破,攻擊者也碰不到其他站的資料,這種隔離就是所謂的「圍堵」(containment)。設定完成後,到後台新增一篇草稿、儲存、再刪除,三個動作都成功就代表權限剛好夠用、沒有多餘。

限制連線來源,不讓資料庫對外網開門

在多數 WordPress 環境裡,WordPress 與 MySQL 跑在同一台伺服器上,根本沒有理由開放外部 IP 直接連進資料庫。如果遠端連線一直開著,攻擊者就能從網路上任何地方對你的 MySQL 嘗試認證,又一次繞過了 WordPress。

關閉的位置有兩處,建議兩邊都檢查。第一處是 MySQL 設定。如果你自己管理伺服器(VPS 或雲端主機),打開 MySQL 設定檔,找到 bind-address 這一行,確認它的值是 127.0.0.1;如果看到 0.0.0.0,代表它對所有網路介面開放,改成 127.0.0.1 後重啟 MySQL 即可。

第二處是資料庫帳號本身的允許來源。即使 MySQL 已綁定本機,也值得在帳號層級再確認一次。在 phpMyAdmin 的「使用者帳號」裡,看你的 WordPress 帳號那一列的「主機」欄位,正常應該是 localhost127.0.0.1;如果出現 % 這個萬用字元,代表這個帳號可以從任何 IP 連進來,應該把它移除後,重新建立一個主機限定為 localhost 的帳號。

如果你用的是共享主機、拿不到 MySQL 設定檔,就改去控制台處理。以 cPanel 為例,「資料庫」分類底下通常有「遠端 MySQL」(Remote MySQL)的設定,把裡面列出的 IP 全部移除,等同在主機層級關掉了遠端存取。

連線加密在什麼情況下才真的需要

連線加密這一步的關鍵判斷是:你的 WordPress 與 MySQL 是不是跑在同一台機器上。如果是同機,資料在兩者之間流動時完全不經過網路,本身就沒有被中途竊聽的問題,這一步可以略過。一般的共享主機多半屬於這種情形。

但如果你的資料庫跑在另一台伺服器,這在 VPS 多機架構、雲端主機或部分代管環境很常見,那麼帳密、查詢內容、工作階段權杖等資料就會實際走過一段網路連線。少了加密,這些資料是以明碼傳輸的,等於把登入憑證攤在路上。

先和主機商確認,是很值得的一步。Kinsta、WP Engine、Cloudways 這類代管服務,多半已經在基礎架構層級強制啟用了資料庫連線加密,你可能早就被保護到了,動手改設定前先查主機文件比較保險。

如果確定要自己啟用,伺服器端要在 MySQL 設定檔指定 SSL 憑證路徑(ssl-cassl-certssl-key),並把 require_secure_transport 設為 ON 來要求加密連線,存檔後重啟 MySQL。WordPress 端則是在 wp-config.php 裡,於 /* That's all, stop editing! */ 這一行上方加入一行常數,告訴 WordPress 連線時要走 SSL:

define(‘MYSQL_CLIENT_FLAGS’, MYSQLI_CLIENT_SSL);

這個常數自 WordPress 3.6 起就支援。若需要更細的憑證驗證控制,還可以搭配其他常數調整,例如在某些憑證設定下用 MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT 略過伺服器憑證驗證,但這會降低安全性,只在你清楚自己在做什麼時才用。設好之後,可以查看 MySQL 伺服器的錯誤紀錄,確認應用程式帳號的連線已標示為使用 SSL。

順帶一提,這裡講的「資料庫連線加密」和你網站對訪客啟用的 HTTPS(瀏覽器網址列那把鎖)是兩件不同的事。前者保護的是 WordPress 與 MySQL 之間,後者保護的是訪客瀏覽器與你網站之間,兩者都該做,但解決的不是同一段路。

保護 wp-config.php,斷掉憑證外洩的那條路

前面把資料庫帳號限制得再好,只要 wp-config.php 能被讀走,攻擊者就拿到了直接連線的全部鑰匙。這個檔案以明碼存著資料庫名稱、帳號、密碼,是任何一次 WordPress 攻擊最先被瞄準的檔案之一,建議把下面三道保護一起套上,因為它們各自堵的是不同的破口。

移到網站根目錄之上:WordPress 在找不到 wp-config.php 時,會自動往上一層目錄找,所以你可以把它從 public_html 移到上一層而不必改任何設定。這樣即使網站目錄被穿透,這個檔案也不在可被存取的範圍內。部分代管主機不允許存取網站根目錄之上的位置,遇到這種情況就跳過這道、用後面兩道。

用 .htaccess 擋掉瀏覽器直接存取:在網站根目錄的 .htaccess 檔加入規則,告訴 Apache 拒絕所有對這個檔案的瀏覽器請求,這樣就算有人知道完整路徑也讀不到。較新的 Apache 設定改用 Require all denied 的寫法。

把檔案權限設為 400 或 440:檔案權限決定伺服器上哪些使用者能讀寫或執行這個檔案。設成 400 代表只有檔案擁有者能讀,設成 440 則多開放給伺服器群組唯讀,部分主機設定會需要後者。設定方式是在主機檔案管理員裡對 wp-config.php 改權限,或用 FTP 客戶端直接調整。

三道都套上之後,在瀏覽器試著開 你的網域/wp-config.php,應該要得到 403 Forbidden 才算成功。要提醒的是,權限別設得太死,例如設成 000 反而會讓 WordPress 自己也讀不到檔案,出現「無法建立資料庫連線」的錯誤,這時回到 400 或 440 即可。

清掉殘留資料表,並用備份補上最後一道防線

硬化做得再齊全,也只是降低被打中的機率,無法保證百分之百。所以資料庫安全的最後一塊,是「萬一真的被攻破,你能不能乾淨地回復」。

先處理一個容易被忽略的隱患:被棄用外掛留下的殘留資料表。在 WordPress 移除一個外掛時,它建立的資料表通常不會被一併刪除,WordPress 不會自動清,多數外掛也不會在移除時自我清理。這些孤兒資料表除了讓資料庫變肥,更藏著一個安全風險:如果某張表來自一個有已知 SQL 注入漏洞的外掛,即使外掛本體已經移除,那張表仍可能被利用。

清理前一定要先做一份全新備份,因為刪表是不可逆的。在 phpMyAdmin 裡逐一檢視資料表,前綴和現用 $table_prefix 不符、或表名帶有你早已不用的外掛名稱的,都是候選對象。但要特別小心 WooCommerce、表單外掛(如 WPForms)、會員或課程類外掛相關的資料表,它們常存著交易紀錄、表單投稿、使用者資料,就算外掛目前停用也可能還需要。不確定某張表屬於誰,就把表名連同「WordPress」一起搜尋,先查清楚是哪個外掛建立的再決定。

備份本身也要顧到安全,這點常被漏掉。一份沒加密的備份檔放在雲端硬碟,等於你整個資料庫的第二份完整副本,任何拿到那個雲端帳號存取權的人,不必碰你的線上網站,就能下載打開、讀走每一筆使用者紀錄、密碼雜湊與客戶訂單。AES-256 這類加密能讓備份檔在沒有金鑰時形同亂碼,記得把金鑰另外存到密碼管理工具,弄丟金鑰你自己也救不回備份。

備份要排程自動執行、而且要存到網站伺服器以外的地方。手動備份在現實中總會漏,你會記得在大更新前跑一次,卻很難每天都記得;而存在同一台伺服器上的備份不算真正的備份,伺服器一旦整台出事,網站和備份會同時消失。對會持續發文、處理訂單或有活躍使用者的網站,每天一次的資料庫備份是合理節奏,再搭配一份離站副本,才有真正可用的回復點。最後別忘了實際測試一次還原,多數人都是在最需要快速救援時,才發現備份其實是壞的。

從更換前綴、限縮權限、限制連線來源到連線加密,這幾道防線沒有先後優劣之分,缺一道就多一個破口。先確認你的 WordPress 與 MySQL 是否同機,決定要不要做連線加密;接著今天就能動手的,是把資料庫帳號權限收到那四項、把 wp-config.php 三道保護套好,再排一份每天自動執行、且加密存到離站的備份。動任何會改資料庫的步驟之前,先備份、改完先測一遍首頁與後台,這個習慣本身就是你最便宜也最有效的一道保險。

相關文章
標籤: 最小權限, 資料庫備份, wp-config.php, WordPress 資料庫安全, 資料表前綴