diff --git a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryValidationException.cs b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryValidationException.cs index b2fb6e9618..f1ade05d34 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryValidationException.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryValidationException.cs @@ -12,12 +12,23 @@ namespace Microsoft.AspNetCore.Antiforgery { /// /// Creates a new instance of with the specified - /// exception . + /// exception message. /// /// The message that describes the error. public AntiforgeryValidationException(string message) : base(message) { } + + /// + /// Creates a new instance of with the specified + /// exception message and inner exception. + /// + /// The message that describes the error. + /// The inner . + public AntiforgeryValidationException(string message, Exception innerException) + : base(message, innerException) + { + } } } diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryLoggerExtensions.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryLoggerExtensions.cs index 0c8ef5ccfd..232279e4be 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryLoggerExtensions.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryLoggerExtensions.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal { internal static class AntiforgeryLoggerExtensions { + private static readonly Action _failedToDeserialzeTokens; private static readonly Action _validationFailed; private static readonly Action _validated; private static readonly Action _missingCookieToken; @@ -54,6 +55,10 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal "The 'Cache-Control' and 'Pragma' headers have been overridden and set to 'no-cache, no-store' and " + "'no-cache' respectively to prevent caching of this response. Any response that uses antiforgery " + "should not be cached."); + _failedToDeserialzeTokens = LoggerMessage.Define( + LogLevel.Debug, + 9, + "Failed to deserialize antiforgery tokens."); } public static void ValidationFailed(this ILogger logger, string message) @@ -95,5 +100,10 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal { _responseCacheHeadersOverridenToNoCache(logger, null); } + + public static void FailedToDeserialzeTokens(this ILogger logger, Exception exception) + { + _failedToDeserialzeTokens(logger, exception); + } } } diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs index ae28906069..24aa3cb7d3 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs @@ -124,7 +124,10 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal // Extract cookie & request tokens AntiforgeryToken deserializedCookieToken; AntiforgeryToken deserializedRequestToken; - DeserializeTokens(httpContext, tokens, out deserializedCookieToken, out deserializedRequestToken); + if (!TryDeserializeTokens(httpContext, tokens, out deserializedCookieToken, out deserializedRequestToken)) + { + return false; + } // Validate string message; @@ -197,6 +200,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal // Extract cookie & request tokens AntiforgeryToken deserializedCookieToken; AntiforgeryToken deserializedRequestToken; + DeserializeTokens( httpContext, antiforgeryTokenSet, @@ -430,6 +434,27 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal _options.HeaderName); } + private bool TryDeserializeTokens( + HttpContext httpContext, + AntiforgeryTokenSet antiforgeryTokenSet, + out AntiforgeryToken cookieToken, + out AntiforgeryToken requestToken) + { + try + { + DeserializeTokens(httpContext, antiforgeryTokenSet, out cookieToken, out requestToken); + return true; + } + catch (AntiforgeryValidationException ex) + { + _logger.FailedToDeserialzeTokens(ex); + + cookieToken = null; + requestToken = null; + return false; + } + } + private void DeserializeTokens( HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet, diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenSerializer.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenSerializer.cs index 474b2fd7a9..d71f2a2185 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenSerializer.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenSerializer.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal } // if we reached this point, something went wrong deserializing - throw new InvalidOperationException(Resources.AntiforgeryToken_DeserializationFailed, innerException); + throw new AntiforgeryValidationException(Resources.AntiforgeryToken_DeserializationFailed, innerException); } /* The serialized format of the anti-XSRF token is as follows: diff --git a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenSerializerTest.cs b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenSerializerTest.cs index 80280de4f3..88ce09b4e2 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenSerializerTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenSerializerTest.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal var testSerializer = new DefaultAntiforgeryTokenSerializer(_dataProtector.Object, _pool); // Act & assert - var ex = Assert.Throws(() => testSerializer.Deserialize(serializedToken)); + var ex = Assert.Throws(() => testSerializer.Deserialize(serializedToken)); Assert.Equal(@"The antiforgery token could not be decrypted.", ex.Message); }