多數人以為駭客要闖進一個網站,得先找到後台密碼或撬開伺服器的防火牆,其實很多時候他要的只是一個沒設防的文字輸入框:在登入頁的帳號欄位打進一小段文字,就能讓資料庫把整份使用者清單吐出來,甚至直接跳過密碼驗證登入你的後台。
這就是 SQL injection(SQL 注入)的核心手法:把資料庫看得懂的指令偽裝成一般使用者輸入,塞進登入表單、搜尋框、留言區或任何一個外掛的輸入欄位,讓網站程式誤以為那是要執行的查詢,直接照做。WordPress 每一次登入、發文、留言,背後都是靠 SQL 查詢在跟資料庫溝通,只要有一處輸入沒把使用者打的字跟要執行的指令分開處理,就可能被鑽進去。
這不是只存在於教學文裡的老問題。2026 年 7 月,連 WordPress 核心團隊親自維護、每一行程式碼都要經過審查的官方軟體本身,都曾被查出一組能讓完全沒有帳號的人直接取得網站控制權的注入漏洞,而且已經有人在真實環境裡動手利用。問題出在 WordPress 跟資料庫溝通的方式裡,藏著一個很少人真正搞懂的細節。
SQL Injection 是什麼?把使用者輸入誤判成資料庫指令的漏洞
WordPress 網站背後其實有一個資料庫在做所有粗重的工作。你在後台打的每一篇文章、每一則留言、每一次登入,WordPress 都要透過 $wpdb 這個類別,把動作翻譯成資料庫看得懂的 SQL(Structured Query Language,一種操作關聯式資料庫的標準語言)指令,再送去問 MySQL 或相容的 MariaDB 資料庫系統要不要放行、要不要寫入。
問題出在這些指令大多是用字串拼接的方式現場組出來的,程式先寫好一段查詢的骨架,再把使用者輸入的內容直接接進去,變成一整串文字送給資料庫執行。OWASP(國際知名的網路應用程式安全組織)在其 SQL Injection 防禦指南裡,把這個成因講得很直白,只要程式用字串拼接組出動態查詢、又沒把使用者輸入當成純資料處理,SQL injection 的弱點就會出現;防禦的核心原則就是停止用字串拼接寫查詢,並且阻止惡意 SQL 指令混進實際會被執行的查詢裡。
這句話聽起來抽象,換成一個具體例子就很好懂。一個常見的登入查詢,背後其實是在檢查使用者輸入的帳號跟密碼,是否跟資料庫裡某一筆使用者資料完全吻合。如果程式沒把輸入內容當成純資料處理,攻擊者只要在帳號欄位打進 admin' --,這段文字被直接接進查詢後,後面的密碼比對就會被 SQL 的註解符號 -- 整個吃掉。資料庫看到 -- 之後的內容一律當成註解、不再執行,密碼比對這一段查詢等於憑空消失。攻擊者不需要知道正確密碼,光憑這幾個字元就能以 admin 身分登入。

這種手法能存在超過 20 年不是巧合。在 OWASP Top 10(每隔幾年更新一次、業界公認最具指標性的 Web 應用安全風險排名)裡,涵蓋 SQL injection 的注入類別,2025 年版排在第 5 名,再往前 2021 年版排第 3 名,更早之前的多個版本則長年盤據第 1 名。排名數字在動,但它從沒有真正離開過榜單。
從竊取資料到整站癱瘓的實際傷害範圍
知道攻擊手法只是一半,更重要的是搞懂它得手後能造成什麼後果,這不是「資料外洩」四個字可以打發的籠統說法。
SQL injection 攻擊得手後,通常會朝 4 種結果走:第一種是未經授權讀取資料,把本來只有登入使用者才能看到的帳號密碼、私密文章、客戶資料、甚至金流資料整批撈出來;第二種是竄改資料庫內容,改掉使用者權限、竄改文章內容、或直接變更網站設定;第三種是服務中斷,刪除或破壞關鍵資料讓網站無法正常運作;第四種則是權限升級,把這個破口當成跳板,進一步拿下更大範圍的系統存取權,不只停在資料庫這一層。

