Nginx

不知道中間代理 IP 地址時使用 Nginx real_ip

  • October 25, 2021

Nginx 的real_ip 模組允許您$remote_addr根據特定標頭欄位中發送的值設置變數。它對header有特殊的理解,X-Forwarded-For能夠將header中最右邊的untrusted值作為連接IP地址。

我想使用 real_ip 模組來設置$remote_addr連接 IP 地址。**我遇到的問題是我知道從末尾返回多少跳X-Forwarded-For,但不知道中間代理的 IP 地址。**據我了解,這意味著我不能set_real_ip_from用來指定代理的 IP 地址。

我想要做的是配置 nginx 選擇列表中倒數第二個地址作為$remote_addr. 似乎 real_ip 模組僅在您擁有知道代理 IP 地址的基礎架構時才有效。

有沒有辦法用 real_ip 模組做到這一點?我已經制定了一個基於正則表達式的解決方案,但如果可能的話,我更願意使用 real_ip 模組。

我不認為這是nginx real_ip_header 的欺騙,而 X-Forwarded-For 似乎是錯誤的或類似的問題。重申問題:

  • 我知道連接IP地址從末端有多少跳。
  • 不知道連接 IP 和我的伺服器之間的中間代理的可信 IP 地址,所以我不能使用set_real_ip_from.

有關細節的更多詳細資訊:

我在 Google Cloud HTTP 負載均衡器後面的 Google Cloud 中執行 nginx。Google Cloud使用X-Forwarded-For頭指示 Google Cloud 網路的入口點。我知道X-Forwarded-For列表中倒數第二個值是我想要的值,但我不知道最後一個值(代理)的 IP 地址是什麼。即使我可以為代理列舉所有 Google Cloud 的地址空間(沒有指定 GCLB 僅在 GCP 的地址空間內執行),這也會為任何其他可以在該地址空間內獲取伺服器的使用者打開它。

我最終使用了基於正則表達式的版本。從我的 nginx 配置中:

http {
   # Regexes are:
   # (?<connecting_ip>\d+\.\d+\.\d+\.\d+), (?<proxy_ip>\d+\.\d+\.\d+\.\d+)$ # IPv4 only
   # (?<connecting_ip_x>[0-9a-f:.]+),\s*(?<proxy_ip>[0-9a-f:.]+)$ # IPv6 and IPv4, and more robust
   #
   # The last IP address is the one from the GCP front end load balancer
   # The second to last IP address in the list is the connecting IP address (i.e. user IP address)
   # We capture both of them. X-Forwarded-For is separated by commas, hopefully whitespace as well
   # but we don't want to trust that too much.
   #
   # Note that ~ at the start of the string in Nginx marks it as a regex. It's not part
   # of the regex.
   #
   # Test cases for regex101
   # 1.1.1.1, 2.2.2.2
   # 1.1.1.1, 2.2.2.2, 3.3.3.3
   # 1.1.1.1
   # ::ffff:130.211.1.102, 2.2.2.2
   # 2001:0db8:85a3:0000:0000:8a2e:0370:7334, 2.2.2.2
   # 2001:41d0:8:e8ad::1, 2600:1901:0:2ad2::
   # 1.1.1.1,2.2.2.2,3.3.3.3
   #
   # It would be better to use the real_ip module, if that is possible
   # https://serverfault.com/q/947835/334330 might get answered for this.


   # Get the IP address of the connecting IP. If we get a direct connection from
   # GCP's health checkers, there won't be an X-Forwarded-For header. We shouldn't
   # be getting any direct connections from other sources without XFF header.
   map $http_x_forwarded_for $connecting_ip {
       # Capture the proxy IP and connecting_ip_x, then assign the connecting_ip_x
       "~(?<connecting_ip_x>[0-9a-f:.]+),\s*(?<proxy_ip>[0-9a-f:.]+)$" $connecting_ip_x;
       default               $remote_addr;
   }
 # ...
}

然後我在我的伺服器定義中使用 $connecting_ip :

server {
 # ...
 location / {
   proxy_set_header X-Real-IP $connecting_ip;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header Host $http_host;
   proxy_set_header X-Forwarded-Host "";
   proxy_redirect off;
   proxy_next_upstream error;
 }
}

引用自:https://serverfault.com/questions/947835