Nginx多層代理獲取真實客戶端IP【轉載】
阿新 • • 發佈:2020-11-24
一般的應用都是通過Nginx來做為反向代理,並且Nginx還可能是多層的。如果想在內部服務裡面獲取最原始的客戶端IP地址。則需要做一些配置
最外層Nginx
為了防止X-Forwarded-For頭的偽造,可在最外層Nginx將X-Forwarded-For設定為真實IP$remote_addr。 $remote_addr是獲取的是直接TCP連線的客戶端IP(類似於Java中的request.getRemoteAddr()),這個是無法偽造的,即使客戶端偽造也會被覆蓋掉,而不是追加。
upstream innerservice { server 192.168.12.33:9001; server 192.168.12.34:9002; } server { listen 9000; server_name 192.168.12.22; root /usr/share/nginx/html; include /etc/nginx/default.d/*.conf; location / { proxy_pass http://innerservice; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; } }
後續Nginx配置
upstream innerservice { server 192.168.12.33:9001; server 192.168.12.34:9002; } server { listen 9000; // xxx location / { proxy_pass http://innerservice; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
Java中獲取真實IP
/** * Description:客戶端資訊獲取過濾器 */ public class ClientContextFilter extends OncePerRequestFilter { /** * Nginx預設增加的IP地址頭 */ public static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For"; /** * 內部微服務之間呼叫增加的IP地址頭 */ public static final String HEADER_X_REMOTE_USER_IP = "X-Remote-User-IP"; /** * IP響應頭的分割符號 */ private static final String IP_HEADER_DELIMITER = ","; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { String remoteUserIP = loadRemoteUserIP(request); ClientContext context = new ClientContext(); context.setClientIP(request.getRemoteAddr()); context.setRemoteUserIP(remoteUserIP); ClientContextHolder.setContext(context); filterChain.doFilter(request, response); } finally { ClientContextHolder.clearContext(); } } private String loadRemoteUserIP(HttpServletRequest request) { String xForwardedHeader = request.getHeader(HEADER_X_FORWARDED_FOR); // 先嚐試從X-Forwarded-For獲取 if (xForwardedHeader != null && xForwardedHeader.trim().length() > 0) { String[] ips = xForwardedHeader.split(IP_HEADER_DELIMITER); return ips[0].trim(); } else { // 嘗試從內部自定義頭上獲取 String internalIPHeader = request.getHeader(HEADER_X_REMOTE_USER_IP); if (null != internalIPHeader && internalIPHeader.trim().length() > 0) { return internalIPHeader.trim(); } else { return null; } } } }
原理是在服務往後面傳遞的時候,定義一個自定義頭,將真實IP放到這個header中。 後臺服務可取兩個IP地址
request.getRemoteAddr()
- 獲取呼叫方服務的內網IP地址loadRemoteUserIP
- 獲取最源頭的真實客戶端IP地址