1. 程式人生 > >HTTP 請求頭中的 X-Forwarded-For,X-Real-IP

HTTP 請求頭中的 X-Forwarded-For,X-Real-IP

進行 gnu 防止 cal 截取 雲服務器 sta 分配 wow

X-Forwarded-For


在使用nginx做反向代理時,我們為了記錄整個的代理過程,我們往往會在配置文件中做如下配置:

location / {
       省略...
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://1xx.xxx.xxx.xxx;
    
    }
            

紅色部分就是為了記錄代理過程做的配置,在http header中添加代理的信息,我們可以把X-Forwarded-For當成http擴展頭,其格式一般為:

X-Forwarded-For:192.168.247.1, 192.168.247.131, 192.168.247.132

註意,引用X-Forwarded-For時要這樣$http_x_forwarded_for

做一下測試


1.我們測試一下請求經過三層代理的情況,測試設備分配:

  • win10 一臺
  • 運行在win10上的虛擬機centos5.8,ip:192.168.247.131,一級代理
  • 運行在win10上的虛擬機centos6-1, ip:192.168.247.132 ,二級代理
  • 運行在win10上的虛擬機centos6-2, ip:192.168.247.133 ,三級代理

  • 雲服務器,應用服務器

技術分享

2.測試環境配置:

  • win10 在/etc/hosts文件中添加192.168.247.131 http://test.proxy.com
  • centos5.8,ip:192.168.247.131,安裝nginx,把所有請求轉發到192.168.247.132
  • centos6-1, ip:192.168.247.132安裝nginx,把所有請求轉發到192.168.247.133
  • centos6-2, ip:192.168.247.133,安裝nginx,把所有請求轉發到雲服務器
  • 在雲服務器上的日誌中打印http header中的X-Forwarded-For
    信息
  • 防火墻可以關閉掉,防止win10請求無法進入代理鏈

3.nginx配置文件

#centos5.8,ip:192.168.247.131 ,nginx.conf
location / { root html; index index.html index.htm index.php;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X
-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.247.132; }
#centos6-1,ip:192.168.247.132 ,nginx.conf

    location / {
      root   html;
      index  index.html index.htm index.php;
#proxy_set_header X-Real-IP $remote_addr; proxy_set_header X
-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.247.133; } #centos6-2,ip:192.168.247.133 ,nginx.conf location / {
        root   html;
        index  index.html index.htm index.php;  
#
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://123.206.96.111; }


#雲服務器方便起見在日誌中設置打印$http_x_forwarded_for,進行觀察
log_format main ‘$http_x_forwarded_for|$http_x_real_ip|$remote_addr - $remote_user [$time_local] "$request" ‘
‘$status $body_bytes_sent "$http_referer" ‘
‘"$http_user_agent" "$http_x_forwarded_for"‘;

4.基於上面的配置在win10瀏覽器輸入:"http://test.proxy.com" 查看雲服務器日誌打印結果如下:

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:18:20:27 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

192.168.247.1, 192.168.247.131, 192.168.247.132$http_x_forwarded_for內容,顯然記錄了代理過程,其中192.168.247.1是客戶端ip
192.168.247.1 為基於上述設置的真實IP(不一定準確)

101.254.182.6 公網IP


作為重度強迫癥患者,測試到這裏可不是我的風格.....

我們要仔細測試一下在不同代理服務器設置X-FORWARDED-FOR在應用服務器拿到的$http_x_forwarded_for有何不同

1.只在proxy01設置X-FORWARDED-FOR, 在proxy02,proxy03配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.1|192.168.247.1|101.254.182.6 - - [22/May/2017:18:52:49 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1"
2.只在proxy02設置X-FORWARDED-FOR, 在proxy01,proxy03配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.131|192.168.247.1|101.254.182.6 - - [22/May/2017:18:59:59 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.131"
3.只在proxy03設置X-FORWARDED-FOR, 在proxy01,proxy02配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:01:27 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.132"
4.只在proxy01,proxy03設置X-FORWARDED-FOR, 在proxy02配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.1, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:05:49 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.132"
5.只在proxy02,proxy03設置X-FORWARDED-FOR, 在proxy01配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:08:39 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.131, 192.168.247.132"
6.只在proxy01,proxy02設置X-FORWARDED-FOR, 在proxy03配置文件中註釋掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
192.168.247.1, 192.168.247.131|192.168.247.1|101.254.182.6 - - [22/May/2017:19:10:40 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131"

小結:

1.通過以上幾種情況我們可以了解到設置X-Forwarded-For是一個可疊加的過程,後面的代理會把前面代理的IP加入X-Forwarded-For,類似於python的列表append的作用.

2.我們看到在三層代理情況下無論如何設置,應用服務器不可能從$http_x_forwarded_for拿到與它直連的這臺服務器的ip(proxy03 ip),此時我們可以使用$remote_addr(遠程ip,表示直連的那臺代理).一句話,當前服務器無法通過$http_x_forwarded_for獲得上級代理或者客戶端的ip,應該使用$remote_addr.

3.在代理過程中至少有一個代理設置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;否則後面代理或者應用服務器無法獲得相關信息.

4.註意,應用服務器可以通過$proxy_add_x_forwarded_for客戶端IP(只要至少proxy01代理設置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;我們取第一IP就好了),但是我們要考慮客戶端偽造頭部的情況,如下示例:

假設我們在所有代理都加上了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;然後我們在proxy01機器上本機curl代替win10模擬一個客戶端請求,

在proxy01上執行: curl localhost/admin -H ‘X-Forwarded-For: 1.1.1.1‘ -H ‘X-Real-IP: 2.2.2.2‘

1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132|127.0.0.1|101.254.182.6 - - [23/May/2017:11:02:09 +0800] "GET /admin HTTP/1.0" 301 263 "-" "curl/7.15.5 (i386-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132"

可以看到,1.1.1.1放到了最前面,所以我們不能夠想當然的去取第一個ip作為客戶端的這是IP.這裏127.0.0.1是真實IP.

5.雖然X-Forwarded-For可以偽造,但是對我們依然有用,比如我們就從proxy01代理往後截取就行了,這樣就能做到直接忽視偽造得IP.

X-Real-IP


下面我們看一下有多級代理存在時如何獲取客戶端真實IP.

首先要明確在header裏面的 X-Real-IP只是一個變量,後面的設置會覆蓋前面的設置(跟X-Forwarded-For的追加特性區別明顯),所以我們一般只在第一個代理設置proxy_set_header X-Real-IP $remote_addr;就好了,然後再應用端直接引用$http_x_real_ip就行.

1.假如我們只在proxy01設置了 X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [23/May/2017:11:23:00 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

2.假如我們只在proxy02設置了X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:26:22 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

3.假如我們只在proxy03設置了X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.132|101.254.182.6 - - [23/May/2017:11:27:21 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

4.所有代理都設置X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.132|101.254.182.6 - - [23/May/2017:11:29:09 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

5.強迫癥來了,再試一個只設置proxy01,proxy02的看看

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:30:36 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

假如有人假冒X-Real-IP呢?

6. 在proxy01上執行: curl localhost/admin -H ‘X-Forwarded-For: 1.1.1.1‘ -H ‘X-Real-IP: xx.xx.xx.xx‘

1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:36:02 +0800] "GET /admin HTTP/1.0" 301 263 "-" "curl/7.15.5 (i386-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132"

並沒有影響.

IT‘S OVER.

HTTP 請求頭中的 X-Forwarded-For,X-Real-IP