天天看點

阿裡雲場景下擷取使用者真實 IP

擷取使用者的真實 ip,對于安全業務來說非常重要。

阿裡雲場景下一個http 請求一般為:

使用者ip --> ddos 高防 ip ->slb ip

對于web伺服器來說,主要是通過兩種方式擷取 ip

與伺服器建立tcp連接配接的位址 remote address

通過 http header 的 x-forwarded-for 字段

對應的 php 變量如下

與伺服器建立tcp連接配接的 ip

無法僞造,很合适作為使用者真實ip

但是 http 請求經過七層代理後,就不是使用者ip了,一般為slb ip

通過http header傳遞給服務端

可以僞造,有可能擷取的資料不準确,還可能引發 xss,sql 注入等問題

x-forwarded-for :格式如下

x-forwarded-for: client, proxy1, proxy2

如果一個 http 請求到達伺服器之前,經過了三個代理 proxy1、proxy2、proxy3,ip 分别為 ip1、ip2、ip3,使用者真實 ip 為 ip0,服務端最終會收到以下資訊:

x-forwarded-for: ip0, ip1, ip2

proxy3 直連伺服器,它會給 xff 追加 ip2,表示它是在幫 proxy2 轉發請求。清單中并沒有 ip3,ip3 可以在服務端通過 remote_addr 字段獲得。

如果使用者篡改 x-forwarded-for

x-forwarded-for: ip100, ip0, ip1, ip2

我們怎麼通過這兩個字段擷取使用者真實 ip 呢?

如果 http 請求沒有經過七層代理,直接讀取 remote_addr 字段最好

如果 http 請求經過七層代理, 我們隻能從 x-forwarded-for 擷取,但是我們必須過濾使用者僞造資料,擷取真實的使用者 ip

如上面例子 ip1, ip2是我們自己配置的 ip,可信任的ip,過濾掉可信任的代理ip,最後一個不可信任的ip就是使用者ip。

要解決的問題如下

nginx的通路日志,記錄使用者真實ip,現在記錄的是remote address。

php擷取使用者真實ip,如果我們擷取x-forwarded-for第一個ip。容易被使用者篡改。

調研過程中,發現ngx_http_realip_module 滿足我們需求, 當擷取了使用者真實ip,會指派給 nginx變量 $remote_addr 變量,那麼 php的 $_server['remote_addr'] 也變成了使用者真實ip。

與web伺服器建議tcp連接配接的ip 存儲在變量 $realip_remote_addr 中。

set_ip_from

設定信任 ip,就是我們自己的代理ip,可以設定多個

real_ip_header

設定請求頭字段,表示從x-forwarded-for字段擷取使用者 ip

real_ip_recursive

off:如果remote address 能夠比對set_real_ip_from 的ip,使用者 x-forwarded-for最後一個 ip 作為使用者ip。

on: 如果remote address 能夠比對set_real_ip_from 的ip,使用者 x-forwarded-for最後一個不可信任 ip 作為使用者ip。

我們的配置如下,注意還沒有上線

nginx 配置如下

php 擷取使用者ip

$_sever['remote_addr']

<a href="https://imququ.com/post/x-forwarded-for-header-in-http.html">https://imququ.com/post/x-forwarded-for-header-in-http.html</a>

<a href="http://nginx.org/en/docs/http/ngx_http_realip_module.html">http://nginx.org/en/docs/http/ngx_http_realip_module.html</a>

<a href="http://baike.baidu.com/item/iana%e4%bf%9d%e7%95%99%e5%9c%b0%e5%9d%80?fr=aladdin">http://baike.baidu.com/item/iana%e4%bf%9d%e7%95%99%e5%9c%b0%e5%9d%80?fr=aladdin</a>