Finalizing Security Optimizations
This commit is contained in:
parent
dc12425611
commit
897252f9cd
1 changed files with 37 additions and 2 deletions
|
|
@ -9,6 +9,8 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom authentication entry point that handles unauthenticated requests.
|
* Custom authentication entry point that handles unauthenticated requests.
|
||||||
|
|
@ -45,9 +47,42 @@ public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML page requests should redirect to login
|
// HTML page requests should redirect to login. The redirect parameter is built
|
||||||
|
// from the original request URI so the login page can later send the user back.
|
||||||
|
// We must restrict it to a single internal path — anything starting with "//" or
|
||||||
|
// "/\" could be interpreted by browsers as a protocol-relative URL pointing at
|
||||||
|
// an external host, turning this into an open redirect.
|
||||||
log.debug("HTML page request - redirecting to /login");
|
log.debug("HTML page request - redirecting to /login");
|
||||||
String redirectUrl = "/login?redirect=" + requestUri;
|
String redirectUrl;
|
||||||
|
if (isSafeInternalPath(requestUri)) {
|
||||||
|
redirectUrl = "/login?redirect=" + URLEncoder.encode(requestUri, StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
log.warn("Refusing to propagate suspicious redirect target: {}", requestUri);
|
||||||
|
redirectUrl = "/login";
|
||||||
|
}
|
||||||
response.sendRedirect(redirectUrl);
|
response.sendRedirect(redirectUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given path is a safe single-slash internal path that can be
|
||||||
|
* round-tripped through a {@code redirect} query parameter without enabling an open
|
||||||
|
* redirect. Rejects null/empty, anything not starting with {@code /}, and anything
|
||||||
|
* starting with {@code //} or {@code /\} (both of which browsers may interpret as
|
||||||
|
* protocol-relative URLs to a different host).
|
||||||
|
*/
|
||||||
|
private static boolean isSafeInternalPath(String path) {
|
||||||
|
if (path == null || path.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (path.charAt(0) != '/') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (path.length() >= 2) {
|
||||||
|
char second = path.charAt(1);
|
||||||
|
if (second == '/' || second == '\\') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue