初學者指南:如何從請求中抓取對方的 IP 位址

更新日期: 2025 年 5 月 27 日

在開發 Web 應用程式或 API 時,有時你會需要知道用戶的 真實 IP 位址,例如:

  • 做日誌紀錄(Logging)
  • 限制某些地區存取
  • 防止 DDoS 或濫用攻擊
  • 建立地理位置分析

但在現代 Web 架構中(尤其是使用了代理伺服器、CDN 或反向代理時),抓 IP 並不是一件直觀的事。

本篇文章將一步步帶你了解如何正確從請求中抓出對方的 IP 位址。

什麼是用戶 IP?為什麼要特別抓?

什麼是「用戶 IP」?

IP(Internet Protocol)位址是網路中識別每個裝置的唯一代碼,就像住家的地址一樣,讓資料能正確傳送到對方。

在 Web 應用中,每當一位使用者打開網站、發送請求到伺服器,這個請求都會包含該使用者裝置的「來源 IP 位址」。

例如,一位使用者從筆電連上網站,他的請求中可能會帶有這樣的 IP:

203.0.113.45

這個 IP 就是你伺服器收到請求時,判斷對方是誰的依據之一。

為什麼我們要抓用戶的 IP?

抓取使用者 IP 可以幫助你:

  1. 做日誌紀錄(Logging):讓你知道是哪個 IP 發出的請求,便於錯誤追蹤與系統監控。
  2. 分析用戶行為與分布:例如統計不同地區的訪問量。
  3. 實作權限控制或封鎖名單:例如防止特定 IP 的攻擊或濫用。
  4. 防止作弊、重複操作:像是防止某人用機器重複填寫表單、投票等。
  5. 進行地理定位(Geo IP):根據 IP 判斷用戶可能來自哪個國家或城市,提供更符合在地需求的內容。

為什麼不是直接拿 req.ip 就好?

理論上,Web 伺服器會根據用戶的 TCP 連線,自動知道對方的 IP,你甚至可以透過像是 req.ip(Express)、request.connection.remoteAddress(Node.js 原生)直接拿到。

但在現實中,我們的伺服器通常 不是直接面對用戶,而是架設在以下這些結構中:

  • Nginx、Apache 等反向代理伺服器
  • CDN 服務(如 Cloudflare)
  • 雲端負載平衡器(如 AWS Load Balancer)
  • PaaS 平台(如 Heroku、Vercel)

這些架構會「幫你先接住使用者的請求」,然後再「轉送」給你的應用伺服器。這麼一轉,原本的來源 IP 就會被蓋掉,變成中介平台的 IP。

例如你抓到的可能是:

10.0.0.1

這是 AWS 的內部 IP,根本不是使用者的真實 IP。你就失去了上面所說的用途(風控、定位、追蹤等)。

解法:改從「請求標頭」抓 IP

為了讓你還是能知道「原本的用戶 IP 是誰」,這些中介層會在轉送請求時加上一些特殊的 HTTP Header(請求標頭),像是:

  • X-Forwarded-For
  • x-original-ip
  • x-real-ip

這些標頭會包含原始使用者的 IP。你的伺服器只要判斷這些標頭的值,就可以取得對方真正的 IP。

小結

概念說明
使用者 IP網路上辨識用戶裝置的代碼,會夾帶在請求中
直接取得 IP 的風險代理/CDN 會蓋掉真實 IP,導致抓不到
解法從標頭(Header)中抓出中介層補上的原始 IP

只要你了解這些基礎概念,就能在不同的 Web 架構中,正確、安全地取得用戶 IP,不怕資料錯誤、日誌無效、風控失靈。

常見的 IP 標頭介紹

在使用代理伺服器(Proxy)、CDN 或負載平衡器的環境中,直接從伺服器的連線資訊取得的 IP(如 req.socket.remoteAddress)通常是中介伺服器的 IP,而不是用戶端的真實 IP。

為了解決這個問題,這些中介系統會幫你在 HTTP 請求中加入一些標頭(Header),記錄原始用戶的 IP。

以下是幾個最常見、最實用的 IP 標頭介紹與使用建議。

X-Forwarded-For:最常見、最重要

這是目前業界最常用的標頭,用於記錄整條代理鏈上的 IP 位址:

