獲取請求來源 IP 地址

IP 追溯主要用於獲取請求的真實 IP ,因爲現有服務是基於 Nginx 實現負載均衡的,所以獲取請求真實 IP 存在必定難度。在 Matrix 現有實現中,IP 追溯由 getIp 函數完成,其具體代碼以下。javascript

/** * 得到請求發送方的 ip * @param {Context} ctx * @return {string} */
export function getIp(ctx) {
  const xRealIp = ctx.get('X-Real-Ip');
  const { ip } = ctx;
  const { remoteAddress } = ctx.req.connection;
  return xRealIp || ip || remoteAddress;
}
複製代碼

在對代碼進行更爲詳細的討論以前,咱們須要分析幾種經常使用獲取請求 IP 來源的方式:html

  • req.socket.remoteAddress
  • X-Forwarded-For
  • X-Real-IP

req.socket.remoteAddress

在 Node.js 官方文檔 net_socket_remoteaddress 中,咱們得知可經過 req.socket.remtoeAddress 獲取 Socket 鏈接的源 IP 地址信息。java

socket.remoteAddress

Added in: v0.5.10node

  • String

The string representation of the remote IP address. For example, '74.125.127.100' or '2001:4860:a005::68'. Value may be undefined if the socket is destroyed (for example, if the client disconnected).nginx

根據官方文檔 http_request_socket 的描述,req.connectionreq.socket 是等價的,咱們也能夠經過 req.connection.remoteAddress 獲取 Socket 鏈接的源 IP 信息。這種獲取請求 IP 來源的方式,適用於客戶端直連服務端的場景。git

但因爲現有 Matrix 服務使用了 Nginx 做爲服務集羣的負載均衡,故經過 req.socket.connection 獲取獲得的是 Nginx 的 IP 地址,並非請求的真實 IP 地址。github

X-Forwarded-For

根據 RFC 7239 規範,HTTP 代理(如 Nginx、Apache 等)會改寫 HTTP 請求頭部,添加 X-Forwarded-For 字段,用於追蹤請求的來源,該字段的格式以下:api

X-Forwarded-For: client, proxy1, proxy2
複製代碼

下面對 X-Forwarded-For 字段的處理過程,進行詳細闡述:瀏覽器

  • 客戶端(如瀏覽器)在發送 HTTP 請求時,默認是不帶 X-Forwarded-For 字段。
  • 當請求到達第一個 HTTP 代理服務器時,代理服務器根據 RFC 7239 規範,爲請求頭部添加 X-Forwared-For 字段,而且將值設置爲客戶端的 IP 地址
  • 若後面存在多個 HTTP 代理(即請求在後續會依次被多個 HTTP 代理處理),則每一個代理都會在 X-Forwarded-For 字段值中追加上一代理的 IP 地址
  • 在業務服務器中,咱們可經過 X-Forwarded-For 值的最左邊的 IP 地址獲取客戶端的 IP 地址。

但遺憾的是,X-Forwarded-For可僞造的:若是客戶端在發起 HTTP 請求時,設置了僞造的 X-Forwarded-For 字段,因爲後續的每層代理只會追加此字段而不會覆蓋,故業務服務器最終獲取的客戶端 IP 地址多是客戶端僞造的地址。安全

一般,咱們須要進行額外的配置,才能使得 Nginx 支持 X-Forwarded-For

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
複製代碼

X-Real-IP

HTTP 代理服務器可在請求頭部中設置 X-Real-IP 請求源信息,但這並非 RFC 規範中的內容

X-Real-IP客戶端不可僞造的,但僅能描述最近一個代理的真實 IP ,若是有多層代理,其仍舊不可做爲客戶端請求的真實 IP 。在現實生活中,多層代理實際上是比較少見的,常見的是單層代理,所以在一般狀況下,使用 X-Real-IP 是足以完成任務的,且相對於 X-Forwarded-For 有更好的安全性。

咱們可經過如下設置,使得 Nginx 支持 X-Real-IP 字段的自動設置。

proxy_set_header X-Real-IP $remote_addr;
複製代碼

幾種方式的對比

如下是我對幾種獲取客戶端真實 IP 的方式的總結,分析了各方式的侷限和應用場景。

req.socket.remoteAddress X-Forwarded-For X-Real-IP
是否可僞造
有效性 僅在客戶端直連服務端時 僅在未僞造時 僅在客戶端未通過多級代理時

參考資料

相關文章
相關標籤/搜索