HTTP源地址獲取規范


  1. 代理和獲取規范

    • 原則

      1. F5第一層代理,Nginx作為第二層代理,最終到web應用,如示例:F5->Nginx->Web
      2. 第一層代理需要把源IP設置到X-Real-IP,二級代理需把一級代理地址寫入X-Forwarded-For
    • 名詞解釋

      1. X-Real-IP: 自定義請求頭中字段
      2. X-Forwarded-For:一個 HTTP 擴展頭部,各大 HTTP 代理、負載均衡等轉發服務廣泛使用,並被寫入 RFC 7239(Forwarded HTTP Extension)標准之中
    • 定義規范的背景

      1. X-Real-IP和X-Forwarded-For都可以被客戶端隨意偽造,但是自定義X-Real-IP只能存在一個值,X-Forwarded-For字段可以存在多個以逗號分割,代理服務器只能追加,不能確定源IP地址寫入的具體順序
      2. Remote Address 無法偽造,因為建立 TCP 連接需要三次握手,如果偽造了源 IP,無法建立 TCP 連接,更不會有后面的 HTTP 請求
      3. 基於以上2點,需要一級代理服務器把源IP寫入X-Real-IP,各級代理需把上級代理地址寫入X-Forwarded-For中,追蹤代理調用鏈
    • F5地址轉換規范

      1. 在F5配置界面中,把源 IP寫入參數: X-Real-IP
    • Nginx地址轉換配置模板:

      Nginx配置
      server {
              # 監聽端口
              listen        7777;
              server_name   localhost;
              charset           utf-8;
              location /{
                  # 轉發地址
                  proxy_pass  http://10.19.205.58:7777;
                  proxy_set_header Host $host;
                  # 只有一層代理時候開啟,源地址放入X-Real-Ip
                  # proxy_set_header X-Real-IP $remote_addr;
                  # Nginx作為代理必須開啟,源地址和代理服務器代理地址放入X-Forwarded-For字段
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              }
          }
    • java代碼獲取源地址

      public String getRealIp(HttpServletRequest request){
               // 1. 獲取真實地址
               String realIp = request.getHeader( "X-Real-IP" );
               // 2. 非正常地址或者異常調用
               if (isIlegalHost(realIp)) {
                   // 2.1 獲取X-Forwarded-For地址組
                   String forwardIps= request.getHeader( "X-Forwarded-For" );
                   if (forwardIps != null ){
                       String[] forwardIpArray =  forwardIps.split( "," );
                       // 2.2 循環X-Forwarded-For 的地址,返回第一個正常的地址
                       for (String forwardIp : forwardIpArray){
                           if (!isIlegalHost(forwardIp)){
                               return forwardIp;
                           }
                       }
                   }
                   //2.3 X-Forwarded-For不存在正常地址,則取遠程地址
                   realIp = request.getRemoteAddr();
                   // 防止Nginx和web同一台無法獲取地址
                   if ( "127.0.0.1" .equals(realIp)) {
                       try {
                           // 2.4 如果是本機,則嘗試獲取網卡配置的IP
                           realIp = InetAddress.getLocalHost().getHostAddress();
                       } catch (UnknownHostException e) {}
                   }
               }
               return realIp;
           }
       
           public boolean isIlegalHost(String ip){
               if (ip == null || ip.length() == 0 || "unknown" .equalsIgnoreCase(ip)) {
                   return true ;
               }
               return false ;
           }

