大型網站架構,通常會使用負載平衡或反向代理,通常都是 透過 X-Forwarded-For 取得用戶端 Ip,但因為 Frpc 的 https模式只能透過 proxy tocol 協定才能取得真實 IP,但是微軟的網頁伺服器,內建不支援這個協定,因此需要透過 nginx 轉發才能獲得真實用戶端的 IP。
當 Proxy Protocol 功能啟用後,frpc 在和本地服務建立連接後,會先發送一段 Proxy Protocol 的協議內容給本地服務,本地服務通過解析這一內容可以獲得訪問用戶的真實 IP。所以不僅僅是 HTTP 服務,任何的 TCP 服務,只要支持這一協議,都可以獲得用戶的真實 IP 地址。
傳統代理伺服器和應用程式間的 IP傳遞是透過,Header 中的 X-Forwarded-For 所取得的 IP,是有機會被竄改的,但 proxy protocoL,實作原理是透過網路底層 tcpip 交握時取得,因此能避免被篡改被篡改,也比較安全
Fpc 取得 ip 的方式
[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
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 } }
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; }