首頁 > 軟體

專案中Nginx多級代理是如何獲取使用者端的真實IP地址

2022-05-27 14:04:20

多級代理中獲取使用者端真實IP

紀錄檔的格式

nginx中常用紀錄檔格式設定如下:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';
access_log  /var/log/nginx/access.log  main;

其中的main為紀錄檔格式的別名,在使用的時候直接使用別名即可。

例子:

10.0.3.137 - - [09/Oct/2020:09:41:02 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko" "10.1.9.98"
變數含義例子
$remote_addr使用者端的ip地址(直連的IP,代理伺服器,顯示代理服務ip)10.0.3.137
$remote_user用於記錄遠端使用者端的使用者名稱稱-
$time_local用於記錄存取時間和時區08/Oct/2020:02:37:25 -0400
$request用於記錄請求的url、請求方法,協定的版本GET / HTTP/1.1
$status響應狀態碼200
$body_bytes_sent給使用者端傳送的檔案主體內容位元組0
$http_referer可以記錄使用者是從哪個連結存取過來的-
$http_user_agent使用者所使用的代理(一般為瀏覽器)Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
$http_x_forwarded_for可以記錄使用者端IP和所有經過的代理伺服器的IP10.1.9.98

日積月累下,紀錄檔檔案會越來越大,紀錄檔檔案太大嚴重影響伺服器效率,所以需要定時對紀錄檔檔案進行切割。

由於這裡是演示,所以切割方式是按分鐘來切割,正常生產上使用一般是按天來進行分割:

#!/bin/bash
#紀錄檔檔案存放目錄
LOGS_PATH=/usr/local/nginx/logs
#備份檔名稱
YESTERDAY=$(date -d "yesterday" +%Y%m%d%H%M)
#重新命名紀錄檔檔案
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log
mv ${LOGS_PATH}/error.log ${LOGS_PATH}/error_${YESTERDAY}.log
## 向 Nginx 主程序傳送 USR1 訊號。USR1 訊號是重新開啟紀錄檔檔案
kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)

然後新增定時任務:

# crontab -e
*/1 * * * * /bin/bash /usr/local/nginx/logs/nginx_log.sh

獲取使用者端真實IP

伺服器資源分配情況如下:

  • 10.1.9.98:充當使用者端
  • 10.0.3.137:一級代理
  • 10.0.4.105:二級代理
  • 10.0.4.129:三級代理
  • 10.0.4.120:伺服器端,為了方便,這裡使用一個nginx充當伺服器端,正常情況下一般是一個web伺服器,如tomcat。

各個服務初始設定如下:

10.0.3.137的設定:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format main '$remote_addr - $http_x_forwarded_for - $http_x_real_ip';
    access_log  logs/access.log  main;
    server {
        listen  80;

        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.105;
        }
    }

}

10.0.4.105的設定,其他設定與10.0.3.137的一致:

...
        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.129;
        }
...

10.0.4.129的設定,其他設定與10.0.3.137的一致:

...
        location / {
                # proxy_set_header X-Real-IP $remote_addr;
                # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://10.0.4.120;
        }
...

10.0.4.120的設定,其他設定與10.0.3.137的一致

...
        location / {
                root html;
                index index.html;
        }
...

下面的記錄為access.log中列印的結果:

操作10.0.3.13710.0.4.10510.0.4.12910.0.4.120
10.1.9.98存取curl http://10.0.3.13710.1.9.98 - - - -10.0.3.137 - - - -10.0.4.105 - - - -10.0.4.129 - - - -
10.0.3.137開啟X-Forwarded-For10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - -10.0.4.105 - 10.1.9.98 - -10.0.4.129 - 10.1.9.98 - -
10.0.4.105開啟X-Forwarded-For10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - -10.0.4.105 - 10.1.9.98, 10.0.3.137 - -10.0.4.129 - 10.1.9.98, 10.0.3.137 - -
10.0.4.129開啟X-Forwarded-For10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - -10.0.4.105 - 10.1.9.98, 10.0.3.137 - -10.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - -
10.1.9.98偽造頭部存取curl http://10.0.3.137 -H ‘X-Forwarded-For: 1.1.1.1’10.1.9.98 - 1.1.1.1 - -10.0.3.137 - 1.1.1.1, 10.1.9.98 - -10.0.4.105 - 1.1.1.1, 10.1.9.98, 10.0.3.137 - -10.0.4.129 - 1.1.1.1, 10.1.9.98, 10.0.3.137, 10.0.4.105 - -
10.0.3.137開啟X-Real-IP10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - 10.1.9.9810.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.1.9.9810.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.1.9.98
10.0.4.105開啟X-Real-IP10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - 10.1.9.9810.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.13710.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.3.137
10.0.4.129開啟X-Real-IP10.1.9.98 - - - -10.0.3.137 - 10.1.9.98 - 10.1.9.9810.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.13710.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.4.105
10.1.9.98偽造頭部存取 curl http://10.0.3.137 -H ‘X-Real-IP: 8.8.8.8’10.1.9.98 - - - 8.8.8.810.0.3.137 - 10.1.9.98 - 10.1.9.9810.0.4.105 - 10.1.9.98, 10.0.3.137 - 10.0.3.13710.0.4.129 - 10.1.9.98, 10.0.3.137, 10.0.4.105 - 10.0.4.105

總結:

  • X-Forwarded-For是一個追加的過程,後面的代理會把前面代理的IP追加到X-Forwarded-For尾部,用逗號進行分隔。
  • 應用伺服器(10.0.4.120)無法從X-Forwarded-For中獲取到與它直連的代理伺服器的IP(10.0.4.129),此時我們可以使用r e m o t e a d d r ( 遠 程 i p , 表 示 直 連 的 那 臺 代 理 ) 。 當 服 務 器 無 法 過 remote_addr(遠端ip,表示直連的那臺代理)。當伺服器無法過remote addr(遠端ip,表示直連的那臺代理)。當伺服器無法過http_x_forwarded_for獲得上級代理或者使用者端的ip時(可能沒有經過代理),應該使用$remote_addr。
  • 在代理過程中至少有一個代理設定了X-Forwarded-For,否則後面的代理或者應用伺服器無法獲得相關資訊。
  • X-Forwarded-For中雖然包含了真實的使用者端IP,一般是第一個IP,但是如果使用者端偽造了請求頭,那麼真實的使用者端IP就不是第一個了。
  • HTTP中header裡面的X-Real-IP只是一個變數,後面的設定會覆蓋前面的設定,所以只需要在第一個代理伺服器上設定proxy_set_header X-Real-IP $remote_addr即可,然後在應用端直接參照$http_x_real_ip就行。

在java中,如果請求沒有經過nginx代理,可以使用如下方法獲取使用者端的真實IP:

# 類似nginx中的$remote_addr
request.getRemoteHost();

如果請求經過了nginx代理,可以從請求頭中獲取(前提是必須正確設定nginx才能獲取到):

request.getHeader("x-real-ip");

如果是用的其他Apache,Squid等反向代理軟體,同樣是從請求頭中獲取真實IP,只是屬性名不一樣而已。

到此這篇關於專案中Nginx多級代理是如何獲取使用者端的真實IP地址的文章就介紹到這了,更多相關Nginx多級代理獲取使用者端真實IP內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com