From 557de7690eefb50ca8e49f670ce2ccab1bc360a0 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Wed, 10 Sep 2014 10:32:56 +0200 Subject: [PATCH] Fix CRSF protection on Chrome, and add check if 'Referer' header --- .../main/java/org/keycloak/util/UriUtils.java | 19 +++++++++ .../services/resources/AccountService.java | 41 +++++++++++-------- 2 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 core/src/main/java/org/keycloak/util/UriUtils.java diff --git a/core/src/main/java/org/keycloak/util/UriUtils.java b/core/src/main/java/org/keycloak/util/UriUtils.java new file mode 100644 index 00000000000..873283f61e7 --- /dev/null +++ b/core/src/main/java/org/keycloak/util/UriUtils.java @@ -0,0 +1,19 @@ +package org.keycloak.util; + +import java.net.URI; + +/** + * @author Stian Thorgersen + */ +public class UriUtils { + + public static String getOrigin(URI uri) { + return getOrigin(uri.toString()); + } + + public static String getOrigin(String uri) { + String u = uri.toString(); + return u.substring(0, u.indexOf('/', 8)); + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index 540f7ec3788..19e4e4ce114 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -64,6 +64,7 @@ import org.keycloak.services.validation.Validation; import org.keycloak.social.SocialLoader; import org.keycloak.social.SocialProvider; import org.keycloak.social.SocialProviderException; +import org.keycloak.util.UriUtils; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -148,30 +149,38 @@ public class AccountService { account = session.getProvider(AccountProvider.class).setRealm(realm).setUriInfo(uriInfo); - AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers); + AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers); if (authResult != null) { - auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, authResult.getSession(), true); - Cookie cookie = headers.getCookies().get(KEYCLOAK_STATE_CHECKER); - if (cookie != null) { - stateChecker = cookie.getValue(); - } else { - stateChecker = UUID.randomUUID().toString(); - String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo); - boolean secureOnly = realm.getSslRequired().isRequired(clientConnection); - CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, -1, secureOnly, true); - } - account.setStateChecker(stateChecker); - + auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, authResult.getSession(), false); } else { - authResult = authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers); + authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers); if (authResult != null) { - auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, authResult.getSession(), false); + auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, authResult.getSession(), true); + Cookie cookie = headers.getCookies().get(KEYCLOAK_STATE_CHECKER); + if (cookie != null) { + stateChecker = cookie.getValue(); + } else { + stateChecker = UUID.randomUUID().toString(); + String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo); + boolean secureOnly = realm.getSslRequired().isRequired(clientConnection); + CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, -1, secureOnly, true); + } + account.setStateChecker(stateChecker); } } + + String requestOrigin = UriUtils.getOrigin(uriInfo.getBaseUri()); + // don't allow cors requests unless they were authenticated by an access token // This is to prevent CSRF attacks. if (auth != null && auth.isCookieAuthenticated()) { - if (headers.getRequestHeaders().containsKey("Origin")) { + String origin = headers.getRequestHeaders().getFirst("Origin"); + if (origin != null && !requestOrigin.equals(origin)) { + throw new ForbiddenException(); + } + + String referrer = headers.getRequestHeaders().getFirst("Referer"); + if (referrer != null && !requestOrigin.equals(UriUtils.getOrigin(referrer))) { throw new ForbiddenException(); } }