mirror of
https://github.com/google/nomulus.git
synced 2025-05-17 01:47:14 +02:00
Allow XSRF to be sent as POST parameter in addition to HTML header
HTML headers can only be sent via JS, we need this change to allow secure POST form submission. The form itself will have a hidden "input" tag with the XSRF token in it. This is how other framework do it as well - see https://en.wikipedia.org/wiki/Cross-site_request_forgery#Synchronizer_token_pattern This is in preparation for the OT&E setup page, which will be a simple form with a "submit" button, so using JS for it is overkill. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=226178070
This commit is contained in:
parent
7c9b2172fd
commit
da5a8796b8
3 changed files with 202 additions and 2 deletions
|
@ -14,9 +14,11 @@
|
|||
|
||||
package google.registry.request.auth;
|
||||
|
||||
import static com.google.common.base.Strings.emptyToNull;
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static google.registry.request.auth.AuthLevel.NONE;
|
||||
import static google.registry.request.auth.AuthLevel.USER;
|
||||
import static google.registry.security.XsrfTokenManager.P_CSRF_TOKEN;
|
||||
import static google.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
||||
|
||||
import com.google.appengine.api.users.UserService;
|
||||
|
@ -52,8 +54,7 @@ public class LegacyAuthenticationMechanism implements AuthenticationMechanism {
|
|||
return AuthResult.create(NONE);
|
||||
}
|
||||
|
||||
if (!SAFE_METHODS.contains(request.getMethod())
|
||||
&& !xsrfTokenManager.validateToken(nullToEmpty(request.getHeader(X_CSRF_TOKEN)))) {
|
||||
if (!SAFE_METHODS.contains(request.getMethod()) && !validateXsrf(request)) {
|
||||
return AuthResult.create(NONE);
|
||||
}
|
||||
|
||||
|
@ -61,4 +62,27 @@ public class LegacyAuthenticationMechanism implements AuthenticationMechanism {
|
|||
USER,
|
||||
UserAuthInfo.create(userService.getCurrentUser(), userService.isUserAdmin()));
|
||||
}
|
||||
|
||||
private boolean validateXsrf(HttpServletRequest request) {
|
||||
String headerToken = emptyToNull(request.getHeader(X_CSRF_TOKEN));
|
||||
if (headerToken != null) {
|
||||
return xsrfTokenManager.validateToken(headerToken);
|
||||
}
|
||||
// If we got here - the header didn't have the token.
|
||||
// It might be in the POST data - however even checking whether the POST data has this entry
|
||||
// could break the Action!
|
||||
//
|
||||
// Reason: if we do request.getParameter, any Action that injects @Payload or @JsonPayload
|
||||
// would break since it uses request.getReader - and it's an error to call both getReader and
|
||||
// getParameter!
|
||||
//
|
||||
// However, in this case it's acceptable since if we got here - the POST request didn't even
|
||||
// have the XSRF header meaning if it doesn't have POST data - it's not from a valid source at
|
||||
// all (a valid but outdated source would have a bad header value, but getting here means we had
|
||||
// no value at all)
|
||||
//
|
||||
// TODO(b/120201577): Once we know from the @Action whether we can use getParameter or not -
|
||||
// only check getParameter if that's how this @Action uses getParameters.
|
||||
return xsrfTokenManager.validateToken(nullToEmpty(request.getParameter(P_CSRF_TOKEN)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ public final class XsrfTokenManager {
|
|||
/** HTTP header used for transmitting XSRF tokens. */
|
||||
public static final String X_CSRF_TOKEN = "X-CSRF-Token";
|
||||
|
||||
/** POST parameter used for transmitting XSRF tokens. */
|
||||
public static final String P_CSRF_TOKEN = "xsrfToken";
|
||||
|
||||
/** Maximum age of an acceptable XSRF token. */
|
||||
private static final Duration XSRF_VALIDITY = Duration.standardDays(1);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue