我有一个网站项目。它使用Go和Gorilla及其CSRF软件包来防御CSRF。我还有一个JSON API,该令牌使用JWT之类的令牌提供程序(内部)进行身份验证,因此用户必须在每次发出JSON请求之前对此进行身份验证。因此,CSRF在JSON方面不是问题。至少我不这么认为。
这是我的代码,其中我将NewRouter用于Web路径,并将子路由器用于/ api / v1 / [endpoint] s。如果我调用执行POST的JSON端点,则CSRF已启用,并且我收到了禁止-CSRF令牌无效的信息。我当时假设,子路由器可能没有与CSRF检查相关的中间件。
router := mux.NewRouter().StrictSlash(false)
router.Path("/").HandlerFunc(myApp.IndexHandler).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(":8000",
csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false), // Set to false as we offload SSL elsewhere
)(router)))
问题: 如何在没有CSRF保护的情况下使用我的API?显然,将需要保护Web路径以保护表单帖子。
答案 0 :(得分:2)
一种选择是仅在特定的HTTP处理程序上使用CSRF保护,而不是保护整个路由器。请注意,这将要求您对myApp.IndexHandler
执行类型转换,以满足csrf.Protect()
返回的函数的类型签名。
router := mux.NewRouter().StrictSlash(false)
// Instead of protecting your entire router, you can protect specific HTTP
// handlers.
router.Path("/").Handler(
csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false),
)(http.HandlerFunc(myApp.IndexHandler)),
).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(
":8000",
router,
)
或者,您可以使用csrf.Protect()
返回的函数来创建自己的中间件,并具有仅对某些请求添加CSRF保护的逻辑。例如,您可以使用这种方法仅在前缀为/api
的端点上添加保护,就像我在下面的代码中所做的那样。
protectionMiddleware := func(handler http.Handler) http.Handler {
protectionFn := csrf.Protect(
[]byte("my-long-key-here-redacted"),
csrf.Secure(false),
)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Use some kind of condition here to see if the router should use
// the CSRF protection. For the sake of this example, we'll check
// the path prefix.
if !strings.HasPrefix(r.URL.Path, "/api") {
protectionFn(handler).ServeHTTP(w, r)
return
}
handler.ServeHTTP(w, r)
})
}
router := mux.NewRouter().StrictSlash(false)
router.Path("/").HandlerFunc(myApp.IndexHandler).Methods("GET")
apiRouter := router.PathPrefix("/api").Subrouter()
apiRouter.Path("/dosomething").HandlerFunc(myApp.DoSomethingAPIHandler).Methods("POST", "OPTIONS")
http.ListenAndServe(
":8000",
protectionMiddleware(router),
)