Nancy启用跨站攻击防护(CSRF)

什么是CSRF(跨站攻击)

可能很多人已经对CSRF有所了解,就简单的介绍下:

CSRF全程是 Cross-Site Request Forgery 。大概意思就是在登录用户不知情的情况下,由一个网站对已经登录的另外一个网站发送请求。

为了保证请求是来自我们自己的网站,在表单的隐藏域中添加一个唯一的值,这个值被成为 AntiForgeryToken。

如果你想详细的了解下CSRF,你可以看下百度百科

 

CSRF和Nancy

正如Nancy的其他功能,你不可能在默认情况下就能获得一个完整的解决方案。由于Nancy是轻量级、自由开发的,我们还是需要付出一点努力才能使用CSRF防护。

  1. 在Bootstrapper中启用CSRF防护支持
  2. 在应用的每一个Form中添加AntiForgeryToken
  3. 使用Nancy内置的方法ValidateCsrfToken验证CSRF票据
  4. 处理Nancy无法接收正确票据的请求

启用CSRF

如果没有创建就创建一个NancyDefaultBootstrapper类,添加下面的代码到ApplicationStartup()方法中

Nancy.Security.Csrf.Enable(pipelines);

我们的Bootstrapper如下:

using Nancy;
using Nancy.Bootstrapper;
using Nancy.TinyIoc;

namespace NancyCsrfDemo
{
    public class Bootstrapper : DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            Nancy.Security.Csrf.Enable(pipelines);
        }
    }
}

 

 

在表单中添加AntiForgeryToken

如果你采用的是Razor视图引擎,视图文件应该是下面的样子:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
    <body>
        <h1>Welcome to Nancy CSRF Demo, @ViewBag.Name</h1>
        <form action="/" method="POST">
            Name:<br/>
            <input type="text" name="name" value="@ViewBag.Name" />
            <input type="submit" />
            @Html.AntiForgeryToken()
        </form>
    </body>
</html>

如果采用的是SSVE (The Super Simple View Engine)

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
    <body>
        <h1>Welcome to Nancy CSRF Demo, @Model.Name</h1>
        <form action="/" method="POST">
            Name:<br/>
            <input type="text" name="name" value="@Model.Name" />
            <input type="submit" />
            @AntiForgeryToken
        </form>
    </body>
</html>

不管使用那个引擎,都会在表单中生成一个隐藏域

<input type="hidden" name="NCSRF" value="AAEAAAD/////AQAAAAAAAAAMAgAAAD1OYW5jeSwgVmVyc2lvbj0wLjIyLjIuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBQEAAAAYTmFuY3kuU2VjdXJpdHkuQ3NyZlRva2VuAwAAABw8UmFuZG9tQnl0ZXM+a19fQmFja2luZ0ZpZWxkHDxDcmVhdGVkRGF0ZT5rX19CYWNraW5nRmllbGQVPEhtYWM+a19fQmFja2luZ0ZpZWxkBwAHAg0CAgAAAAkDAAAAOrVPNrYs0YgJBAAAAA8DAAAACgAAAAI4qmisW7sYu2FlDwQAAAAgAAAAAsdnVjuuU1fzpb58LEjF1pcK98u9ENMjG0viyxLpvlv/CwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="/>

 

校验Token

当用户点击按钮的时候,浏览器就会向后台发送 AntiForgeryToken/CSRF 票据。

Nancy有一个内置方法ValidateCsrfToken,这个方法会自动检测隐藏域Request.Form.Ncsrf,如果票据不对会报错异常:CsrfValidationException

异常会默认返回一个500错误,我们需要捕捉这个异常,并进行一些处理:

using Nancy;
using Nancy.Security;

namespace NancyCsrfDemo
{
    public class HomeModule : NancyModule
    {
        public HomeModule()
        {
            Get["/"] = p =>
            {
                return View["Index"];
            };

            Post["/"] = p =>
            {
                try
                {
                    this.ValidateCsrfToken();
                }
                catch (CsrfValidationException)
                {
                    return Response.AsText("Csrf Token not valid.").WithStatusCode(403);
                }
                
                ViewBag.Name = Request.Form.Name;
                return View["Index"];
            };
        }   
    }
}

 

这样如果票据没有验证通过的话,用户就会收到一个 403禁止访问错误,而不是500错误。

 

posted @ 2017-05-21 20:37  理论家  阅读(622)  评论(0编辑  收藏  举报
点击这里给我发消息