组队大项目--防止CSRF攻击 | 青训营笔记

68 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第10天

CSRF是CROSS Site Request Forgy的缩写,即跨站请求伪造。我们看下他的攻击原理。

当用户访问一个网站的时候,第一次登录完成后,网站会将验证的相关信息保存在浏览器的cookie中。在对该网站的后续访问中,浏览器会自动携带该站点下的cookie信息,以便服务器校验认证信息。

因此,当服务器经过用户认证之后,服务器对后续的请求就只认cookie中的认证信息,不再区分请求的来源了。那么,攻击者就可以模拟一个正常的请求来做一些影响正常用户利益的事情。

如何预防

常见的有3种方法:

一种是在网站中增加对请求来源的验证,比如在请求头中增加REFFER信息。

一种是在浏览器中启用SameSite策略。该策略是告诉浏览器,只有请求来源是同网站的才能发送cookie,跨站的请求不要发送cookie。但这种也有漏洞,就是依赖于浏览器是否支持这种策略。

一种是使用Token信息。由网站自己决定token的生成策略以及对token的验证。

其中使用Token信息这种是三种方法中最安全的一种。接下来我们就看看今天要推荐的CSRF包是如何利用token进行预防的。

可以实现防止CSRF攻击,使用gorilla/csrf package和gin结合即可。具体代码如下:

var csrfMd func(http.Handler) http.Handler

func CSRF() gin.HandlerFunc {
   csrfMd = csrf.Protect(
      []byte("THEVG76TJJXLYS0J5WCJ8XB928VWMFQW"),
      csrf.Secure(false),
      csrf.HttpOnly(true),
      csrf.ErrorHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
         w.WriteHeader(http.StatusForbidden)
         w.Write([]byte(`{"message": "Forbidden - CSRF token invalid"}`))
      })),
   )
   return adapter.Wrap(csrfMd)
}

func CSRFToken() gin.HandlerFunc {
   return func(c *gin.Context) {
      c.Header("X-CSRF-Token",csrf.Token(c.Request))
   }
}

func main() {
   Init()
   r := gin.New()
   if conf.Server.RunMode == "debug" {
      r.Use(gin.Logger(), gin.Recovery())
   } else {
      gin.SetMode(gin.ReleaseMode)
   }
   r.Use(CSRF())
   r.Use(CSRFToken())

首先通过csrf.Protect函数生成一个中间件或请求处理器,然后在启动web server时对真实的请求处理器进行包装。get请求的时候就会拿到X-Csrf-Token,然后post操作都得带上该X-Csrf-Token在header里,即可完成验证。

CSRF攻击是基于将验证信息存储于cookie中,同时浏览器在发送请求时会自动携带cookie的原理进行的。所以,其预防原理也就是验证请求来源的真实性。csrf包就是利用了token校验的原理,让前后连续的请求签发token、下次请求验证token的方式进行预防的。