From 97d2691713cef112f93c14d328af1549d10265e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dvo=C5=99=C3=A1k?= Date: Fri, 14 Jul 2023 11:51:39 +0200 Subject: [PATCH] Fix #930: Restrict token validation for timestamps in future (#931) * Fix #930: Restrict token validation for timestamps in future * Fix typo * Add property to test application.properties --- .../PowerAuthServiceConfiguration.java | 23 +++++++++++++++++++ .../app/server/service/PowerAuthService.java | 8 ++++++- .../server/service/model/ServiceError.java | 8 ++++++- .../src/main/resources/application.properties | 1 + .../src/test/resources/application.properties | 1 + 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/configuration/PowerAuthServiceConfiguration.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/configuration/PowerAuthServiceConfiguration.java index c9525c6e5..f32ea4d93 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/configuration/PowerAuthServiceConfiguration.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/configuration/PowerAuthServiceConfiguration.java @@ -198,6 +198,13 @@ public class PowerAuthServiceConfiguration { @Min(1) private long tokenTimestampValidityInMilliseconds; + /** + * Token timestamp validity to future in milliseconds, checked before validating the token. + */ + @Value("${powerauth.service.token.timestamp.forward.validity}") + @Min(0) + private long tokenTimestampForwardValidityInMilliseconds; + /** * Master DB encryption key. */ @@ -589,6 +596,22 @@ public void setTokenTimestampValidityInMilliseconds(long tokenTimestampValidityI this.tokenTimestampValidityInMilliseconds = tokenTimestampValidityInMilliseconds; } + /** + * Get the token timestamp validity into future in milliseconds. + * @return Token timestamp validity into future in milliseconds + */ + public long getTokenTimestampForwardValidityInMilliseconds() { + return tokenTimestampForwardValidityInMilliseconds; + } + + /** + * Set the token timestamp validity into future in milliseconds. + * @param tokenTimestampForwardValidityInMilliseconds Token timestamp validity into future in milliseconds + */ + public void setTokenTimestampForwardValidityInMilliseconds(long tokenTimestampForwardValidityInMilliseconds) { + this.tokenTimestampForwardValidityInMilliseconds = tokenTimestampForwardValidityInMilliseconds; + } + /** * Get master DB encryption key. * @return Master DB encryption key. diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/PowerAuthService.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/PowerAuthService.java index 60dd5137a..954095a77 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/PowerAuthService.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/PowerAuthService.java @@ -1088,11 +1088,17 @@ public ValidateTokenResponse validateToken(ValidateTokenRequest request) throws throw localizationProvider.buildExceptionForCode(ServiceError.INVALID_REQUEST); } // Verify the token timestamp validity - if (request.getTimestamp() < System.currentTimeMillis() - powerAuthServiceConfiguration.getTokenTimestampValidityInMilliseconds()) { + final long currentTimeMillis = System.currentTimeMillis(); + if (request.getTimestamp() < currentTimeMillis - powerAuthServiceConfiguration.getTokenTimestampValidityInMilliseconds()) { logger.warn("Invalid request - token timestamp is too old for token ID: {}", request.getTokenId()); // Rollback is not required, database is not used for writing throw localizationProvider.buildExceptionForCode(ServiceError.TOKEN_TIMESTAMP_TOO_OLD); } + if (request.getTimestamp() > currentTimeMillis + powerAuthServiceConfiguration.getTokenTimestampForwardValidityInMilliseconds()) { + logger.warn("Invalid request - token timestamp is set too much in the future for token ID: {}", request.getTokenId()); + // Rollback is not required, database is not used for writing + throw localizationProvider.buildExceptionForCode(ServiceError.TOKEN_TIMESTAMP_TOO_IN_FUTURE); + } try { logger.info("ValidateTokenRequest received, token ID: {}", request.getTokenId()); final ValidateTokenResponse response = behavior.getTokenBehavior().validateToken(request); diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/model/ServiceError.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/model/ServiceError.java index 7b67522bd..d2fddb952 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/model/ServiceError.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/model/ServiceError.java @@ -252,9 +252,14 @@ public class ServiceError { */ public static final String DUPLICATE_APPLICATION = "ERR0043"; + /** + * Token timestamp is too much in the future. + */ + public static final String TOKEN_TIMESTAMP_TOO_IN_FUTURE = "ERR0044"; + public static List allCodes() { - List list = new ArrayList<>(43); + List list = new ArrayList<>(44); list.add(UNKNOWN_ERROR); list.add(NO_USER_ID); list.add(NO_APPLICATION_ID); @@ -299,6 +304,7 @@ public static List allCodes() { list.add(OPERATION_ERROR); list.add(OPERATION_TEMPLATE_ERROR); list.add(DUPLICATE_APPLICATION); + list.add(TOKEN_TIMESTAMP_TOO_IN_FUTURE); return list; } diff --git a/powerauth-java-server/src/main/resources/application.properties b/powerauth-java-server/src/main/resources/application.properties index abfe81def..c7959e7fd 100644 --- a/powerauth-java-server/src/main/resources/application.properties +++ b/powerauth-java-server/src/main/resources/application.properties @@ -68,6 +68,7 @@ powerauth.service.http.connection.timeout=5000 # Token Timestamp Validity in Milliseconds powerauth.service.token.timestamp.validity=7200000 +powerauth.service.token.timestamp.forward.validity=1800000 # Recovery Code Configuration powerauth.service.recovery.maxFailedAttempts=5 diff --git a/powerauth-java-server/src/test/resources/application.properties b/powerauth-java-server/src/test/resources/application.properties index a9f20891a..fcc99773f 100644 --- a/powerauth-java-server/src/test/resources/application.properties +++ b/powerauth-java-server/src/test/resources/application.properties @@ -55,6 +55,7 @@ powerauth.service.http.connection.timeout=5000 # Token Timestamp Validity in Milliseconds powerauth.service.token.timestamp.validity=7200000 +powerauth.service.token.timestamp.forward.validity=1800000 # Recovery Code Configuration powerauth.service.recovery.maxFailedAttempts=5