我想在我的 Go Web 应用程序中实现 CSRF 预防。用户无需登录,但他们会填写表格并付款(通过 Stripe Checkout)。
发布内容会在会话变量 (cookie) 中设置一个密钥,以便他们稍后可以编辑他们发布的内容,并且电子邮件中的 URL 允许他们在 cookie 过期时返回并在需要时再次编辑它。
据我所知,我可以使用https://code.google.com/p/xsrftoken/和“双重提交 cookie”方法来实现 CSRF 预防:
针对任意用户 ID(通过go-uuid uuid.V4())生成 CSRF 令牌,如下所示:
if session.Values["id"] == "" { session.Values["id"] = uuid.NewV4() } csrfToken := xsrftoken.Generate(csrfKey, session.Values["id"], "/listing/new/post")
...并将其存储在会话中并将其呈现在模板中的隐藏字段中:
session.Values["csrfToken"] = csrfToken ... <input type="hidden" id="_csrf" value={{ .csrfToken }}>
当用户提交表单时,我需要获取我生成的 ID,确认
csrfToken
从表单提交的与会话中的匹配,如果是,则使用 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) }
我的相关问题是:
每次呈现表单时我是否应该生成一个新令牌?或者是否可以为单个用户会话重新使用未过期的令牌? 更新:根据这个答案,我应该只为每个会话生成一个新令牌(即同一个用户在同一个表单上获得相同的令牌,直到令牌过期)
鉴于更新的问题,我该如何处理在用户请求表单和提交表单之间创建的令牌过期的情况?(也许还剩 10 分钟,他们 alt+tab 了一段时间)将它们重定向回表单(当然是重新填充!)并生成一个新的会话 id + csrf 令牌?
有不同的方法可以做到这一点吗?Coding Horror表示 SO 会为发送给客户端的每个 HTML 表单生成一个唯一的密钥?考虑到在生成新密钥时它需要一个用户 ID,我将如何使用 xsrf 包沿着这条路线走下去?
我还忽略了什么?