138 lines
6.8 KiB
C#
138 lines
6.8 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNet.DataProtection;
|
|
using Microsoft.AspNet.Http;
|
|
using Microsoft.AspNet.Mvc.Rendering;
|
|
using Microsoft.AspNet.WebUtilities;
|
|
using Microsoft.Framework.Internal;
|
|
using Microsoft.Framework.OptionsModel;
|
|
using Microsoft.Framework.WebEncoders;
|
|
|
|
namespace Microsoft.AspNet.Mvc
|
|
{
|
|
/// <summary>
|
|
/// Provides access to the anti-forgery system, which provides protection against
|
|
/// Cross-site Request Forgery (XSRF, also called CSRF) attacks.
|
|
/// </summary>
|
|
public sealed class AntiForgery
|
|
{
|
|
private static readonly string _purpose = "Microsoft.AspNet.Mvc.AntiXsrf.AntiForgeryToken.v1";
|
|
private readonly AntiForgeryWorker _worker;
|
|
|
|
public AntiForgery([NotNull] IClaimUidExtractor claimUidExtractor,
|
|
[NotNull] IDataProtectionProvider dataProtectionProvider,
|
|
[NotNull] IAntiForgeryAdditionalDataProvider additionalDataProvider,
|
|
[NotNull] IOptions<AntiForgeryOptions> antiforgeryOptions,
|
|
[NotNull] IHtmlEncoder htmlEncoder,
|
|
[NotNull] IOptions<DataProtectionOptions> dataProtectionOptions)
|
|
{
|
|
var config = antiforgeryOptions.Options;
|
|
var applicationId = dataProtectionOptions.Options.ApplicationDiscriminator ?? string.Empty;
|
|
config.CookieName = config.CookieName ?? ComputeCookieName(applicationId);
|
|
|
|
var serializer = new AntiForgeryTokenSerializer(dataProtectionProvider.CreateProtector(_purpose));
|
|
var tokenStore = new AntiForgeryTokenStore(config, serializer);
|
|
var tokenProvider = new AntiForgeryTokenProvider(config, claimUidExtractor, additionalDataProvider);
|
|
_worker = new AntiForgeryWorker(serializer, config, tokenStore, tokenProvider, tokenProvider, htmlEncoder);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates an anti-forgery token for this request. This token can
|
|
/// be validated by calling the Validate() method.
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
/// <returns>An HTML string corresponding to an <input type="hidden">
|
|
/// element. This element should be put inside a <form>.</returns>
|
|
/// <remarks>
|
|
/// This method has a side effect:
|
|
/// A response cookie is set if there is no valid cookie associated with the request.
|
|
/// </remarks>
|
|
public TagBuilder GetHtml([NotNull] HttpContext context)
|
|
{
|
|
var builder = _worker.GetFormInputElement(context);
|
|
return builder;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates an anti-forgery token pair (cookie and form token) for this request.
|
|
/// This method is similar to GetHtml(HttpContext context), but this method gives the caller control
|
|
/// over how to persist the returned values. To validate these tokens, call the
|
|
/// appropriate overload of Validate.
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
/// <param name="oldCookieToken">The anti-forgery token - if any - that already existed
|
|
/// for this request. May be null. The anti-forgery system will try to reuse this cookie
|
|
/// value when generating a matching form token.</param>
|
|
/// <remarks>
|
|
/// Unlike the GetHtml(HttpContext context) method, this method has no side effect. The caller
|
|
/// is responsible for setting the response cookie and injecting the returned
|
|
/// form token as appropriate.
|
|
/// </remarks>
|
|
public AntiForgeryTokenSet GetTokens([NotNull] HttpContext context, string oldCookieToken)
|
|
{
|
|
// Will contain a new cookie value if the old cookie token
|
|
// was null or invalid. If this value is non-null when the method completes, the caller
|
|
// must persist this value in the form of a response cookie, and the existing cookie value
|
|
// should be discarded. If this value is null when the method completes, the existing
|
|
// cookie value was valid and needn't be modified.
|
|
return _worker.GetTokens(context, oldCookieToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates an anti-forgery token that was supplied for this request.
|
|
/// The anti-forgery token may be generated by calling GetHtml(HttpContext context).
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
public async Task ValidateAsync([NotNull] HttpContext context)
|
|
{
|
|
await _worker.ValidateAsync(context);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates an anti-forgery token pair that was generated by the GetTokens method.
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
/// <param name="cookieToken">The token that was supplied in the request cookie.</param>
|
|
/// <param name="formToken">The token that was supplied in the request form body.</param>
|
|
public void Validate([NotNull] HttpContext context, string cookieToken, string formToken)
|
|
{
|
|
_worker.Validate(context, cookieToken, formToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates an anti-forgery token pair that was generated by the GetTokens method.
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
/// <param name="antiForgeryTokenSet">The anti-forgery token pair (cookie and form token) for this request.
|
|
/// </param>
|
|
public void Validate([NotNull] HttpContext context, AntiForgeryTokenSet antiForgeryTokenSet)
|
|
{
|
|
Validate(context, antiForgeryTokenSet.CookieToken, antiForgeryTokenSet.FormToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates and sets an anti-forgery cookie if one is not available or not valid. Also sets response headers.
|
|
/// </summary>
|
|
/// <param name="context">The HTTP context associated with the current call.</param>
|
|
public void SetCookieTokenAndHeader([NotNull] HttpContext context)
|
|
{
|
|
_worker.SetCookieTokenAndHeader(context);
|
|
}
|
|
|
|
private string ComputeCookieName(string applicationId)
|
|
{
|
|
using (var sha256 = SHA256.Create())
|
|
{
|
|
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(applicationId));
|
|
var subHash = hash.Take(8).ToArray();
|
|
return WebEncoders.Base64UrlEncode(subHash);
|
|
}
|
|
}
|
|
}
|
|
} |