You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CSRF令牌无效:请求令牌始终为null导致403禁止访问

CSRF令牌为null导致403 Forbidden错误排查

问题背景

我希望在请求头中传递CSRF令牌,但发送请求时令牌始终为null,触发403 Forbidden错误。以下是相关实现代码及请求信息:

1. 主函数中CSRF中间件配置

csrfMiddleware := csrf.Protect([]byte("qwnbjb13jbhb12j3bjbbj"))
mainRouter.Use(csrfMiddleware)

serverPort := ":" + os.Getenv("SERVER_PORT")
logs.Logger.Info("starting server at ", serverPort)

err = http.ListenAndServe(serverPort, mainRouter)
if err != nil {
    logs.LogFatal(logs.Logger, "main", "main", err, "Failed to start server")
}
    logs.Logger.Info("server stopped")
}

2. 尝试在响应头中设置令牌的代码

func NewAuthHandler(authMwRouter *mux.Router, mainRouter *mux.Router, u domain.AuthUsecase) {
    handler := &AuthHandler{
        AuthUsecase: u,
    }

    mainRouter.HandleFunc("/api/v1/auth/login", handler.Login).Methods(http.MethodPost, http.MethodOptions)
    mainRouter.HandleFunc("/api/v1/auth/register", handler.Register).Methods(http.MethodPost, http.MethodOptions)
}

func (a *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-CSRF-Token", csrf.Token(r))

}

3. 请求详情

URL: http://localhost:8080/api/v1/auth/register
Method: POST
Status code: 403 Forbidden (service worker)
URL : strict-origin-when-cross-origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST,OPTIONS
Access-Control-Allow-Origin: http://localhost
Content-Length: 31
Content-Type: text/plain; charset=utf-8
Date: Mon, 06 Nov 2023 11:27:57 GMT
X-Content-Type-Options: nosniff
Content-Type: application/json;charset=utf-8
Referer: http://localhost/
Sec-Ch-Ua: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
X-Csrf-Token: null


问题分析与修复方案

核心问题

  1. 令牌生成时机错误:在POST请求的Register接口中调用csrf.Token(r)时,CSRF中间件已经在预检环节校验令牌,此时未生成有效令牌,返回null。
  2. 跨域预检请求处理缺失:浏览器发送OPTIONS预检请求时,未返回CSRF令牌,导致后续POST请求无法获取有效令牌。
  3. 中间件配置不匹配跨域场景:默认配置下CSRF令牌存储在HttpOnly Cookie中,前端无法读取,无法在请求头中携带。

修复步骤

  1. 新增令牌获取接口:创建专门的GET接口用于返回CSRF令牌,让前端先获取再发起POST请求:

    func (a *AuthHandler) GetCSRFToken(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-CSRF-Token", csrf.Token(r))
        w.WriteHeader(http.StatusOK)
    }
    

    路由注册:

    mainRouter.HandleFunc("/api/v1/csrf-token", handler.GetCSRFToken).Methods(http.MethodGet, http.MethodOptions)
    
  2. 调整CSRF中间件配置:适配跨域场景,允许前端读取Cookie中的令牌:

    csrfMiddleware := csrf.Protect(
        []byte("qwnbjb13jbhb12j3bjbbj"),
        csrf.HttpOnly(false), // 关闭HttpOnly,允许前端读取Cookie
        csrf.SameSite(csrf.SameSiteLaxMode), // 适配跨域Cookie传递
        csrf.Secure(false), // 开发环境关闭,生产环境需开启(配合HTTPS)
    )
    
  3. 完善跨域响应头:确保Access-Control-Allow-Headers包含X-CSRF-Token,避免浏览器拦截请求:

    w.Header().Set("Access-Control-Allow-Headers", "Content-Type,X-CSRF-Token")
    

前端配合操作

先请求/api/v1/csrf-token获取响应头中的X-CSRF-Token值,再在POST请求的X-CSRF-Token头中携带该值发送请求。


内容的提问来源于stack exchange,提问作者Алексей Молдованов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:53:19