使用WAF之后相当于多一层代理,后方的nginx或者服务直接获取到的IP其实是WAF的回源IP,而不是终端用户的真是IP,那么如何获得真实IP呢?其实WAF会把真实IP放到请求头里,通用Header为:X-Forwarded-For,目前看阿里云、华为云都会放到这个header。经发现阿里云还会放到Header:X-Real-IP,而Cloudflare会放到Header:CF-Connecting-IP。
可以在nginx侧打印日志进行测试,注意nginx日志的变量命名稍微有些不同,header要加上http_开头,横杆要改为下划线。例如:$http_x_forwarded_for、 $http_x_real_ip。完整例子:
1
2
3
|
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工具类,具体实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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的获取IP的实现代码是通过以下一系列Header来获取:
1
2
3
4
5
6
7
8
|
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);
}
|
Controller快速获取客户端IP的调试代码
1
2
3
4
5
6
7
8
9
|
@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为例:
在http节点下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
# 启用 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;
...
|
上述配置中 Cloudflare IP 地址列表需要进行定期更新,以包含最新的 IP 地址段。可以从 https://www.cloudflare.com/ips/ 获取最新的 Cloudflare IP 地址列表。
文本地址为:
https://www.cloudflare.com/ips-v4/
https://www.cloudflare.com/ips-v6/
这样真实IP会存储到remote_addr中。
nginx快速获取客户端ip调试配置
1
2
3
4
5
|
location /getip
{
default_type "text/plain;charset=utf-8";
return 200 "$remote_addr";
}
|