iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Software Development

一套真實運作中的 Laravel 系統,拆解它的原生機制系列 第 23 篇

Day 23:Trusted Proxies——Docker 環境下抓不到真實 IP 的坑

  • 分享至 

  • xImage
  •  

前言:「為什麼後台記錄的操作 IP 全部都一樣?」

「日誌裡怎麼每一筆操作紀錄的 IP 都長一樣?是不是全公司只有一個人在用系統?」

如果你的 Laravel 專案跑在 Docker、後面又有一層反向代理(Nginx、負載平衡器之類),這個問題的答案很可能不是「真的只有一個人在用」,而是應用程式從頭到尾都沒有拿到使用者的真實 IP,看到的永遠是反向代理自己的 IP。今天要講的就是這個坑,以及它怎麼被修好的。

今日目標

  • 理解為什麼 Docker + 反向代理架構下,取得真實 IP 沒有想像中直覺
  • 認識 Laravel 的 TrustProxies middleware 在解決什麼問題
  • 看一個真實案例:白名單信任特定網段,在 Docker 環境下失效
  • 理解「信任所有代理」這個寫法的安全前提是什麼,不能照抄就用

本文主體

問題:request 看到的 IP,不一定是真實使用者的 IP

HTTP 請求經過反向代理轉發時,應用程式收到的連線來源,技術上是反向代理的 IP,不是使用者瀏覽器發出請求的那個 IP。為了解決這個問題,反向代理通常會把使用者的真實 IP 塞進一個標頭(最常見的是 X-Forwarded-For),但應用程式預設不會自動信任這個標頭——原因很直接:如果隨便相信一個 HTTP 標頭裡宣稱的 IP,任何人都可以自己在請求裡加一個假的 X-Forwarded-For,偽裝成任何 IP。

所以 Laravel 提供了 TrustProxies 這個 middleware:明確告訴框架「只信任從這些特定 IP/網段送來的 X-Forwarded-For 標頭」,其他來源的偽造標頭一律忽略。

真實案例:白名單網段,在 Docker 環境下失效

這個系列的素材專案裡,bootstrap/app.php 原本的設定是這樣:明確列出幾個信任的網段——通常是內網網段跟反向代理本身的固定 IP。這個設定在一般的雲端主機部署裡運作得很好:反向代理的 IP 是固定的,寫死在白名單裡剛好對得上。

但換到 Docker 環境之後,這個假設不再成立。Docker 容器之間的網路是動態配置的——每次容器重啟,內部的 IP 位址都可能不一樣,反向代理容器實際連進應用程式容器的來源 IP,跟白名單裡寫死的那個 IP 對不上。結果就是:TrustProxies middleware 判定「這個標頭不是從信任的來源送來的」,直接忽略掉 X-Forwarded-For,應用程式看到的永遠是 Docker 內部網路裡那個變動的來源 IP——難怪日誌裡的操作 IP 看起來都長得差不多,甚至完全一樣。

修法是把白名單改成信任「所有」代理來源。用一組對照來看這個差異:

❌ 白名單信任特定網段(在傳統主機部署下沒問題)
$middleware->trustProxies(at: ['192.168.0.0/16', '固定IP/24']);
→ Docker 環境下容器間 IP 動態配置,
  反向代理的實際來源 IP 常常對不上白名單,
  導致 X-Forwarded-For 被忽略,永遠拿不到真實 IP

✅ 信任所有代理來源
$middleware->trustProxies(at: '*');
→ 不管反向代理的來源 IP 是什麼,都信任它宣稱的
  X-Forwarded-For,正確還原出使用者真實 IP

「信任所有代理」不是萬用解法,前提要成立

看到這裡,可能會有一個疑問:一開始不就是因為「不能隨便信任標頭裡宣稱的 IP」才需要白名單嗎?現在直接改成「信任所有」,不就繞回原本要防的問題了嗎?

答案是:這個寫法能安全成立,前提是應用程式本身不會被外部直接連到——也就是說,前面一定要有一層真正可信的反向代理或負載平衡器擋著,外部流量沒辦法繞過這層代理、直接對應用程式容器發出偽造的 X-Forwarded-For。在容器化部署裡,這通常靠網路層的隔離來保證(應用程式容器不對外開放連接埠,只有反向代理能連到它)。

如果你的應用程式本身就是直接暴露在公開網路上、沒有反向代理擋在前面,那麼「信任所有代理」這個設定會讓任何人都能透過偽造標頭來假冒任意 IP——這時候該做的不是複製這個修法,而是先確認自己的部署架構有沒有那層可信的邊界。

今日思考題

如果你的專案也跑在容器化環境、後面有反向代理,回想一下:你上一次檢查系統記錄的操作 IP,是不是真的驗證過那是使用者的真實 IP,還是其實一直都是同一個內部網路位址,只是沒有人發現?

今日重點回顧

  • Docker + 反向代理架構下,應用程式收到的連線來源不是使用者真實 IP,需要靠 X-Forwarded-For 標頭還原
  • Laravel 的 TrustProxies middleware 決定要不要信任這個標頭,避免被偽造的標頭欺騙
  • 真實案例:白名單信任固定網段,在 Docker 動態 IP 環境下失效,導致真實 IP 一直拿不到
  • 「信任所有代理」這個修法能安全成立,前提是應用程式前面真的有一層可信的邊界擋著,不能無條件照抄

明日預告

明天要看兩支輕量但用途完全不同的 middleware——一支只是加一個安全性標頭,另一支則是把「依網域判斷該不該重導」這種業務邏輯放進了路由層。middleware 能做的事,比很多人以為的更廣。


上一篇
Day 22:檔案上傳安全——一次真實資安事件後,才補上的 webshell 防護
下一篇
Day 24:Middleware 實戰——CSP header 跟業務導流邏輯,兩種輕量 middleware 長什麼樣
系列文
一套真實運作中的 Laravel 系統,拆解它的原生機制 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言