好吧,伙计们,我正在编写一个Django应用程序,我只是想知道实际上csrf令牌是什么以及它如何保护数据.如果不使用csrf令牌,帖子数据是不安全的?
我知道如何使用csrf_token但我只需要一些信息它是如何工作的.
我试图了解CSRF的整个问题以及预防它的适当方法.(资源我已阅读,理解并同意:OWASP CSRF预防报告表,关于CSRF的问题.)
据我了解,CSRF的漏洞是通过假设(从网络服务器的角度来看)传入HTTP请求中的有效会话cookie反映经过身份验证的用户的意愿而引入的.但是,原始域的所有cookie都被浏览器神奇地附加到请求上,因此实际上所有服务器都可以通过请求中存在的有效会话cookie来推断该请求来自具有经过身份验证的会话的浏览器; 它无法进一步假设该浏览器中运行的代码,或者它是否真正反映了用户的意愿.防止这种情况的方法是在请求中包含其他身份验证信息("CSRF令牌"),这些信息由浏览器的自动cookie处理以外的某些方式携带.然后,松散地说,会话cookie验证用户/浏览器,并且CSRF令牌验证在浏览器中运行的代码.
简而言之,如果您使用会话cookie来验证Web应用程序的用户,您还应该为每个响应添加一个CSRF令牌,并在每个(变异)请求中要求匹配的CSRF令牌.然后,CSRF令牌从服务器到浏览器进行往返回服务器,向服务器证明发出请求的页面是由该服务器批准(甚至由该服务器生成).
关于我的问题,这是关于在该往返中用于该CSRF令牌的特定传输方法.
看起来很常见(例如在AngularJS,Django,Rails中)将CSRF令牌从服务器发送到客户端作为cookie(即在Set-Cookie头中),然后让客户端中的Javascript将其从cookie中删除并附加它作为单独的XSRF-TOKEN标头发送回服务器.
(另一种方法是由例如Express推荐的方法,其中由服务器生成的CSRF令牌通过服务器端模板扩展包含在响应主体中,直接附加到将其提供回服务器的代码/标记,例如作为一个隐藏的表单输入.这个例子是一个更多的Web 1.0-doh的做事方式,但是可以很好地推广给更多JS的客户端.)
为什么使用Set-Cookie作为CSRF令牌的下游传输是如此常见/为什么这是一个好主意?我想所有这些框架的作者都仔细考虑了他们的选择,并没有弄错.但乍一看,使用cookie解决基本上对cookie的设计限制似乎很愚蠢.实际上,如果您使用cookie作为往返传输(Set-Cookie:服务器的下游标头告诉浏览器CSRF令牌,而Cookie:上游标题,浏览器将其返回给服务器)您将重新引入漏洞正试图解决.
我意识到上面的框架不会使用cookie来进行CSRF令牌的整个往返; 他们使用Set-Cookie下游,然后在上游使用其他东西(例如X-CSRF-Token标头),这确实可以关闭漏洞.但即使使用Set-Cookie作为下游传输也可能具有误导性和危险性; 浏览器现在将CSRF令牌附加到每个请求,包括真正的恶意XSRF请求; 充其量只会使请求变得比它需要的更大,而在最坏的情况下,一些善意但误导的服务器代码实际上可能会尝试使用它,这将是非常糟糕的.此外,由于CSRF令牌的实际预期接收者是客户端Javascript,这意味着此cookie不能仅使用http保护.因此,在Set-Cookie标头中向下游发送CSRF令牌对我来说似乎非常不理想.
我用AJAX从视图向控制器发送数据我得到了这个错误:
警告:无法验证CSRF令牌的真实性
我想我必须发送带有数据的令牌.
有谁知道我该怎么做?
编辑:我的解决方案
我通过将以下代码放在AJAX帖子中来完成此操作:
headers: {
'X-Transaction': 'POST Example',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
Run Code Online (Sandbox Code Playgroud) 我已经在我的应用程序中实现了对我在互联网上的一些博客文章中阅读的信息后的CSRF攻击的缓解.特别是这些帖子是我实施的驱动力
基本上这些文章和建议说,为了防止CSRF攻击,任何人都应该实现以下代码:
1)添加[ValidateAntiForgeryToken]接受POST Http动词的每个动作
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}
Run Code Online (Sandbox Code Playgroud)
2)在<%= Html.AntiForgeryToken() %>向服务器提交数据的表单中添加帮助程序
<div style="text-align:right; padding: 8px;">
<%= Html.AntiForgeryToken() %>
<input type="submit" id="btnSave" value="Save" />
</div>
Run Code Online (Sandbox Code Playgroud)
无论如何,在我的应用程序的某些部分,我正在使用jQuery对服务器进行Ajax POST,而根本没有任何形式.例如,当我让用户点击图像来执行特定操作时,会发生这种情况.
假设我有一个包含活动列表的表.我在表的一列上有一个图像,上面写着"将活动标记为已完成",当用户点击该活动时,我正在进行Ajax POST,如下例所示:
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {},
success: function (response) {
// ....
}
});
});
Run Code Online (Sandbox Code Playgroud)
我如何<%= Html.AntiForgeryToken() %>在这些情况下使用?我应该在Ajax调用的data参数中包含帮助器调用吗? …
我可以通过我的AJAX帖子使用一些符合Django的CSRF保护机制的帮助.我按照这里的指示:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
我已经完全复制了他们在该页面上的AJAX示例代码:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
我getCookie('csrftoken')在xhr.setRequestHeader打电话之前打印了一个警告打印内容,确实填充了一些数据.我不确定如何验证令牌是否正确,但我鼓励它发现并发送一些东西.
但是Django仍然拒绝我的AJAX帖子.
这是我的JavaScript:
$.post("/memorize/", data, function (result) {
if (result != "failure") {
get_random_card();
}
else {
alert("Failed to save card data.");
}
});
Run Code Online (Sandbox Code Playgroud)
这是我从Django看到的错误:
[23/Feb/2011 22:08:29]"POST/memorize/HTTP/1.1"403 2332
我确定我错过了一些东西,也许这很简单,但我不知道它是什么.我一直在搜索SO,并看到一些关于通过csrf_exempt装饰器关闭CSRF检查我的视图的信息,但我发现它没有吸引力.我已经试过了,但它确实有效,但我宁愿让我的POST以Django的设计方式工作,如果可能的话.
为了防止它有用,这里是我的观点的主旨:
def myview(request):
profile = request.user.profile
if request.method == 'POST':
"""
Process the post...
"""
return HttpResponseRedirect('/memorize/')
else: # request.method == 'GET'
ajax = request.GET.has_key('ajax')
"""
Some irrelevent code...
"""
if ajax:
response = HttpResponse()
profile.get_stack_json(response)
return response
else:
"""
Get …Run Code Online (Sandbox Code Playgroud) 我在使用ajax的AntiForgeryToken遇到了麻烦.我正在使用ASP.NET MVC 3.我在jQuery Ajax调用和Html.AntiForgeryToken()中尝试了解决方案.使用该解决方案,现在正在传递令牌:
var data = { ... } // with token, key is '__RequestVerificationToken'
$.ajax({
type: "POST",
data: data,
datatype: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
url: myURL,
success: function (response) {
...
},
error: function (response) {
...
}
});
Run Code Online (Sandbox Code Playgroud)
当我删除[ValidateAntiForgeryToken]属性只是为了查看数据(带有令牌)是否作为参数传递给控制器时,我可以看到它们正在被传递.但由于某种原因,A required anti-forgery token was not supplied or was invalid.当我放回属性时,消息仍会弹出.
有任何想法吗?
编辑
antiforgerytoken是在表单中生成的,但我没有使用提交操作来提交它.相反,我只是使用jquery获取令牌的值,然后尝试ajax发布.
这是包含令牌的表单,位于顶部母版页:
<form id="__AjaxAntiForgeryForm" action="#" method="post">
@Html.AntiForgeryToken()
</form>
Run Code Online (Sandbox Code Playgroud) 从我到目前为止所学到的,令牌的目的是防止攻击者伪造表单提交.
例如,如果某个网站的表单中添加了添加到购物车中的商品,并且攻击者可能会使用您不想要的商品向您的购物车发送垃圾邮件.
这是有道理的,因为购物车表单可能有多个有效输入,攻击者必须做的就是知道网站正在销售的项目.
我理解令牌如何工作并在这种情况下增加安全性,因为它们确保用户实际填写并按下表格中的"提交"按钮以添加到购物车中的每个项目.
但是,令牌是否为用户登录表单添加了任何安全性,这需要用户名和密码?
由于用户名和密码非常独特,攻击者必须知道这两种情况才能使登录伪造工作(即使你没有设置令牌),如果攻击者已经知道这一点,他就可以登录网站本人.更不用说,使用户登录的CSRF攻击无论如何都没有任何实际意义.
我对CSRF攻击和令牌的理解是否正确?我怀疑它们对用户登录表单没用吗?
我知道基于cookie的身份验证.可以应用SSL和HttpOnly标志来保护来自MITM和XSS的基于cookie的身份验证.但是,需要采取更多特殊措施以保护其免受CSRF的影响.它们有点复杂.(参考)
最近,我发现JSON Web Token(JWT)作为身份验证的解决方案非常热门.我知道有关编码,解码和验证JWT的内容.但是,我不明白为什么有些网站/教程在使用JWT时不需要CSRF保护.我已经阅读了很多,并试图总结下面的问题.我只是希望有人可以提供JWT的全貌并澄清我对JWT误解的概念.
如果JWT存储在cookie中,我认为它与基于cookie的身份验证相同,除了服务器不需要有会话来验证cookie /令牌.如果没有实施特殊措施,CSRF仍存在风险.JWT不是存储在cookie中吗?
如果JWT存储在localStorage/sessionStorage中,那么没有cookie所以不需要防止CRSF.问题是如何将JWT发送到服务器.我发现这里建议使用jQuery通过ajax请求的HTTP头发送JWT.那么,只有ajax请求才能进行身份验证吗?
此外,我发现还有一个博客节目使用"授权标题"和"承载"来发送JWT.我不明白博客谈论的方法.有人可以解释一下"授权标题"和"持票人"的更多信息吗?这是否使所有请求的HTTP头传输JWT?如果是的话,CSRF怎么样?
我已经看过关于这个主题的文章和帖子(包括SO),而流行的评论是同源策略阻止跨域的表单POST.我见过的唯一一个人建议同源政策不适用于表格帖子,就在这里.
我想从更"官方"或正式的消息来源得到答案.例如,有没有人知道解决同源来源如何影响表格POST的RFC?
澄清:我不是在询问是否可以构建GET或POST并将其发送到任何域.我在问:
顺便提一下,如果同源不影响表单POST,那么它就会更清楚地说明为什么需要使用防伪令牌.我说"有些"因为似乎很容易相信攻击者可以简单地发出HTTP GET来检索包含防伪令牌的表单,然后进行包含相同令牌的非法POST.评论?
如果protect_from_forgery在application_controller中提到了该选项,那么我可以登录并执行任何GET请求,但是在第一次POST请求时,Rails会重置会话,这会导致我退出.
我protect_from_forgery暂时关闭了该选项,但想将它与Angular.js一起使用.有办法做到这一点吗?