傷害不會只停在技術面。Google 官方說明指出,一旦網站被判定已經遭到入侵、或是被用來操縱搜尋排名,搜尋結果旁可能會被標上「這個網站可能已遭駭客入侵」這類警示字樣,網站也可能被列入 Google 安全瀏覽(Safe Browsing)的危險網站清單,多數主流瀏覽器都會採用這份名單,訪客一點進來就會先看到警告頁。要解除警示,網站經營者得先把惡意內容徹底清乾淨,再透過 Search Console 提交安全性問題報告申請移除,這是官方唯一認可的管道。
這不是少數倒楣網站才會遇到的狀況。國際級 CDN 與資安大廠 Akamai 在分析 2017 年 11 月到 2019 年 3 月共 17 個月的 Web 應用防火牆資料後發現,SQL injection 攻擊佔了所有 Web 應用層攻擊的 65.1%,逼近三分之二,比兩年前同類攻擊僅佔 44% 的比例又高出一截,是該份報告裡成長最快的攻擊手法。專門守護 WordPress 生態圈的資安廠商 Wordfence,也在《2024 Annual WordPress Vulnerability and Threat Report》裡指出,光是自家防火牆在 2024 年全年就攔截了超過 11 億次 SQL injection 攻擊嘗試,是當年度第二常被攔截的攻擊類型,僅次於跨站腳本攻擊(XSS,90 億次)。只要你的網站掛在網路上,被試探的機率就遠比想像中高。
連 WordPress 核心團隊都曾被攻破的一次注入漏洞事件
上面這些數字聽起來像是別人的網站才會遇到的事,但 2026 年 7 月發生的一起事件證明,就算是 WordPress 核心本身,也不是絕對安全的保證。
2026 年 7 月 17 日,WordPress 核心團隊發布 7.0.2 安全更新,修補一組合併後能讓完全沒有帳號的人直接執行任意程式碼的漏洞鏈,業界稱為「wp2shell」。受影響版本涵蓋 WordPress 6.8 到 7.0.1,範圍相當廣;因為風險評等極高,官方罕見地對受影響網站啟用了強制自動更新,多數網站的管理員甚至不需要自己動手,系統就會被推送更新。
這組攻擊鏈之所以危險,在於 2 個看似都不算嚴重的漏洞被串在一起。第一個漏洞出在 WordPress 核心 WP_Query 處理 author__not_in 這個查詢參數的方式上,官方原本設計的清理函式只有在這個參數是「陣列」型態時才會執行;如果改用「字串」型態送進去,清理程序就會被整個略過,字串直接被拼進 SQL 的 WHERE 子句,沒有經過任何整數轉換或參數化,構成一個典型的 SQL injection 弱點。
但正常情況下,一般使用者根本碰不到這個參數。真正讓它變得危險的是第二個漏洞,出在 REST API 的批次請求端點:它在「比對要用哪個處理器驗證」跟「實際執行哪個處理器」這兩件事上,各自用了一份索引陣列,而這 2 份陣列在特定情況下會對不齊。攻擊者只要讓批次請求裡的第一筆子請求故意觸發特定錯誤,就能讓後面每一筆子請求的驗證與執行整個錯位:原本負責新增文章、不會檢查參數是不是陣列的處理器被拿去做驗證,實際執行的卻換成不需要登入、會把值一路送進 WP_Query 的查詢文章清單處理器。兩個漏洞疊在一起,一個完全沒有帳號的攻擊者只要發出一個 HTTP 請求,就能觸發 SQL injection,進而取得完整的程式碼執行權限。

漏洞公布沒幾天,這組攻擊鏈的概念驗證程式碼就流出到網路上;美國網路安全暨基礎設施安全局(CISA)已經把這兩個 CVE 編號都列進「已知被利用漏洞」(Known Exploited Vulnerabilities)目錄,證實真實環境裡已經有攻擊者主動利用。這件事值得記住的地方有 2 個:一是就算由專職安全團隊全職維護、每一行改動都要經過審查的 WordPress 核心,精心設計的輸入驗證仍然可能被另一個看似無關的邏輯錯誤繞過,這正是 SQL injection「防不勝防」名聲的來源;二是 WordPress 官方只有在極少數這種高風險情境下才會直接對網站強制推送更新,如果你的網站當時開著自動更新,這次事件對你來說可能完全無感。
外掛與佈景主題才是漏洞真正集中的破口
核心會出事,但真正該放在心上的破口其實不在核心。資安平台 Patchstack 發布的《State of WordPress Security in 2026》年度報告指出,2025 年 WordPress 生態圈總共新發現 11,334 個安全漏洞,其中 91% 出現在外掛,9% 出現在佈景主題,只有 6 個出現在 WordPress 核心本身,而且都被列為低風險等級。換句話說,你的網站如果真的中了 SQL injection,源頭幾乎肯定不是 WordPress 本身,而是你裝的某個外掛或佈景主題。
這個懸殊落差不是偶然,而是兩邊的把關機制天差地遠。WordPress 核心有官方專職安全團隊維護,每一次程式碼修改都要經過審查流程才能合併,上一節的 wp2shell 事件正好是這套流程的另一面,核心團隊在極短時間內就找出並修補了一組相當隱晦的漏洞鏈。反觀外掛與佈景主題,任何開發者都能把作品上架到 WordPress.org 官方目錄或其他第三方市場,並沒有強制的安全審查機制,品質自然參差不齊,有些出自經驗豐富的團隊、更新頻繁,有些則是個人開發者寫完就很少再回頭維護。
WordPress 核心其實已經把安全的路鋪好了。透過 $wpdb 類別提供的 $wpdb->insert()、$wpdb->update()、$wpdb->delete() 這些方法,官方會自動處理查詢的準備、跳脫與清理,大幅降低直接手寫 SQL 造成漏洞的機會。問題是這條路要外掛與佈景主題的開發者自己選擇去走,如果作者沒有使用這些內建工具,而是自己動手拼接 SQL 字串,等於主動繞過了 WordPress 核心原本就準備好的保護。
沒有用參數化查詢的外掛,是這類漏洞共同的技術根源
外掛品質參差不齊講起來抽象,實際上幾乎都指向同一件事,開發者沒有用 WordPress 提供的參數化查詢機制,這也是這類漏洞共同的技術根源。
參數化查詢(prepared statement)的原理其實不難懂。資料庫收到的第一步,只是一份只有指令骨架、資料要放的位置先用佔位符代表的查詢;等到指令的骨架都確定之後,才把使用者輸入的實際內容當成純資料綁定進去。這樣一來,資料庫從一開始就分得清楚這是要執行的指令、還是要處理的資料,就算使用者輸入裡混進了 SQL 的關鍵字,也只會被當成一串文字看待,不會被誤判成指令的一部分。OWASP 在其 SQL Injection 防禦指南裡,把這個方法列為預防 SQL injection 的第一優先防禦選項。
WordPress 官方把這套原理實作成 $wpdb->prepare() 這個方法,用 %s(字串)、%d(整數)、%f(浮點數)這些佔位符取代直接把變數拼進 SQL 字串的寫法,官方文件也明確要求,任何用 $wpdb->query() 執行的自訂查詢,都應該先經過 prepare() 處理。一段用 %d 佔位符查詢文章的寫法大致長這樣:
$wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE post_author = %d AND post_status = 'publish'",
$author_id
)
);Code language: PHP (php)
$author_id 不管使用者傳進來什麼內容,都會被當成整數處理,不會有機會被拼接成額外的 SQL 指令。