X-Forwarded-For: 203.0.113.45, 70.41.3.18, 150.172.238.178
  • 第一個 IP(最左邊)是使用者最初的真實 IP。
  • 後面的 IP 則是請求經過的每個代理伺服器所加入的,從左到右依序排列

🧠 範例解析:

X-Forwarded-For: 客戶端IP, 第一層代理IP, 第二層代理IP

實務使用建議

只要抓第一個 IP 通常就是用戶端的真實 IP:

const realIp = req.headers['x-forwarded-for']?.split(',')[0].trim();

⚠️ 注意:

  • 如果代理鏈中的某個節點沒處理好或惡意竄改,也可能導致 IP 被偽造。
  • 建議搭配可信任代理的設定(如 Express 中 app.set('trust proxy', true))使用。

x-original-ip:次常見,平台依賴性高

這個標頭並不是業界標準,但在某些特定環境中會出現,例如:

  • Microsoft Azure Application Gateway
  • 自建代理伺服器(有些會自己加上這個欄位)
x-original-ip: 203.0.113.45

特點:

  • 通常只會包含單一 IP
  • 如果你無法取得 X-Forwarded-For,這是個不錯的備援來源

✅ 建議:可以列為備用方案,例如:

const ip = req.headers['x-forwarded-for']?.split(',')[0].trim()
         || req.headers['x-original-ip']
         || req.socket.remoteAddress;

其他常見 IP 標頭

📌 X-Real-IP

  • 常見於 Nginx 或其他自訂代理伺服器
  • 通常只會傳送一個 IP(即使用者原始 IP)
X-Real-IP: 203.0.113.45

✅ 適用於你知道請求只經過單層代理時,例如你只用一層 Nginx 當作反向代理。

📌 CF-Connecting-IP

  • Cloudflare 專屬標頭,只會有一個 IP
  • 如果你用 Cloudflare,這是最可靠的來源
CF-Connecting-IP: 203.0.113.45

✅ 建議 Cloudflare 環境下優先採用,避免從 X-Forwarded-For 中誤抓到 Cloudflare 的節點 IP。

📌 True-Client-IP

  • Akamai CDN 專屬標頭
  • 原理與 CF-Connecting-IP 相同
True-Client-IP: 203.0.113.45

✅ 僅在你使用 Akamai 服務時才會出現,可優先參考。

📌 Forwarded

  • RFC 7239 定義的標準化格式
  • 支援記錄更多資訊,例如協定、代理等
Forwarded: for=203.0.113.45; proto=https; by=203.0.113.1

✅ 優點是格式嚴謹,可機器可讀
⚠️ 缺點是支援的系統還不普及,實務上還不常見。

補充:哪個 IP 標頭該優先讀取?

你可以設計一個順序邏輯來取得 IP:

function getClientIp(req) {
  return req.headers['x-forwarded-for']?.split(',')[0].trim()
      || req.headers['cf-connecting-ip']
      || req.headers['true-client-ip']
      || req.headers['x-original-ip']
      || req.headers['x-real-ip']
      || req.socket.remoteAddress;
}

這樣設計的好處:

  • 相容多種平台(Cloudflare、Nginx、Azure 等)
  • 保留備援機制,不怕某個標頭缺失

小結

Header 名稱適用情境是否標準
X-Forwarded-For通用、最常見✅ 非正式業界慣例
x-original-ipAzure、自建代理❌ 非標準
X-Real-IPNginx❌ 非標準
CF-Connecting-IPCloudflare❌ 平台專屬
True-Client-IPAkamai❌ 平台專屬
ForwardedRFC 標準格式✅ 標準

📌 提醒:HTTP 標頭容易被偽造,所以這些資訊僅適用於日誌、分析或非關鍵用途,不建議用來做嚴格的身份認證依據。

程式實作範例(Node.js)

以 Express 框架為例:

function getClientIp(req) {
  const xForwardedFor = req.headers['x-forwarded-for'];
  if (xForwardedFor) {
    return xForwardedFor.split(',')[0].trim();
  }

  const xOriginalIp = req.headers['x-original-ip'];
  if (xOriginalIp) {
    return xOriginalIp;
  }

  const xRealIp = req.headers['x-real-ip'];
  if (xRealIp) {
    return xRealIp;
  }

  return req.socket.remoteAddress;
}

