Skip to content
This repository has been archived by the owner on Nov 22, 2018. It is now read-only.

Commit

Permalink
[Fixes #105] Disable caching when response uses antiforgery
Browse files Browse the repository at this point in the history
  • Loading branch information
kichalla committed Nov 2, 2016
1 parent 72bc9c0 commit 46d07da
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/Microsoft.AspNetCore.Antiforgery/IAntiforgery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public interface IAntiforgery
{
/// <summary>
/// Generates an <see cref="AntiforgeryTokenSet"/> for this request and stores the cookie token
/// in the response.
/// in the response. This operation also sets the "Cache-control" and "Pragma" headers to "no-cache" and
/// the "X-Frame-Options" header to "SAMEORIGIN".
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <returns>An <see cref="AntiforgeryTokenSet" /> with tokens for the response.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal static class AntiforgeryLoggerExtensions
private static readonly Action<ILogger, Exception> _newCookieToken;
private static readonly Action<ILogger, Exception> _reusedCookieToken;
private static readonly Action<ILogger, Exception> _tokenDeserializeException;
private static readonly Action<ILogger, Exception> _responseCacheHeadersOverridenToNoCache;

static AntiforgeryLoggerExtensions()
{
Expand Down Expand Up @@ -47,6 +48,11 @@ static AntiforgeryLoggerExtensions()
LogLevel.Error,
7,
"An exception was thrown while deserializing the token.");
_responseCacheHeadersOverridenToNoCache = LoggerMessage.Define(
LogLevel.Warning,
8,
"The 'Cache-Control' and 'Pragma' headers have been overridden and set to 'no-cache' to prevent " +
"caching of this response. Any response that uses antiforgery should not be cached.");
}

public static void ValidationFailed(this ILogger logger, string message)
Expand Down Expand Up @@ -83,5 +89,10 @@ public static void TokenDeserializeException(this ILogger logger, Exception exce
{
_tokenDeserializeException(logger, exception);
}

public static void ResponseCacheHeadersOverridenToNoCache(this ILogger logger)
{
_responseCacheHeadersOverridenToNoCache(logger, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Antiforgery.Internal
{
Expand Down Expand Up @@ -66,6 +67,10 @@ public AntiforgeryTokenSet GetAndStoreTokens(HttpContext httpContext)
}
}

// Explicitly set the cache headers to 'no-cache'. This could override any user set value but this is fine
// as a response with antiforgery token must never be cached.
SetDoNotCacheHeaders(httpContext);

return tokenSet;
}

Expand Down Expand Up @@ -237,6 +242,10 @@ public void SetCookieTokenAndHeader(HttpContext httpContext)
{
_logger.ReusedCookieToken();
}

// Explicitly set the cache headers to 'no-cache'. This could override any user set value but this is fine
// as a response with antiforgery token must never be cached.
SetDoNotCacheHeaders(httpContext);
}

private void SaveCookieTokenAndHeader(HttpContext httpContext, string cookieToken)
Expand Down Expand Up @@ -358,6 +367,43 @@ private IAntiforgeryFeature GetTokensInternal(HttpContext httpContext)
return antiforgeryFeature;
}

private void SetDoNotCacheHeaders(HttpContext httpContext)
{
// Since antifogery token generation is not very obvious to the end users (ex: MVC's form tag generates them
// by default), log a warning to let users know of the change in behavior to any cache headers they might
// have set explicitly.
LogCacheHeaderOverrideWarning(httpContext.Response);

httpContext.Response.Headers[HeaderNames.CacheControl] = "no-cache";
httpContext.Response.Headers[HeaderNames.Pragma] = "no-cache";
}

private void LogCacheHeaderOverrideWarning(HttpResponse response)
{
var logWarning = false;
CacheControlHeaderValue cacheControlHeaderValue;
if (CacheControlHeaderValue.TryParse(response.Headers[HeaderNames.CacheControl], out cacheControlHeaderValue))
{
if (!cacheControlHeaderValue.NoCache)
{
logWarning = true;
}
}

var pragmaHeader = response.Headers[HeaderNames.Pragma];
if (!logWarning
&& !string.IsNullOrEmpty(pragmaHeader)
&& string.Compare(pragmaHeader, "no-cache", ignoreCase: true) != 0)
{
logWarning = true;
}

if (logWarning)
{
_logger.ResponseCacheHeadersOverridenToNoCache();
}
}

private AntiforgeryTokenSet Serialize(IAntiforgeryFeature antiforgeryFeature)
{
// Should only be called after new tokens have been generated.
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.AspNetCore.Antiforgery/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"Microsoft.AspNetCore.DataProtection": "1.1.0-*",
"Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*",
"Microsoft.AspNetCore.Http.Extensions": "1.1.0-*",
"Microsoft.AspNetCore.WebUtilities": "1.1.0-*",
"Microsoft.Extensions.ObjectPool": "1.1.0-*",
"NETStandard.Library": "1.6.1-*"
Expand Down
Loading

0 comments on commit 46d07da

Please sign in to comment.