CSRF(跨站请求伪造)是一种常见的 Web 应用程序安全漏洞。本 CSRF 中间件为 NexFrame框架提供了一种简单而有效的方法来防止 CSRF 攻击。它通过生成、验证和管理 CSRF 令牌来保护您的应用程序免受未经授权的请求。
首先,确保您的项目中已经安装了 Gorilla Mux。如果没有,可以通过以下命令安装:
go get -u github.com/sagoo-cloud/nexframe
然后,将 CSRF 中间件的代码文件添加到您的项目中。
最简单的使用方式是使用默认配置:
package main
import (
"net/http"
"github.com/gorilla/mux"
"github.com/sagoo-cloud/nexframe/middleware"
)
func main() {
srv := nexframe.Server()
// 使用默认配置的 CSRF 中间件
srv.WithMiddleware(middleware.CSRF())
// 注册控制器
err := srv.BindHandlerFunc("/", homeHandler).Methods("GET")
if err != nil {
return
}
err := srv.BindHandlerFunc("/", submitHandler).Methods("POST")
if err != nil {
return
}
srv.SetPort(":8080")
srv.Run()
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
// 从上下文中获取 CSRF 令牌
token := r.Context().Value("csrf").(string)
// 在表单中使用此令牌
html := `
<form method="POST" action="/submit">
<input type="hidden" name="csrf_token" value="` + token + `">
<input type="submit" value="提交">
</form>`
w.Write([]byte(html))
}
func submitHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("表单提交成功!"))
}
如果您需要更细粒度的控制,可以使用自定义配置:
config := middleware.CSRFConfig{
TokenLength: 32,
TokenLookup: "form:csrf_token,header:X-CSRF-Token",
CookieName: "my_csrf_token",
CookieMaxAge: 3600,
CookieSecure: true,
CookieHTTPOnly: true,
}
srv.WithMiddleware(middleware.CSRFWithConfig(config))
CSRFConfig
结构体提供了以下配置选项:
Skipper
: 函数类型,用于定义跳过中间件处理的条件。TokenLength
: uint8,生成的令牌的长度。TokenLookup
: string,定义如何从请求中提取令牌。ContextKey
: string,用于将生成的 CSRF 令牌存储到上下文中的键。CookieName
: string,CSRF cookie 的名称。CookieDomain
: string,CSRF cookie 的域。CookiePath
: string,CSRF cookie 的路径。CookieMaxAge
: int,CSRF cookie 的最大年龄(以秒为单位)。CookieSecure
: bool,指示 CSRF cookie 是否安全。CookieHTTPOnly
: bool,指示 CSRF cookie 是否为 HTTP only。CookieSameSite
: http.SameSite,指示 CSRF cookie 的 SameSite 模式。ErrorHandler
: 函数类型,用于自定义错误处理。
您可以自定义从请求中提取令牌的方式:
config := middleware.CSRFConfig{
TokenLookup: "header:X-CSRF-Token,form:csrf_token,query:csrf_token",
}
这将依次从 header、form 和 query 参数中查找令牌。
您可以自定义 CSRF 验证失败时的错误处理:
config := middleware.CSRFConfig{
ErrorHandler: func(err error, w http.ResponseWriter, r *http.Request) {
http.Error(w, "CSRF 验证失败", http.StatusForbidden)
},
}
使用 Skipper
函数可以跳过对特定请求的 CSRF 保护:
config := middleware.CSRFConfig{
Skipper: func(r *http.Request) bool {
return r.URL.Path == "/public-api"
},
}
- 始终在敏感操作(如表单提交、更改密码等)中使用 CSRF 保护。
- 将 CSRF 令牌作为隐藏字段包含在所有表单中。
- 对于 AJAX 请求,将令牌包含在自定义 HTTP 头中。
- 使用 HTTPS 来加密所有通信,包括 CSRF 令牌。
- 定期轮换 CSRF 令牌,特别是在用户登录或会话更新时。
- 确保
CookieSecure
和CookieHTTPOnly
在生产环境中设置为 true。
- 如果表单提交被拒绝,检查 CSRF 令牌是否正确包含在请求中。
- 确保 cookie 设置正确,特别是在使用自定义域或路径时。
- 对于 SPA(单页应用程序),确保在每次页面加载时更新 CSRF 令牌。
- 如果使用了自定义的
TokenLookup
,确保它与您的前端代码匹配。
// 后端代码
err := srv.BindHandlerFunc("/api/data", submitHandler).Methods("POST")
if err != nil {
return
}
srv
// 前端 JavaScript 代码
fetch('/api/data', {
method: 'POST',
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
CSRF 中间件为您的应用提供了一个强大而灵活的 CSRF 保护层。通过正确配置和使用这个中间件,您可以显著提高应用的安全性。记住,安全是一个持续的过程,定期审查和更新您的安全策略是很重要的。