客戶端直接訪問後端伺服器時,$_SERVER['REMOTE_ADDR']
ji真實客戶端 IP:
remote_addr 是無法偽造的:因為建立 TCP 連線需要三次握手,如果偽造了源 IP,無法建立 TCP 連線。
可如果經過代理
$_SERVER['REMOTE_ADDR']
是上一級代理的 IP。
真實 IP 通常在 headers
中的 X-Forwarded-For
和 X-Real-Ip
來獲取:
X-Forwarded-For 是一個 HTTP 擴充套件頭部。HTTP/1.1(RFC 2616)協議並沒有對它的定義,它最開始是由 Squid 這個快取代理軟體引入,用來表示 HTTP 請求端真實 IP。如今它已經成為事實上的標準,被各大 HTTP 代理、負載均衡等轉發服務廣泛使用,並被寫入 RFC 7239(Forwarded HTTP Extension)標準之中。
X-Real-IP,這又是一個自定義頭部欄位。X-Real-IP 通常被 HTTP 代理用來表示與它產生 TCP 連線的裝置 IP,這個裝置可能是其他代理,也可能是真正的請求端。需要注意的是,X-Real-IP 目前並不屬於任何標準,代理和 Web 應用之間可以約定用任何自定義頭來傳遞這個資訊。
我們只討論 X-Forwarded-For
。圖2 中的 proxy
代理到 server
需如下配置
location / {
proxy_pass http://server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
同理,如果再有多個代理:
透過觀察,請求頭 X-Forwarded-For 的組成是:client,proxy1,proxy2..
第一個 ip 就是客戶端 ip,PHP 中獲取: $_SERVER['HTTP_X_FORWARDED_FOR'][0]
。
X-Forwarded-For 是可以偽造的,當 client
傳送這樣的請求時:
curl http://xx/ -H 'X-Forwarded-For: 123.123.123.123'
proxy1
再轉發給 proxy2
location / {
proxy_pass http://proxy2;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
最終:
甚至是不法字串:
curl http://xx/ -H 'X-Forwarded-For: select 1 = 1'
所以取第一個不一定準確,如果沒有檢查 ip 的格式,還有安全隱患。
我們可以這樣配置面向客戶端的 proxy1
的代理轉發,把真實客戶端 ip $remote_addr
直接傳給 `X-Forwarded-For:
location / {
proxy_pass http://proxy2;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
}
這樣就保證了第一個是真實地址。
假設第一個有可能偽造,便引入了可信代理的概念。假設中間代理是可信任的,即不可能偽造 X-Forwarded-For
。如果 server
端獲取的 X-Forwarded-For
頭是:
"http_x_forwarded_for": "select 1 = 1,1.1.1,2.2.2.2,3.3.3.3,4.4.4.4"
配置可信代理:
protected $proxies = [
'4.4.4.4',
'3.3.3.3',
'2.2.2.2',
];
由後向前依次排除,直到 1.1.1.1
不在可信列表中,就認為是真實客戶端 IP。
我們還可以透過 nginx 配置 set_real_ip_from
使 remote_addr
為客戶端真實地址,此配置項依賴 nginx 擴充套件模組 http_realip_module
。
參考:www.runoob.com/w3cnote/http-x-forw...
本作品採用《CC 協議》,轉載必須註明作者和本文連結