Mark Ku's Blog
首頁 關於我
Net core 應用程式,透過 Frpc 內網穿透時,取得用戶端真實 IP
NETCORE
Net core 應用程式,透過 Frpc 內網穿透時,取得用戶端真實 IP
Mark Ku
Mark Ku
January 22, 2022
1 min

問題

大型網站架構,通常會使用負載平衡或反向代理,通常都是 透過 X-Forwarded-For 取得用戶端 Ip,但因為 Frpc 的 https模式只能透過 proxy tocol 協定才能取得真實 IP,但是微軟的網頁伺服器,內建不支援這個協定,因此需要透過 nginx 轉發才能獲得真實用戶端的 IP。

何謂 Proxy protocol

當 Proxy Protocol 功能啟用後,frpc 在和本地服務建立連接後,會先發送一段 Proxy Protocol 的協議內容給本地服務,本地服務通過解析這一內容可以獲得訪問用戶的真實 IP。所以不僅僅是 HTTP 服務,任何的 TCP 服務,只要支持這一協議,都可以獲得用戶的真實 IP 地址。

傳統代理伺服器和應用程式間的 IP傳遞是透過,Header 中的 X-Forwarded-For 所取得的 IP,是有機會被竄改的,但 proxy protocoL,實作原理是透過網路底層 tcpip 交握時取得,因此能避免被篡改被篡改,也比較安全

Frpc 取得 IP 的方式種類

Fpc 取得 ip 的方式

  1. http(非加密協定) - 可以從 X-Forwarded-For 取得用戶端真實 ip
  2. 如果是您要採用 https 則,一定得透過 proxy protocol 底層協定取得用戶端 Ip.

首先編輯你的 frpc.ini 的設定,將 proxy_protocol_version 改成 v2

[common]
server_addr = your public frps url 
server_port = 7000
auth_token = you token
pool_count = 10000
proxy_protocol_version = v2

[web]
type = https
local_port = 443
custom_domains = www.markkulab.net
proxy_protocol_version = v2

接著 nginx.config 的設定

upstream frp {
    server 34.80.106.95:80;  # 这个是frp_server的内网ip和http监听端口
}

server {
    listen 80;
    server_name www.letgo.com.tw;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server
    {
    listen 80 proxy_protocol;
    listen 443 ssl http2 proxy_protocol;
    listen [::]:443 ssl http2;
    server_name www.letgo.com.tw; # local server ip

    set_real_ip_from 172.31.0.1; # frp client ip
    real_ip_recursive on;
    real_ip_header  proxy_protocol;


        ssl_certificate     /etc/letsencrypt/live/www.letgo.com.tw/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.letgo.com.tw/privkey.pem;
    
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";
    error_page 497  https://$host$request_uri;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;      
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://192.168.50.52:8890/; # your local application ip
    }
}

最後,你可以透過請求中的 X-Forwarded-For Header 取得用戶端 IP

public static string GetUserIp(this HttpContext context)
{
    var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();

    if (!string.IsNullOrWhiteSpace(ip))
    {
    ip = ip.Replace("::ffff:", "");
    }           
          
    return ip;
}

參考資料

參考資料1


Tags

Mark Ku

Mark Ku

Software Developer

8年以上豐富網站開發經驗,直播系統、POS系統、電子商務、平台網站、SEO、金流串接、DevOps、Infra 出身,帶過幾次團隊,目前專注於北美及德國市場電商網站開發團隊。

Expertise

前端(React)
後端(C#)
網路管理
DevOps
溝通
領導

Social Media

facebook github website

Related Posts

淺談使用 Dotnet 開源 Yarp Revert Proxy 實現滾動式佈署 ( Rolling-update ) - Part's 1 設計思路
淺談使用 Dotnet 開源 Yarp Revert Proxy 實現滾動式佈署 ( Rolling-update ) - Part's 1 設計思路
July 02, 2022
1 min

Quick Links

關於我

Social Media