首页 后端开发 Golang Waffle 简介:Go 应用程序的应用内 WAF

Waffle 简介:Go 应用程序的应用内 WAF

Jan 05, 2025 pm 10:42 PM

介绍

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

Introduction to Waffle: In-app WAF for Go Applications

什么是应用内 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 默认返回的错误消息,如下所示:

Introduction to Waffle: In-app WAF for Go Applications

如果使用占位符:

使用占位符时,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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1653
14
CakePHP 教程
1413
52
Laravel 教程
1304
25
PHP教程
1251
29
C# 教程
1224
24
Golang的目的:建立高效且可扩展的系统 Golang的目的:建立高效且可扩展的系统 Apr 09, 2025 pm 05:17 PM

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

Golang和C:并发与原始速度 Golang和C:并发与原始速度 Apr 21, 2025 am 12:16 AM

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

Golang vs. Python:主要差异和相似之处 Golang vs. Python:主要差异和相似之处 Apr 17, 2025 am 12:15 AM

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

Golang vs. Python:性能和可伸缩性 Golang vs. Python:性能和可伸缩性 Apr 19, 2025 am 12:18 AM

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

表演竞赛:Golang vs.C 表演竞赛:Golang vs.C Apr 16, 2025 am 12:07 AM

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

Golang的影响:速度,效率和简单性 Golang的影响:速度,效率和简单性 Apr 14, 2025 am 12:11 AM

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

C和Golang:表演至关重要时 C和Golang:表演至关重要时 Apr 13, 2025 am 12:11 AM

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

Golang和C:性能的权衡 Golang和C:性能的权衡 Apr 17, 2025 am 12:18 AM

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

See all articles