基于Go后端与Vue前端的CSRF防护实现方法问询
嗨Julia,我来帮你一步步搞定Vue+Go栈的CSRF防护,结合gorilla/csrf的最佳实践落地——既然你的Go服务器要负责渲染Vue应用,这中间有几个关键步骤得捋清楚:
第一步:配置Go后端的gorilla/csrf中间件
首先得确保你的Go Web服务器正确集成gorilla/csrf,核心是配置中间件,并且把CSRF Token注入到Vue的入口页面里(因为Go要渲染Vue应用)。
以下是完整的Go代码示例:
package main import ( "net/http" "html/template" "github.com/gorilla/csrf" "github.com/gorilla/mux" ) func main() { r := mux.NewRouter() // 生产环境务必从环境变量读取密钥,别硬编码! csrfKey := []byte("your-32-byte-secret-key-here") // 配置CSRF中间件,关键参数要注意: csrfMiddleware := csrf.Protect( csrfKey, csrf.Secure(true), // 生产环境必须开启(HTTPS下生效),本地测试可设为false csrf.HttpOnly(true), // 开启这个防止XSS窃取cookie中的token csrf.FieldName("X-CSRF-Token"), // 和前端axios的请求头名称对应 csrf.ErrorHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "CSRF Token无效", http.StatusForbidden) })), ) // 托管Vue打包后的静态文件(dist目录) r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./dist/static")))) // API路由必须经过CSRF中间件校验 apiRouter := r.PathPrefix("/api").Subrouter() apiRouter.Use(csrfMiddleware) apiRouter.HandleFunc("/submit", submitHandler).Methods("POST") // 核心:处理根路径,渲染Vue的index.html并注入CSRF Token r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // 从请求上下文获取当前的CSRF Token token := csrf.Token(r) // 加载Vue的index.html模板 tpl, err := template.ParseFiles("./dist/index.html") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // 将Token传入模板,用于在页面中渲染 templateData := map[string]string{ "CSRFToken": token, } tpl.Execute(w, templateData) }) http.ListenAndServe(":8080", r) } func submitHandler(w http.ResponseWriter, r *http.Request) { // 这里的请求已经通过CSRF校验,放心处理业务逻辑 w.WriteHeader(http.StatusOK) w.Write([]byte("请求处理成功")) }
第二步:Vue前端获取并携带CSRF Token
因为Go会渲染Vue的入口页面,我们可以在页面中注入Token,然后前端读取并在请求中携带:
1. 在Vue的入口页面注入Token
修改Vue项目的public/index.html(开发环境),或者打包后的dist/index.html(生产环境),添加一个隐藏的input标签(和你原代码的选择器对应):
<!-- 隐藏input,用于存储CSRF Token --> <input type="hidden" name="gorilla.csrf.Token" value="{{.CSRFToken}}">
如果你觉得input不够优雅,也可以用meta标签:
<meta name="csrf-token" content="{{.CSRFToken}}">,后续前端读取方式对应调整即可。
2. 调整Axios配置,携带Token
你的原代码已经接近正确,只需要做一点小调整,确保能稳定获取Token,同时处理Token过期的情况:
// 获取CSRF Token(和页面中的标签对应) let csrfToken = document.getElementsByName("gorilla.csrf.Token")[0].value; // 如果用meta标签的话,改成: // let csrfToken = document.querySelector('meta[name="csrf-token"]').content; // 创建Axios实例,全局携带CSRF Token const instance = axios.create({ baseURL: "/api/", // 用相对路径避免跨域问题 timeout: 1000, headers: { "X-CSRF-Token": csrfToken } }); // 发起POST请求的逻辑 try { const resp = await instance.post(endpoint, formData); // 处理响应数据 console.log(resp.data); } catch (err) { // 处理异常:如果是CSRF Token无效/过期,刷新页面重新获取 if (err.response?.status === 403) { window.location.reload(); } else { // 其他错误处理逻辑 console.error("请求失败:", err); } }
关键安全注意事项
- 生产环境必开HTTPS:一定要保持
csrf.Secure(true),确保CSRF Cookie只在HTTPS连接下传输。 - 避免直接读取Cookie:尽量用页面注入Token的方式(而非让前端读取Cookie),因为
HttpOnly(true)可以防止XSS攻击窃取Cookie中的Token,这是更安全的做法。 - 跨域场景特殊处理:如果Vue和Go不在同一域名下,需要配置CORS,允许
X-CSRF-Token请求头传递,同时设置Cookie的SameSite属性为Lax或None(跨域时)。
内容的提问来源于stack exchange,提问作者Julia12
相关产品推荐
相关产品推荐

