防止asp.net Web表单中的跨站点请求伪造(csrf)攻击

Nad*_*uli 24 asp.net webforms csrf .net-framework-version

我使用Visual Studio 2013创建了一个ASP.Net Web窗体应用程序,我使用的是.NET Framework 4.5.我想确保我的网站是安全的跨站点请求伪造(CSRF),我发现很多文章谈论如何在MVC应用程序上实现此功能,但很少谈论Web窗体.在这个StackOverflow问题上,一条评论说明了这一点

"这是一个老问题,但最新的Web表单Visual Studio 2012 ASP.NET模板包含在主页面中加入的反CSRF代码.如果您没有模板,这里是它生成的代码:......"

我的母版页不包含该答案中提到的代码.它真的包含在新的应用程序中吗?如果没有,添加它的最佳方法是什么?

Saf*_*e99 32

您可以尝试以下方法.在Web表单中添加:

<%= System.Web.Helpers.AntiForgery.GetHtml() %>
Run Code Online (Sandbox Code Playgroud)

这将添加隐藏字段和cookie.因此,如果您填写一些表单数据并将其发回服务器,则需要进行简单的检查:

protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
 AntiForgery.Validate();
}
Run Code Online (Sandbox Code Playgroud)

AntiForgery.Validate(); 如果反XSFR检查失败,则抛出异常.

  • 命名空间是Microsoft.AspNet.WebPages Nuget-Package中的System.Web.Helpers. (5认同)
  • 有人知道是否有一个不依赖 Razor 的可用软件包? (2认同)

Nad*_*uli 21

ViewStateUserKey&Double提交Cookie

从Visual Studio 2012开始,Microsoft为新的Web表单应用程序项目添加了内置的CSRF保护.要使用此代码,请在解决方案中添加新的ASP .NET Web窗体应用程序,并查看页面后面的Site.Master代码.此解决方案将CSRF保护应用于从Site.Master页面继承的所有内容页面.

此解决方案必须满足以下要求:

所有进行数据修改的Web表单都必须使用Site.Master页面.所有进行数据修改的请求都必须使用ViewState.该网站必须没有所有跨站点脚本(XSS)漏洞.有关详细信息,请参阅如何使用Microsoft .Net Web Protection Library修复跨站点脚本(XSS).

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.");
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用VS2017,但在Site.Master.cs(全新的Web窗体应用程序项目)中没有看到此代码。 (2认同)
  • 我们使用此代码大约一年,并且不断遇到问题:偶尔会引发异常。我们有我们的自定义身份验证模块,用于保存auth(长期有效)cookie。当用户打开浏览器并导航到该站点时,它将基于该cookie自动登录。一旦我有幸至少达到断点,然后看看哪个条件失败了:那是第二学期。Context.User.Identity.Name为空,但ViewState包含用户名。为什么我们甚至填充并检查用户名? (2认同)
  • @ryanulit XSRF背后的想法是,某个人可以假装来自完全不同的域(例如,通过&lt;img&gt;或&lt;iframe&gt;)作为客户端。正如您所指出的那样,此代码不能保护服务器免受最初访问客户端浏览器的人的侵害(这更像是XSS攻击)。 (2认同)

Mah*_*ava 11

在VS 2013中创建新的"Web窗体应用程序"项目时,site.master.cs将自动Page_Init在类的部分中包含XSRF/CSRF代码.如果您仍然没有获得生成的代码,您可以手动Copy+ Paste代码.如果您使用的是C#,请使用以下内容: -

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.");
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)