我有一个网站项目。它使用 Go 和 Gorilla 及其 CSRF 包来防御 CSRF。我还有一个 JSON API,它使用类似 token 提供程序(内部)的 JWT 进行身份验证,因此用户每次发出 JSON 请求之前都必须使用该 API 进行身份验证。所以 CSRF 在 JSON 方面不是问题。至少我不这么认为。
这是我的代码,其中我使用 NewRouter 作为 Web 路径,并使用 Subrouter 作为/api/v1/[endpoint]。如果我调用执行 POST 的 JSON 端点,则会使用 CSRF,并且我会收到 Forbidden - CSRF token 无效。我的假设是,子路由器可能没有与 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)))
问题: 如何让我的 API 在有或没有 CSRF 保护的情况下工作?显然,需要保护网络路径以保护表单帖子。
最佳答案
一种选择是仅在特定 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),
)
关于go - 在 JSON API 调用上禁用 CSRF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53271241/