獲取用戶的真實ip


常見的坑有兩個:

 

一、獲取的是內網的ip地址。在nginx作為反向代理層的架構中,轉發請求到php,java等應用容器上。結果php獲取的是nginx代理服務器的ip,表現為一個內網的地址。php獲取REMOTE_ADDR就是這樣一個情況(內網地址)。

二、獲取的是攻擊者偽造的ip地址。攻擊者可以隨便偽造一個頭部信息,隨便填寫一個ip放到頭部發過來,php獲取到HTTP_CLIENT_IP就是這樣一個情況。偽造的ip,導致我們數據庫存儲是假的ip,無從真實去判斷攻擊者的來源。比如批量注冊帳號的注冊ip,登錄的ip等。

     為避免偽造,不要使用discuz原來的獲取ip函數,里面的判斷優先級會使得攻擊者容易偽造ip。

 

 

php代碼:

 

 

 

function getIP() {

 

        if (getenv("HTTP_X_FORWARDED_FOR")) {

            //這個提到最前面,作為優先級,nginx代理會獲取到用戶真實ip,發在這個環境變量上,必須要nginx配置這個環境變量HTTP_X_FORWARDED_FOR

            $ip = getenv("HTTP_X_FORWARDED_FOR");

        } else if (getenv("REMOTE_ADDR")) {

           //在nginx作為反向代理的架構中,使用REMOTE_ADDR拿到的將會是反向代理的的ip,即拿到是nginx服務器的ip地址。往往表現是一個內網ip。

            $ip = getenv("REMOTE_ADDR");

        } else if ($_SERVER['REMOTE_ADDR']) {

            $ip = $_SERVER['REMOTE_ADDR'];

        } else if (getenv("HTTP_CLIENT_IP")) {

            //HTTP_CLIENT_IP攻擊者可以偽造一個這樣的頭部信息,導致獲取的是攻擊者隨意設置的ip地址。

            $ip = getenv("HTTP_CLIENT_IP");

        } else {

            $ip = "unknown";

        }

        return $ip;

    }

 

 

 

說明

 

在反向代理架構中,不能通過REMOTE_ADDR來獲取用戶的真實ip!

 

以前的理解方式有誤(更新一下)

一般的方式是這樣:

nginx>>(fastcgi方式)>>php引擎

nginx把REMOTE_ADDR傳遞給了php。代表的是當前與nginx通信的客戶端ip,一般情況下(非反向代理),這個客戶就是用戶的瀏覽器,所以得到的用戶的ip。


假設做了反向代理架構,是下面這樣子的:


用 戶>>>>>>>>>>>服務器 a>>>>>>>>>>>>>>>>>>nginx>>>>>>>>>>>>>> (fastcgi方式通信)>>>>>>>>>>>>php引擎


   用戶訪問一個域名,實際上是通過服務器a做了轉發,轉發到nginx去(反向代理架構經常會這樣部署)


  於是,當前與nginx通信的客戶端,就是服務器a的地址, REMOTE_ADDR就是a服務器的地址了。


  如何判斷:nginx的上一層是不是還有一層。像上面的情況就還有一層。所以得到的將會是服務器a的地址。

 

 

 

總結:在nginx作為反向代理的架構中,php的REMOTE_ADDR(其他語言也是類似的名稱)拿到的將會是nginx代理的ip地址。拿不到用戶的真實ip,拿到是nginx反向代理服務器地址。

 

REMOTE_ADDR本意就是遠程的地址,nginx是代理層,轉發請求到php,php獲取到的遠程地址實際上是nginx反向代理服務器ip,這是符合協議規則的。

 

但是,可以讓nginx幫助我們拿到用戶的真實ip,寫到一個環境變量中,然后轉發給我們,只要按照某個約定的名稱即可,比如約定名稱為HTTP_X_FORWARD_FOR(也可以約定其他名稱,關鍵看nginx中配置,可以全公司考慮統一)

 

 

nginx配置類似於這樣:

 

fastcgi_param  HTTP_X_FORWARD_FOR  $remote_addr;

 

 上一句的目的是,將HTTP_X_FORWARD_FOR的值設置為$remote_addr的值。也就是將用戶真實的ip(或用戶使用代理的ip)放到HTTP_X_FORWARD_FOR中去。

 

 $remote_addr是nginx的內置變量,這個變量它得到是用戶真實的ip地址(用戶使用了代理,則就是代理的ip地址)。

 

於是在php端通過getenv("HTTP_X_FORWARDED_FOR")就可以獲取到nginx傳遞過來的值,是用戶真實的ip地址。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM