csrf防御

csrf介绍

CSRF(Cross-site request forgery)跨站请求伪造,也被称为One Click Attack或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

攻击案例

攻击通过在授权用户访问的页面中包含链接或者脚本的方式工作。例如:一个网站用户Bob可能正在浏览聊天论坛,而同时另一个用户Alice也在此论坛中,并且后者刚刚发布了一个具有Bob银行链接的图片消息。设想一下,Alice编写了一个在Bob的银行站点上进行取款的form提交的链接,并将此链接作为图片src。如果Bob的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当Bob的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经Bob同意的情况下便授权了这次事务。CSRF是一种依赖web浏览器的、被混淆过的代理人攻击(deputy attack)。在上面银行示例中的代理人是Bobweb浏览器,它被混淆后误将Bob的授权直接交给了Alice使用

CSRF防御

  • 通过referer,token 或者验证码来检测用户提交
  • 尽量不要在页面的链接中暴露用户隐私信息
  • 对于用户修改删除等操作最好都使用post操作
  • 避免全站通用的cookie,严格设置cookie的域

目录结构

主目录csrf

  1. —— main.go
  2. —— views
  3. —— user
  4. —— signup.html

代码示例

main.go

  1. //此中间件提供跨站点请求伪造保护
  2. //它安全地生成一个掩码(每个请求唯一)令牌
  3. //可以嵌入HTTP响应中(例如表单字段或HTTP标头)。
  4. //原始令牌存储在会话中,该会话无法访问
  5. // 攻击者(如果您使用的是HTTPS后续请求是 期望包含此令牌,该令牌与会话令牌进行比较。
  6. //匹配令牌失败包HTTP 403 Forbidden 错误响应。
  7. package main
  8. // $ go get -u github.com/iris-contrib/middleware/...
  9. import (
  10. "github.com/kataras/iris"
  11. "github.com/iris-contrib/middleware/csrf"
  12. )
  13. func main() {
  14. app := iris.New()
  15. app.RegisterView(iris.HTML("./views", ".html"))
  16. //请注意,提供的身份验证密钥应为32个字节应用程序重新启动时保持不变
  17. protect := csrf.Protect([]byte("9AB0F421E53A477C084477AEA06096F5")
  18. csrf.Secure(false)) //默认为true,但在没有https(devmode)的情况下传递`false`
  19. users := app.Party("/user", protect)
  20. {
  21. users.Get("/signup", getSignupForm)
  22. //没有有效令牌的POST请求将返回HTTP 403 Forbidden。
  23. users.Post("/signup", postSignupForm)
  24. }
  25. // GET: http://localhost:8080/user/signup
  26. // POST: http://localhost:8080/user/signup
  27. app.Run(iris.Addr(":8080"))
  28. }
  29. func getSignupForm(ctx iris.Context) {
  30. // views/user/signup.html只需要一个{{.csrfField}}模板标记
  31. // csrf.TemplateField将CSRF令牌注入即可!
  32. ctx.ViewData(csrf.TemplateTag, csrf.TemplateField(ctx))
  33. ctx.View("user/signup.html")
  34. //我们也可以直接从csrf.Token(ctx)中获取检索令牌
  35. //在请求标头中设置它 - ctx.GetHeader("X-CSRF-Token",token)
  36. //如果您要向客户端或前端JavaScript发送JSON,这将非常有用
  37. //框架
  38. }
  39. func postSignupForm(ctx iris.Context) {
  40. ctx.Writef("You're welcome mate!")
  41. }

/views/user/signup.html

  1. <form method="POST" action="/user/signup">
  2. {{ .csrfField }}
  3. <button type="submit">Proceed</button>
  4. </form>