使用WAF(Web应用防火墙)后,相当于在客户端和服务器之间增加了一层代理。后端的nginx或应用服务直接获取到的IP实际上是WAF的回源IP,而不是终端用户的真实IP。
🔍 WAF真实IP传递机制
WAF会将客户端真实IP放到HTTP请求头中,不同厂商使用的Header略有差异:
WAF厂商 | Header字段 |
---|---|
阿里云、华为云 | X-Forwarded-For |
阿里云 | X-Real-IP |
Cloudflare | CF-Connecting-IP |
🔧 Nginx日志配置
可以在nginx侧配置日志来测试真实IP获取:
注意事项:
- Header需要加上
http_
前缀 - 横杠需要改为下划线
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$http_x_real_ip"';
☕ Java获取真实IP
使用Hutool工具类
结合hutool工具类的具体实现:
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.servlet.ServletUtil;
public class IpAddressUtil {
private static final Log log = Log.get();
private static final String LOCAL_IP = "127.0.0.1";
private static final String LOCAL_REMOTE_HOST = "0:0:0:0:0:0:0:1";
/**
* 获取客户端IP
*/
public static String getIp(HttpServletRequest request) {
if (ObjectUtil.isEmpty(request)) {
return LOCAL_IP;
} else {
String remoteHost = ServletUtil.getClientIP(request);
return LOCAL_REMOTE_HOST.equals(remoteHost) ? LOCAL_IP : remoteHost;
}
}
}
Hutool实现原理
Hutool通过以下Header顺序获取客户端IP:
public static String getClientIP(HttpServletRequest request, String... otherHeaderNames) {
String[] headers = new String[]{
"X-Forwarded-For",
"X-Real-IP",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR"
};
if (ArrayUtil.isNotEmpty(otherHeaderNames)) {
headers = (String[])ArrayUtil.addAll(new String[][]{headers, otherHeaderNames});
}
return getClientIPByHeader(request, headers);
}
调试接口
用于快速测试各个Header的值:
@GetMapping("/getClientIp")
public String testClientIp(HttpServletRequest request) {
String[] headers = {
"X-Forwarded-For",
"X-Real-IP",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR"
};
StringBuilder sb = new StringBuilder();
for (String header : headers) {
sb.append(header)
.append(": ")
.append(ServletUtil.getClientIPByHeader(request, header))
.append("\n");
}
return sb.toString();
}
🌐 使用ngx_http_realip_module模块
Cloudflare配置示例
在nginx的http节点下配置:
# 启用 ngx_http_realip_module 模块
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;
# 设置 Cloudflare 的 IP 地址段
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# ... 更多IP段
IP地址列表更新
⚠️ 重要提醒:Cloudflare IP地址列表需要定期更新,以包含最新的IP地址段。
获取最新IP列表:
- 📋 总览页面:https://www.cloudflare.com/ips/
- 🌐 IPv4地址:https://www.cloudflare.com/ips-v4/
- 🌐 IPv6地址:https://www.cloudflare.com/ips-v6/
配置完成后,真实IP会存储到 $remote_addr
变量中。
调试配置
用于快速测试IP获取的nginx配置:
location /getip {
default_type "text/plain;charset=utf-8";
return 200 "$remote_addr";
}
💡 提示:建议定期检查和更新WAF厂商的IP地址段,确保真实IP获取的准确性。