Waffle 简介:Go 应用程序的应用内 WAF
介绍
Web 应用程序防火墙 (WAF) 长期以来一直是保护 Web 应用程序的标准安全解决方案。 AWS WAF 和 Cloudflare WAF 等基于云的 WAF 由于易于实施而特别受欢迎。然而,它们也面临着一些挑战:
- 对应用程序上下文的了解有限
- 误报率高
- 受限的自定义逻辑实现
为了应对这些挑战,一种称为应用内 WAF 或 RASP(运行时应用程序自我保护)的新方法正在引起人们的关注。
在这篇文章中,我将介绍 Waffle,一个用于将应用内 WAF 功能集成到 Go Web 应用程序中的库。
- https://sitebatch.github.io/waffle-website
- https://github.com/sitebatch/waffle-go
什么是应用内 WAF/RASP?
应用内 WAF/RASP 并不是要取代现有的云 WAF,而是通过将 WAF 功能直接嵌入到您的应用程序中来补充它们,以增强保护。
它可以处理常见的 Web 应用程序攻击,例如 SQL 注入和 XSS,以及应用程序业务逻辑攻击,例如撞库和暴力尝试。
主要优势是通过完整的请求上下文感知来准确检测和预防。
考虑这个用于创建博客文章的 HTTP 请求:
POST /blog/post HTTP/1.1 ... { "title": "What is SQL ?" "body": "SQL example code: `SELECT * FROM users` ..." }
如果您的应用程序使用占位符来安全地构造 SQL 语句,则 SQL 注入是不可能的。但是,依赖于模式匹配的基于云的 WAF 会阻止此请求,因为它包含可疑的类似 SQL 的模式(字符串 SELECT * FROM 会引发 SQL 注入问题)。
开发人员经常发现自己需要繁琐地调整参数、端点或 WAF 规则来减少这些误报。好麻烦的任务啊!
相比之下,应用内 WAF / RASP 可以理解请求上下文。它可以识别何时未使用占位符,并且仅在“实际上可能发生 SQL 注入”时阻止攻击。这种上下文感知方法可以减少误报,甚至可以帮助缓解零日漏洞。
在 Go 应用程序中使用 Waffle 实现应用内 WAF/RASP
Waffle 是一个在 Go Web 应用程序中启用应用内 WAF / RASP 功能的库。
让我们看看如何将 Waffle 集成到您的应用程序中以及它如何防止攻击。
应用示例
虽然此示例使用标准库的 net/http,但 Waffle 还支持其他库,例如 Gin 和 GORM。
有关更多详细信息,请查看支持的库文档。
以下应用程序在 /login 端点中存在 SQL 注入漏洞:
POST /blog/post HTTP/1.1 ... { "title": "What is SQL ?" "body": "SQL example code: `SELECT * FROM users` ..." }
package main import ( "context" "database/sql" "fmt" "net/http" _ "github.com/mattn/go-sqlite3" ) var database *sql.DB func init() { setupDB() } func newHTTPHandler() http.Handler { mux := http.NewServeMux() mux.Handle("/login", http.HandlerFunc(loginController)) return mux } func main() { srv := &http.Server{ Addr: ":8000", Handler: newHTTPHandler(), } srv.ListenAndServe() } func loginController(w http.ResponseWriter, r *http.Request) { email := r.FormValue("email") password := r.FormValue("password") if err := login(r.Context(), email, password); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write([]byte("Login success")) } func login(ctx context.Context, email, password string) error { // ⚠️ SQL INJECTION VULNERABILITY rows, err := database.QueryContext(ctx, fmt.Sprintf("SELECT * FROM users WHERE email = '%s' AND password = '%s'", email, password)) if err != nil { return err } defer rows.Close() if !rows.Next() { return fmt.Errorf("invalid email or password") } // do something return nil } func setupDB() { db, err := sql.Open("sqlite3", "file::memory:?cache=shared") if err != nil { panic(err) } if _, err := db.Exec("CREATE TABLE users(id int, email text, password text);"); err != nil { panic(err) } if _, err := db.Exec("INSERT INTO users(id, email, password) VALUES(1, 'user@example.com', 'password');"); err != nil { panic(err) } database = db }
集成Waffle防止SQL注入
让我们集成Waffle来防止SQL注入:
$ go run . # SQL injection attack $ curl -i -X POST 'http://localhost:8000/login' \ --data "email=user@example.com' OR 1=1--&password=" HTTP/1.1 200 OK Date: Sun, 05 Jan 2025 10:32:50 GMT Content-Length: 13 Content-Type: text/plain; charset=utf-8 Login success
修改main.go如下:
$ go get github.com/sitebatch/waffle-go
变化很小:
package main import ( "context" "database/sql" "errors" "fmt" "net/http" "github.com/sitebatch/waffle-go" "github.com/sitebatch/waffle-go/action" waffleSQL "github.com/sitebatch/waffle-go/contrib/database/sql" waffleHTTP "github.com/sitebatch/waffle-go/contrib/net/http" _ "github.com/mattn/go-sqlite3" ) var database *sql.DB func init() { setupDB() } func newHTTPHandler() http.Handler { mux := http.NewServeMux() mux.Handle("/login", http.HandlerFunc(loginController)) handler := waffleHTTP.WafMiddleware(mux) return handler } func main() { srv := &http.Server{ Addr: ":8000", Handler: newHTTPHandler(), } // Start waffle with debug mode waffle.Start(waffle.WithDebug()) srv.ListenAndServe() } func loginController(w http.ResponseWriter, r *http.Request) { email := r.FormValue("email") password := r.FormValue("password") if err := login(r.Context(), email, password); err != nil { var actionErr *action.BlockError if errors.As(err, &actionErr) { return } http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write([]byte("Login success")) } func login(ctx context.Context, email, password string) error { // ⚠️ SQL INJECTION VULNERABILITY rows, err := database.QueryContext(ctx, fmt.Sprintf("SELECT * FROM users WHERE email = '%s' AND password = '%s'", email, password)) if err != nil { return err } defer rows.Close() if !rows.Next() { return fmt.Errorf("invalid email or password") } // do something return nil } func setupDB() { db, err := waffleSQL.Open("sqlite3", "file::memory:?cache=shared") if err != nil { panic(err) } if _, err := db.Exec("CREATE TABLE users(id int, email text, password text);"); err != nil { panic(err) } if _, err := db.Exec("INSERT INTO users(id, email, password) VALUES(1, 'user@example.com', 'password');"); err != nil { panic(err) } database = db }
现在,当我们尝试 SQL 注入攻击时,Waffle 会阻止它:
diff --git a/main.go b/main.go index 90b8197..9fefb06 100644 --- a/main.go +++ b/main.go @@ -3,9 +3,15 @@ package main import ( "context" "database/sql" + "errors" "fmt" "net/http" + "github.com/sitebatch/waffle-go" + "github.com/sitebatch/waffle-go/action" + waffleSQL "github.com/sitebatch/waffle-go/contrib/database/sql" + waffleHTTP "github.com/sitebatch/waffle-go/contrib/net/http" + _ "github.com/mattn/go-sqlite3" ) @@ -19,7 +25,9 @@ func newHTTPHandler() http.Handler { mux := http.NewServeMux() mux.Handle("/login", http.HandlerFunc(loginController)) - return mux + handler := waffleHTTP.WafMiddleware(mux) + + return handler } func main() { @@ -28,6 +36,9 @@ func main() { Handler: newHTTPHandler(), } + // Start waffle with debug mode + waffle.Start(waffle.WithDebug()) + srv.ListenAndServe() } @@ -36,6 +47,11 @@ func loginController(w http.ResponseWriter, r *http.Request) { password := r.FormValue("password") if err := login(r.Context(), email, password); err != nil { + var actionErr *action.BlockError + if errors.As(err, &actionErr) { + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -60,7 +76,7 @@ func login(ctx context.Context, email, password string) error { } func setupDB() { - db, err := sql.Open("sqlite3", "file::memory:?cache=shared") + db, err := waffleSQL.Open("sqlite3", "file::memory:?cache=shared") if err != nil { panic(err) }
此 HTML 是 waffle 默认返回的错误消息,如下所示:
如果使用占位符:
使用占位符时,Waffle 会识别出不可能进行 SQL 注入,并且不会阻止请求:
$ curl -i -X POST 'http://localhost:8000/login' \ --data "email=user@example.com' OR 1=1--&password=" -i HTTP/1.1 403 Forbidden Date: Sun, 05 Jan 2025 10:38:22 GMT Content-Length: 1574 Content-Type: text/html; charset=utf-8 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Access Denied</title>
# Fix SQL injection vulnerability diff --git a/main.go b/main.go index 9fefb06..5b482f2 100644 --- a/main.go +++ b/main.go @@ -60,7 +60,7 @@ func loginController(w http.ResponseWriter, r *http.Request) { } func login(ctx context.Context, email, password string) error { - rows, err := database.QueryContext(ctx, fmt.Sprintf("SELECT * FROM users WHERE email = '%s' AND password = '%s'", email, password)) + rows, err := database.QueryContext(ctx, "SELECT * FROM users WHERE email = ? AND password = ?", email, password) if err != nil { return err }
请注意,即使在这种情况下,Waffle 仍然可以像基于云的 WAF 一样检测尝试的 SQL 注入(尽管它不会阻止它):
# Waffle won't block the request since SQL injection isn't possible $ curl -i -X POST 'http://localhost:8000/login' \ --data "email=user@example.com' OR 1=1--&password=" HTTP/1.1 500 Internal Server Error Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff Date: Sun, 05 Jan 2025 10:49:05 GMT Content-Length: 26 invalid email or password
Waffle 检测和预防的攻击
虽然我们已经演示了 SQL 注入预防,但 Waffle 可以检测并防止各种攻击:
- 已知安全扫描仪的侦察
- 目录遍历
- XSS
- SQL注入
- 敏感文件访问
- SSRF
- 帐户接管
有关更多详细信息,请查看规则列表文档。
规则持续更新,欢迎贡献。
结论
通过将 Waffle 集成到您的应用程序中,您可以准确地检测和预防攻击。
特定于框架的实现指南和详细使用说明,请参阅文档中的指南部分。
Waffle 正在积极开发中。我们欢迎反馈和贡献。
- https://github.com/sitebatch/waffle-go
以上是Waffle 简介:Go 应用程序的应用内 WAF的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Go语言在构建高效且可扩展的系统中表现出色,其优势包括:1.高性能:编译成机器码,运行速度快;2.并发编程:通过goroutines和channels简化多任务处理;3.简洁性:语法简洁,降低学习和维护成本;4.跨平台:支持跨平台编译,方便部署。

Golang在并发性上优于C ,而C 在原始速度上优于Golang。1)Golang通过goroutine和channel实现高效并发,适合处理大量并发任务。2)C 通过编译器优化和标准库,提供接近硬件的高性能,适合需要极致优化的应用。

Golang和Python各有优势:Golang适合高性能和并发编程,Python适用于数据科学和Web开发。 Golang以其并发模型和高效性能着称,Python则以简洁语法和丰富库生态系统着称。

Golang在性能和可扩展性方面优于Python。1)Golang的编译型特性和高效并发模型使其在高并发场景下表现出色。2)Python作为解释型语言,执行速度较慢,但通过工具如Cython可优化性能。

Golang和C 在性能竞赛中的表现各有优势:1)Golang适合高并发和快速开发,2)C 提供更高性能和细粒度控制。选择应基于项目需求和团队技术栈。

GoimpactsdevelopmentPositationalityThroughSpeed,效率和模拟性。1)速度:gocompilesquicklyandrunseff,ifealforlargeprojects.2)效率:效率:ITScomprehenSevestAndArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdEcceSteral Depentencies,增强开发的简单性:3)SimpleflovelmentIcties:3)简单性。

C 更适合需要直接控制硬件资源和高性能优化的场景,而Golang更适合需要快速开发和高并发处理的场景。1.C 的优势在于其接近硬件的特性和高度的优化能力,适合游戏开发等高性能需求。2.Golang的优势在于其简洁的语法和天然的并发支持,适合高并发服务开发。

Golang和C 在性能上的差异主要体现在内存管理、编译优化和运行时效率等方面。1)Golang的垃圾回收机制方便但可能影响性能,2)C 的手动内存管理和编译器优化在递归计算中表现更为高效。