安全性注意事項

即使我們能從各種標頭中取得使用者 IP,但在實務上有許多安全風險需要特別注意,否則你可能會誤信錯誤的資訊、導致 安全漏洞錯誤判斷

以下是三個最關鍵的注意事項:

HTTP Header 可以被偽造

所有的 HTTP 標頭(Header)本質上都是 純文字資料,在發送請求的時候,任何客戶端都能任意添加或修改

舉例來說,使用者可以在瀏覽器的開發者工具中、或透過 curl/Postman 發送這樣的請求:

GET /api/sensitive-data HTTP/1.1
Host: example.com
X-Forwarded-For: 1.2.3.4

這樣你伺服器讀到的 IP 就會是 1.2.3.4,但事實上這根本不是用戶的真實 IP,而是他自己「聲稱」的 IP。

🚨 結論:

  • 永遠不要把 IP 當作身份驗證依據
  • 如果你在做登入白名單、敏感權限判斷時使用 IP,需要搭配其他驗證機制(如 Token、帳號系統)

需要搭配可信任的 Proxy 設定

如果你的應用程式部署在像是:

  • Nginx → Node.js
  • Heroku、Vercel、Cloudflare → Express
  • AWS Load Balancer → EC2

這些都是「代理層轉發請求」的典型案例。

在這種情況下,你的應用程式需要明確告訴框架:「我信任這個代理,請從標頭中取回真實 IP」。

✅ Express 框架的做法:

app.set('trust proxy', true);

這一行的意思是:當我讀取 req.ip 時,Express 會自動幫你從 X-Forwarded-For 取第一個 IP,而不是使用 socket 的連線 IP。

⚠️ 如果你沒設定這一行,你可能會一直讀到錯誤的 IP,例如:

  • Cloudflare 的 IP
  • AWS 內網 IP(10.0.x.x)

使用 HTTPS 保護資料完整性

在 HTTP(非加密)傳輸中,請求內容很容易被竄改。舉例:

  • 內部網路攻擊者可以攔截並修改 X-Forwarded-For 的內容
  • 這會導致你的伺服器讀到錯誤的 IP,進而做出錯誤判斷(如放行不該放行的請求)

因此,在實際部署時,請務必使用 HTTPS,這樣可以:

  • 確保請求內容在傳輸過程中不被第三方竄改
  • 增加整體通訊的可信任程度

✅ 實務上,大多數現代雲平台(如 Heroku、Vercel、Cloudflare)都已預設使用 HTTPS,但若你自行部署伺服器(例如用 Nginx + Node.js),則需要自行配置 SSL 憑證。

快速總結:如何取得使用者 IP?

當你需要從一個請求中正確地判斷使用者的來源 IP,建議按照以下優先順序依序嘗試:

  1. X-Forwarded-For
  • 業界最通用的標頭,包含完整代理鏈,取第一個 IP 即為用戶 IP
  1. x-original-ip
  • 某些平台(如 Azure)專用,可做為備援
  1. x-real-ip
  • 常見於 Nginx 的簡化標頭
  1. req.socket.remoteAddress
  • 最後手段,僅適用於沒有經過代理伺服器的情況

範例實作(Node.js Express):

function getClientIp(req) {
  return req.headers['x-forwarded-for']?.split(',')[0].trim()
      || req.headers['x-original-ip']
      || req.headers['x-real-ip']
      || req.socket.remoteAddress;
}

結語:IP 是有風險的參考資訊

抓取使用者 IP 是許多應用的基本需求,無論是日誌、分析、風控還是地理判斷。

但在現代架構中(尤其是有代理、CDN、平台中介的情況下),這件事遠比想像中複雜。

請記住:

  • IP 不是安全機制,只是輔助資訊
  • 對於 IP 的取得與解析,一定要考慮環境(有無代理?用的是哪一層?)
  • 搭配框架正確設置、平台文件閱讀、HTTPS 使用,才是穩健解法

💡 小提示:若你用的是 Cloudflare、Heroku、Vercel 等平台,建議參考他們的官方文檔來決定使用哪一個標頭。

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *