go - 在 JSON API 调用上禁用 CSRF

标签 go

我有一个网站项目。它使用 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/

相关文章:

go - 使用 glide 添加 golang cobra 包时出错

go - 意外的模块路径 "github.com/sirupsen/logrus"

go - 使用 os/exec 命令从 Windows 交叉编译到 Linux

multidimensional-array - 戈朗 : Multidimensional array using slice of slice strategy resulting in strange output

html - Go r.FormValue 为空

go - Prometheus客户过早清理柜台?

go - 在 Iris、Party 中将路由器分组到外部文件中

javascript - Ajax 将内容类型为 Multipart 的文件上传到 GoLang 服务器

go - 将字节数组传递给插件函数

go - 捕获或分配 golang 模板输出到变量