Предотвращение атак поддельных запросов (csrf) в веб-формах asp.net

Я создал приложение ASP.Net Web Forms с использованием Visual Studio 2013 и использую.NET Framework 4.5. Я хочу убедиться, что мой сайт защищен от подделки межсайтовых запросов (CSRF), я нашел много статей о том, как эта функция реализована в приложениях MVC, но очень мало о веб-формах. На qaru.site/info/337704/... один комментарий гласит, что

"Это старый вопрос, но последний шаблон Visual Studio 2012 ASP.NET для веб-форм включает код анти-CSRF, запеченный на главной странице. Если у вас нет шаблонов, вот код, который он генерирует:..."

Моя главная страница не содержит код, указанный в этом ответе. Это действительно включено в новые приложения? Если нет, каков наилучший способ добавить его?

Ответ 1

ViewStateUserKey & Двойной файл cookie для отправки

Начиная с Visual Studio 2012, Microsoft добавила встроенную защиту CSRF в новые проекты приложений веб-форм. Чтобы использовать этот код, добавьте новое приложение ASP.NET Web Forms в свое решение и просмотрите код Site.Master за страницей. Это решение будет применять защиту CSRF ко всем страницам контента, которые наследуются от страницы Site.Master.

Для работы этого решения должны быть выполнены следующие требования:

Все веб-формы, вносящие изменения в данные, должны использовать страницу Site.Master. Все запросы, вносящие изменения в данные, должны использовать ViewState. Веб-сайт должен быть свободен от всех уязвимостей межсайтового скриптинга (XSS). Подробнее о том, как исправить межсайтовый скриптинг (XSS) с помощью библиотеки Microsoft.Net Web Protection.

public partial class SiteMaster : MasterPage
{
  private const string AntiXsrfTokenKey = "__AntiXsrfToken";
  private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
  private string _antiXsrfTokenValue;

  protected void Page_Init(object sender, EventArgs e)
  {
    //First, check for the existence of the Anti-XSS cookie
    var requestCookie = Request.Cookies[AntiXsrfTokenKey];
    Guid requestCookieGuidValue;

    //If the CSRF cookie is found, parse the token from the cookie.
    //Then, set the global page variable and view state user
    //key. The global variable will be used to validate that it matches 
    //in the view state form field in the Page.PreLoad method.
    if (requestCookie != null
        && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
    {
      //Set the global token variable so the cookie value can be
      //validated against the value in the view state form field in
      //the Page.PreLoad method.
      _antiXsrfTokenValue = requestCookie.Value;

      //Set the view state user key, which will be validated by the
      //framework during each request
      Page.ViewStateUserKey = _antiXsrfTokenValue;
    }
    //If the CSRF cookie is not found, then this is a new session.
    else
    {
      //Generate a new Anti-XSRF token
      _antiXsrfTokenValue = Guid.NewGuid().ToString("N");

      //Set the view state user key, which will be validated by the
      //framework during each request
      Page.ViewStateUserKey = _antiXsrfTokenValue;

      //Create the non-persistent CSRF cookie
      var responseCookie = new HttpCookie(AntiXsrfTokenKey)
      {
        //Set the HttpOnly property to prevent the cookie from
        //being accessed by client side script
        HttpOnly = true,

        //Add the Anti-XSRF token to the cookie value
        Value = _antiXsrfTokenValue
      };

      //If we are using SSL, the cookie should be set to secure to
      //prevent it from being sent over HTTP connections
      if (FormsAuthentication.RequireSSL &&
          Request.IsSecureConnection)
      {
        responseCookie.Secure = true;
      }

      //Add the CSRF cookie to the response
      Response.Cookies.Set(responseCookie);
    }

    Page.PreLoad += master_Page_PreLoad;
  }

  protected void master_Page_PreLoad(object sender, EventArgs e)
  {
    //During the initial page load, add the Anti-XSRF token and user
    //name to the ViewState
    if (!IsPostBack)
    {
      //Set Anti-XSRF token
      ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;

      //If a user name is assigned, set the user name
      ViewState[AntiXsrfUserNameKey] =
             Context.User.Identity.Name ?? String.Empty;
    }
    //During all subsequent post backs to the page, the token value from
    //the cookie should be validated against the token in the view state
    //form field. Additionally user name should be compared to the
    //authenticated users name
    else
    {
      //Validate the Anti-XSRF token
      if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
          || (string)ViewState[AntiXsrfUserNameKey] !=
               (Context.User.Identity.Name ?? String.Empty))
      {
        throw new InvalidOperationException("Validation of " +
                            "Anti-XSRF token failed.");
      }
    }
  }
}

Источник

Ответ 2

Вы можете попробовать следующее. В веб-форме добавьте:

<%= System.Web.Helpers.AntiForgery.GetHtml() %>

Это добавит скрытое поле и файл cookie. Поэтому, если вы заполняете данные определенной формы и отправляете ее обратно на сервер, вам нужна простая проверка:

protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
 AntiForgery.Validate();
}

AntiForgery.Validate(); выдает исключение, если проверка анти XSFR не выполняется.

Ответ 3

Когда вы создаете новый проект приложения "Веб-форма" в VS 2013, сайт .master.cs автоматически включит код XSRF/CSRF в разделе Page_Init этого класса. Если вы все еще не получаете сгенерированный код, вы можете вручную ввести код Copy + Paste. Если вы используете С#, используйте следующую команду: -

private const string AntiXsrfTokenKey = "__AntiXsrfToken";
private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
private string _antiXsrfTokenValue;

 protected void Page_Init(object sender, EventArgs e)
    {
        // The code below helps to protect against XSRF attacks
        var requestCookie = Request.Cookies[AntiXsrfTokenKey];
        Guid requestCookieGuidValue;
        if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
        {
            // Use the Anti-XSRF token from the cookie
            _antiXsrfTokenValue = requestCookie.Value;
            Page.ViewStateUserKey = _antiXsrfTokenValue;
        }
        else
        {
            // Generate a new Anti-XSRF token and save to the cookie
            _antiXsrfTokenValue = Guid.NewGuid().ToString("N");
            Page.ViewStateUserKey = _antiXsrfTokenValue;

            var responseCookie = new HttpCookie(AntiXsrfTokenKey)
            {
                HttpOnly = true,
                Value = _antiXsrfTokenValue
            };
            if (FormsAuthentication.RequireSSL && Request.IsSecureConnection)
            {
                responseCookie.Secure = true;
            }
            Response.Cookies.Set(responseCookie);
        }

        Page.PreLoad += master_Page_PreLoad;
    }

    protected void master_Page_PreLoad(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Set Anti-XSRF token
            ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
            ViewState[AntiXsrfUserNameKey] = Context.User.Identity.Name ?? String.Empty;
        }
        else
        {
            // Validate the Anti-XSRF token
            if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
                || (string)ViewState[AntiXsrfUserNameKey] != (Context.User.Identity.Name ?? String.Empty))
            {
                throw new InvalidOperationException("Validation of Anti-XSRF token failed.");
            }
        }
    }

Ответ 4

Вы можете использовать ниже фрагмент кода, который будет проверять запрос, откуда он исходит из

if ((context.Request.UrlReferrer == null || context.Request.Url.Host != context.Request.UrlReferrer.Host)) 
    {
        context.Response.Redirect("~/error.aspx", false);
    }

Это отлично работает для меня!