比較少被提到的是,WordPress 從 6.2 版起,$wpdb->prepare() 新增了 %i 這個識別碼專用佔位符,可以安全地把資料表名稱或欄位名稱這類過去沒辦法用一般佔位符參數化的部分也納入保護,%i 會自動用反引號把該值包起來。這正好解決了 OWASP Cheat Sheet 裡明講的老問題,遇到沒辦法用一般變數綁定的資料表名、欄位名、排序方向時,過去只能靠額外的輸入驗證或重新設計查詢來擋。多數中英文教學至今仍停留在講舊版的 %s/%d 用法,很少提到這個官方現在仍在建議使用的新工具。
真實世界的案例可以看得更清楚。CVE-2024-2879 是 WordPress 上熱門的滑動版面外掛 LayerSlider(累計安裝數超過 100 萬)在 7.9.11 與 7.10.0 版被發現的漏洞,出在處理 ls_get_popup_markup 這個 action 傳入的參數時跳脫不足,也沒有對既有 SQL 查詢做足夠的 prepare 處理,導致未經身份驗證的攻擊者能在既有查詢後面接上額外的 SQL 指令,取出資料庫裡的敏感資訊。這個漏洞的 CVSS 風險評分達到 7.5(滿分 10),已經在 LayerSlider 7.10.1 版修補。
另一個案例是 CVE-2026-1865,User Registration & Membership 外掛在 5.1.2 以下所有版本,因為對使用者透過 membership_ids[] 參數送入的值跳脫不足、既有 SQL 查詢同樣沒有做足夠的 prepare 處理,也構成 SQL injection 漏洞。攻擊者只需要最基本的訂閱者層級帳號權限,不需要跟其他使用者互動,就能觸發漏洞並讀取資料庫內容。2 個案例的共同點很清楚,問題都不在 WordPress 核心,而是外掛開發者自己動手寫 SQL 查詢時,沒有確實用 $wpdb->prepare() 把使用者輸入當成純資料處理,這正是上一節「外掛是最大破口」這個說法,在真實世界裡具體發生的樣子。
中招前常見的資料庫錯誤與陌生管理員帳號
網站是不是已經中招,其實不需要工程背景也能自己先抓出幾個跡象,越早發現、損害通常就越小。
第一個訊號是網站上突然冒出看起來像資料庫報錯的文字,句子裡提到 SQL 語法、資料表名稱這類陌生詞彙,代表可能有人正在嘗試、甚至已經成功讓惡意查詢碰到資料庫。第二個訊號是網站上出現你自己沒建立的內容或帳號:後台多出一個陌生的系統管理員、某個頁面內容被悄悄改掉、留言區冒出你從沒核准過的貼文。第三個訊號是網站忽然變慢或頻繁當機,惡意的 SQL 查詢,尤其是反覆猜測資料、或用 UNION 合併大量資料表的查詢,會消耗大量資料庫運算資源,嚴重時可能讓資料庫直接當掉。
聯絡表單跟彈窗這類跟資料庫互動頻繁的功能,也值得多留意:如果它們忽然無法正常送出、跳出你沒設定過的訊息,或載入速度明顯變慢,都可能是背後的查詢正在被異常存取,不一定只是外掛版本問題那麼單純。
看到任何一項跡象,先別急著猜是不是 SQL injection,但把它當成該回頭檢查的訊號,遠比放著不管來得安全。
非工程師站主也能做到的更新、外掛把關與最小權限
破口摸清楚了,接下來是實際能做的事,而且大多數不需要碰任何程式碼。
保持 WordPress 核心、佈景主題、所有外掛更新到最新版本,是最基本也最有效的一步。新版本通常已經包含已知安全漏洞的修補,前面提到的 LayerSlider 與 User Registration & Membership 案例,官方都是在新版本裡把漏洞補起來。WordPress 本身就內建可以開啟核心自動更新的設定,讓網站在背景自動裝上安全性更新,不用等你自己想起來手動點更新。前面 2026 年 7 月 wp2shell 事件也證明了這一點:官方在極高風險的狀況下會直接對受影響網站強制推送更新,如果自動更新本來就開著,等於少一層被攻擊的空窗期。
安裝任何新外掛之前,先做基本的把關:看它最近一次更新是什麼時候、有多少人在用、評分怎麼樣,優先選擇仍在積極維護、來自 WordPress.org 官方目錄或其他可信管道的外掛,避免裝那些長期沒更新、或來路不明(包括破解版、盜版)的外掛與佈景主題,這些往往是最容易被鑽的破口,也最沒人會去修。
在網站前面加一層 Web 應用防火牆(WAF),或安裝有防火牆功能的安全外掛,可以讓帶有 SQL injection 特徵的惡意請求在碰到網站程式之前就先被攔下來,等於在最外層多一道關卡,就算某個外掛本身有漏洞也不一定會被直接打中。
最後一件事容易被忽略,卻同樣重要,落實使用者角色的最小權限原則。只需要發文的人給 Author 角色就好,不要順手給 Administrator,並且定期清掉不再使用的帳號。這樣做不會讓 SQL injection 不發生,但萬一真的被突破,能造成的損害範圍會小很多。

外包或客製開發時,工程師該落實的參數化查詢與最小權限
如果你自己不寫程式,但有找廠商或工程師做客製功能、客製外掛,前面講的技術細節你不一定要親自懂,但可以直接拿去當成要求提出。
第一件事,要求工程師在任何會用使用者輸入組成資料庫查詢的地方,一律使用 $wpdb->prepare() 做參數化查詢,而不是直接把變數拼接進 SQL 字串裡,這本來就是 WordPress 官方文件明訂的寫法,不是額外加碼的要求。
第二件事比較少見,但真的會發生,如果客製功能牽涉到需要動態決定資料表名稱或欄位名稱,例如讓使用者自己選要匯出報表的哪個欄位,可以要求工程師改用 WordPress 從 6.2 版起提供的 %i 識別碼佔位符處理,不用另外自己寫一套白名單驗證邏輯來防呆,這個工具是官方現在仍在建議使用的做法。
第三件事跟程式碼本身無關,卻同樣重要,要求資料庫帳號本身的權限最小化。網站用來連線資料庫的那組帳號,只給它網站實際需要的操作權限,像是讀取、新增、更新資料,不要給刪除資料表、授權這類破壞性或管理性的權限,就算真的發生 SQL injection,攻擊者能造成的破壞也會被這道限制大幅縮小。
第四件事,上線前也可以要求做基本的安全掃描,確認表單、網址參數這類使用者輸入點沒有明顯的 SQL injection 破口。這是委外開發驗收時可以具體提出的要求,不需要指名任何特定廠商或工具,工程師聽得懂、也做得到。
SQL injection 能存在超過 20 年,不是因為防禦方法太難,而是因為它從來不是裝一個外掛就能一勞永逸解決的問題——核心有專職團隊都可能出現 wp2shell 這種漏洞鏈,何況是沒有強制安全審查的外掛與佈景主題。真正能降低風險的,往往是把更新開著、裝外掛前多看一眼、把權限收緊這幾件不起眼的小事,攻擊者最常撲空的地方也正是這裡。與其等到後台冒出陌生帳號才回頭查,現在花幾分鐘檢查一輪,才不會事後付出更大代價。
