mirror of https://github.com/halo-dev/halo
Check X-Real-IP header when obtaining client IP (#4139)
#### What type of PR is this? /kind bug /area core /milestone 2.7.x #### What this PR does / why we need it: In some special situations, Halo can not obtain client IP address from request headers and socket address is unresolved, so that `java.lang.NullPointerException: Cannot invoke "java.net.InetAddress.getHostAddress()" because the return value of "java.net.InetSocketAddress.getAddress()" is null` will happen. This PR will resolve the problem by checking `X-Real-IP` header and checking if remote address is unresolved. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4134 #### Does this PR introduce a user-facing change? ```release-note None ```pull/4069/head^2
parent
25103b9ff8
commit
4aec1ba8f6
|
@ -2,6 +2,7 @@ package run.halo.app.infra.utils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +15,7 @@ public class IpAddressUtils {
|
||||||
|
|
||||||
private static final String[] IP_HEADER_NAMES = {
|
private static final String[] IP_HEADER_NAMES = {
|
||||||
"X-Forwarded-For",
|
"X-Forwarded-For",
|
||||||
|
"X-Real-IP",
|
||||||
"Proxy-Client-IP",
|
"Proxy-Client-IP",
|
||||||
"WL-Proxy-Client-IP",
|
"WL-Proxy-Client-IP",
|
||||||
"CF-Connecting-IP",
|
"CF-Connecting-IP",
|
||||||
|
@ -36,17 +38,18 @@ public class IpAddressUtils {
|
||||||
public static String getClientIp(ServerHttpRequest request) {
|
public static String getClientIp(ServerHttpRequest request) {
|
||||||
for (String header : IP_HEADER_NAMES) {
|
for (String header : IP_HEADER_NAMES) {
|
||||||
String ipList = request.getHeaders().getFirst(header);
|
String ipList = request.getHeaders().getFirst(header);
|
||||||
if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
|
if (StringUtils.hasText(ipList) && !UNKNOWN.equalsIgnoreCase(ipList)) {
|
||||||
String[] ips = ipList.trim().split("[,;]");
|
String[] ips = ipList.trim().split("[,;]");
|
||||||
for (String ip : ips) {
|
for (String ip : ips) {
|
||||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
if (StringUtils.hasText(ip) && !UNKNOWN.equalsIgnoreCase(ip)) {
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var remoteAddress = request.getRemoteAddress();
|
var remoteAddress = request.getRemoteAddress();
|
||||||
return remoteAddress == null ? UNKNOWN : remoteAddress.getAddress().getHostAddress();
|
return remoteAddress == null || remoteAddress.isUnresolved()
|
||||||
|
? UNKNOWN : remoteAddress.getAddress().getHostAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package run.halo.app.infra.utils;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||||
|
@ -19,12 +20,31 @@ class IpAddressUtilsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetUnknownIPAddress() {
|
void testGetIPAddressFromXRealIpHeader() {
|
||||||
|
var request = MockServerHttpRequest.get("/")
|
||||||
|
.header("X-Real-IP", "127.0.0.1")
|
||||||
|
.build();
|
||||||
|
var expected = "127.0.0.1";
|
||||||
|
var actual = IpAddressUtils.getClientIp(request);
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetUnknownIPAddressWhenRemoteAddressIsNull() {
|
||||||
var request = MockServerHttpRequest.get("/").build();
|
var request = MockServerHttpRequest.get("/").build();
|
||||||
var actual = IpAddressUtils.getClientIp(request);
|
var actual = IpAddressUtils.getClientIp(request);
|
||||||
assertEquals(IpAddressUtils.UNKNOWN, actual);
|
assertEquals(IpAddressUtils.UNKNOWN, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetUnknownIPAddressWhenRemoteAddressIsUnresolved() {
|
||||||
|
var request = MockServerHttpRequest.get("/")
|
||||||
|
.remoteAddress(InetSocketAddress.createUnresolved("localhost", 8090))
|
||||||
|
.build();
|
||||||
|
var actual = IpAddressUtils.getClientIp(request);
|
||||||
|
assertEquals(IpAddressUtils.UNKNOWN, actual);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetIPAddressWithMultipleHeaders() {
|
void testGetIPAddressWithMultipleHeaders() {
|
||||||
var headers = new HttpHeaders();
|
var headers = new HttpHeaders();
|
||||||
|
|
Loading…
Reference in New Issue