2.場景分析

      1. 場景一:Nginx->Web;F5->Web

        1. F5只需界面操作,配置源地址寫入:X-Real-IP
        2. Nginx配置

          server {
               # 監聽端口
               listen        7777;
               server_name   localhost;
               charset           utf-8;
               location /{
                   # 轉發地址
                   proxy_pass  http://10.19.205.58:7777;
                   proxy_set_header Host $host;
                   # 源地址放入X-Real-Ip
                   proxy_set_header X-Real-IP $remote_addr;
                   # 調用地址增加到X-Forwarded-For字段
                   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               }
          }
        3. 實例結果:

          # 訪問路徑:http: //10.19.205.60:7777/express
          # 客戶端地址: 10.20 . 23.50
          # Nginx地址: 10.19 . 205.60
          # web應用地址: 10.19 . 205.58
          # 代碼:request.getRemoteAddr()+ "|" +request.getHeader( "X-Real-IP" )+ "|" + request.getHeader( "X-Forwarded-For" )+ "|" +getRealIp();
          # 返回結果:Remote Addr: 10.19 . 205.60
                       X-Real-IP: 10.20 . 23.50
                       X-Forwarded-For: 10.20 . 23.50
                       getRealIp(): 10.20 . 23.50
        4. 異常情況分析
          1. 異常情況:直接調用web地址,解決方法:java示例代碼行注釋2
             

            # 返回結果:Remote Addr:10.20.23.50
                         X-Real-IP:null
                         X-Forwarded-For:null
                         getRealIp():10.20.23.50

             

      2. 場景二:F5->Nginx->Web

        1. F5只需界面操作,配置源地址寫入:X-Real-IP

        2. Nginx配置:
          server {
               # 監聽端口
               listen        7777;
               server_name   localhost;
               charset           utf-8;
               location /{
                   # 轉發web應用地址
                   proxy_pass  http://10.19.205.58:7777;
                   proxy_set_header Host $host;
                   # F5調用地址增加到X-Forwarded-For字段
                   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               }
          }



        3. 實例結果:
          # 訪問路徑:http: //10.19.18.51:7777/express
          # 客戶端地址: 10.20 . 23.50
          # F5虛擬地址: 10.19 . 18.51
          # Nginx地址: 10.19 . 205.59
          # web應用地址: 10.19 . 205.58
          # 代碼:request.getRemoteAddr()+ "|" +request.getHeader( "X-Real-IP" )+ "|" + request.getHeader( "X-Forwarded-For" )+ "|" +getRealIp();
          # 返回結果:Remote Addr: 10.19 . 205.59
                       X-Real-IP: 10.20 . 23.50
                       X-Forwarded-For: 10.19 . 18.254 (F5實際地址)
                       getRealIp(): 10.20 . 23.50
        4. 異常情況分析
          1. 異常情況一:直接調用nginx地址,解決方案:java示例代碼行注釋2

            # 返回結果:Remote Addr: 10.19 . 205.59
                         X-Real-IP: null
                         X-Forwarded-For: 10.20 . 23.50
                         getRealIp(): 10.20 . 23.50
          2. 異常情況二:直接調用web地址,解決方法:java示例代碼行注釋2.3

            # 返回結果:Remote Addr: 10.20 . 23.50
                         X-Real-IP: null
                         X-Forwarded-For: null
                         getRealIp(): 10.20 . 23.50
      3. Nginx->Nginx->Web

        1. 第一層 Nginx配置:

          server {
            # 監聽端口
            listen        7777 ;
            server_name   localhost;
            charset           utf- 8 ;
            location /{
                # 轉發web應用地址
                proxy_pass  http: //10.19.205.58:7777;
                proxy_set_header Host $host;
                # 源地址放入X-Real-Ip
                proxy_set_header X-Real-IP $remote_addr;
                # 調用地址增加到X-Forwarded-For字段
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
        2. 第二層 Nginx配置:

          server {
               # 監聽端口
               listen        7777 ;
               server_name   localhost;
               charset           utf- 8 ;
               location /{
                   # 轉發web應用地址
                   proxy_pass  http: //10.19.205.58:7777;
                   proxy_set_header Host $host;
                   # 第一層調用地址增加到X-Forwarded-For字段
                   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
               }
          }

           

        3. 實例結果:

          # 訪問路徑:http: //10.19.205.69:7777/express
          # 客戶端地址: 10.20 . 23.50
          # 第一層Nginx地址: 10.19 . 205.69
          # 第二層Nginx地址: 10.19 . 205.59
          # web應用地址: 10.19 . 205.58
          # 代碼:request.getRemoteAddr()+ "|" +request.getHeader( "X-Real-IP" )+ "|" + request.getHeader( "X-Forwarded-For" )+ "|" +getRealIp();
          # 返回結果:Remote Addr: 10.19 . 205.59
                       X-Real-IP: 10.20 . 23.50
                       X-Forwarded-For: 10.20 . 23.50 , 10.19 . 205.69
                       getRealIp(): 10.20 . 23.50


           

        4. 異常情況分析
          1. 異常情況一:直接調用第二層nginx地址,解決方案:java示例代碼行注釋2

            # 返回結果:Remote Addr: 10.19 . 205.59
                         X-Real-IP: null
                         X-Forwarded-For: 10.20 . 23.50
                         getRealIp(): 10.20 . 23.50
          2. 異常情況二:直接調用web地址,解決方法:java示例代碼行注釋2.3

            # 返回結果:Remote Addr: 10.20 . 23.50
                         X-Real-IP: null
                         X-Forwarded-For: null
                         getRealIp(): 10.20 . 23.50

             


免責聲明!

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



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