我想在Go Web应用程序中实现CSRF预防.用户不登录,但他们填写表格并付款(通过Stripe Checkout).
发布内容会在会话变量(cookie)中设置一个键,以便以后可以编辑它们发布的内容,并且电子邮件中的URL允许它们在cookie过期时返回并在需要时再次编辑它.
从我所看到的情况来看,我可以使用https://code.google.com/p/xsrftoken/和"双提交cookie"方法来实施CSRF预防:
针对任意用户ID(uuid.V4()通过go-uuid)生成CSRF令牌,如下所示:
if session.Values["id"] == "" {
session.Values["id"] = uuid.NewV4()
}
csrfToken := xsrftoken.Generate(csrfKey, session.Values["id"], "/listing/new/post")
Run Code Online (Sandbox Code Playgroud)...并将其存储在会话中并将其呈现在模板中的隐藏字段中:
session.Values["csrfToken"] = csrfToken
...
<input type="hidden" id="_csrf" value={{ .csrfToken }}>
Run Code Online (Sandbox Code Playgroud)当用户提交表单时,我需要获取我生成的ID,确认csrfToken表单中提交的ID 与会话中的ID 匹配,如果是,请使用xsrf包验证它以确认它未过期:
userID := session.Values["id"]
if session.Values["csrfToken"] != r.PostFormValue("csrfToken") {
http.Redirect(w, r, "/listing/new", 400)
}
if !xsrftoken.Valid(session.Values["csrfToken"], csrfKey, userID, "/listing/new/post") {
http.Redirect(w, r, "/listing/new", 400)
}
Run Code Online (Sandbox Code Playgroud)我的相关问题是:
我应该在每次呈现表单时生成新令牌吗?或者是否可以为单个用户会话重用未过期的令牌? 更新:根据这个答案,我应该只为每个会话生成一个新令牌(即同一个用户在同一个表单上获取相同的令牌,直到令牌过期)
鉴于更新的问题,如何处理创建的令牌在用户请求表单然后提交表单之间到期的情况?(也许还有10分钟左右,他们alt +标签一段时间)重新指导他们回到表格(当然重新填充!)并生成一个新的会话ID + csrf令牌?
有没有不同的方法来做到这一点?Coding Horror表示SO为发送给客户端的每个HTML表单生成一个唯一的密钥?考虑到在生成新密钥时它需要userID,我将如何使用xsrf包继续沿着这条路线走?
还有什么我忽略了?
我应该在每次呈现表单时生成新令牌吗?或者是否可以为单个用户会话重用未过期的令牌?更新:根据这个答案,我应该只为每个会话生成一个新令牌(即同一个用户在同一个表单上获取相同的令牌,直到令牌过期)
经常重新生成令牌和会话ID是个好主意.鉴于相关的攻击者和可行的入口向量,攻击者获得两者都只是时间问题.但是,如果两个标识符中的至少一个在攻击者能够破解当前标识符之前重新生成,则没有问题.
鉴于更新的问题,如何处理创建的令牌在用户请求表单然后提交表单之间到期的情况?(也许还有10分钟左右,他们alt +标签一段时间)重新指导他们回到表格(当然重新填充!)并生成一个新的会话ID + csrf令牌?
如果您希望给客户足够的时间填写表单,可以通过AJAX更新cookie和CSRF令牌.
有没有不同的方法来做到这一点?Coding Horror表示SO为发送给客户端的每个HTML表单生成一个唯一的密钥?考虑到在生成新密钥时它需要userID,我将如何使用xsrf包继续沿着这条路线走?
令牌与需要身份验证的特定操作绑定得越紧密,您拥有的细粒度控制就越多.如果您可以在应用程序中唯一标识每个表单,那么我会说这样做.