Maison > développement back-end > Golang > Introduction à Waffle : WAF intégré à l'application pour les applications Go

Introduction à Waffle : WAF intégré à l'application pour les applications Go

Patricia Arquette
Libérer: 2025-01-05 22:42:45
original
467 Les gens l'ont consulté

Introduction

Les pare-feu d'applications Web (WAF) sont depuis longtemps une solution de sécurité standard pour protéger les applications Web. Les WAF basés sur le cloud comme AWS WAF et Cloudflare WAF sont particulièrement populaires en raison de leur facilité de mise en œuvre. Cependant, ils comportent plusieurs défis :

  • Compréhension limitée du contexte de l'application
  • Taux élevé de faux positifs
  • Implémentation de logique personnalisée restreinte

Pour relever ces défis, une nouvelle approche appelée In-app WAF ou RASP (Runtime Application Self-Protection) a retenu l'attention.

Dans cet article, je présenterai Waffle, une bibliothèque permettant d'intégrer les fonctionnalités WAF intégrées à l'application dans les applications Web Go.

  • https://sitebatch.github.io/waffle-website
  • https://github.com/sitebatch/waffle-go

Introduction to Waffle: In-app WAF for Go Applications

Qu'est-ce que le WAF/RASP intégré à l'application ?

WAF/RASP intégré à l'application n'est pas destiné à remplacer les WAF cloud existants, mais plutôt à les compléter en intégrant la fonctionnalité WAF directement dans votre application pour une protection améliorée.
Il peut gérer les attaques courantes d'applications Web telles que l'injection SQL et XSS, ainsi que les attaques de logique métier d'application telles que le credential stuffing et les tentatives de force brute.

Le principal avantage est une détection et une prévention précises grâce à une connaissance complète du contexte de la demande.

Considérez cette requête HTTP pour créer un article de blog :

POST /blog/post HTTP/1.1
...

{
  "title": "What is SQL ?"
  "body": "SQL example code: `SELECT * FROM users` ..."
}
Copier après la connexion
Copier après la connexion

Si votre application utilise des espaces réservés pour construire des instructions SQL en toute sécurité, l'injection SQL n'est pas possible. Cependant, les WAF basés sur le cloud qui s'appuient sur la correspondance de modèles bloqueraient cette requête car elle contient des modèles suspects de type SQL (la chaîne SELECT * FROM soulève des problèmes d'injection SQL).

Les développeurs se retrouvent souvent fastidieux à ajuster les paramètres, les points de terminaison ou les règles WAF pour réduire ces faux positifs. Quelle lourde tâche !

En revanche, In-app WAF / RASP comprend le contexte de la requête. Il reconnaît quand les espaces réservés ne sont pas utilisés et bloque les attaques uniquement lorsque « l'injection SQL est réellement possible ». Cette approche contextuelle entraîne moins de faux positifs et peut même contribuer à atténuer les vulnérabilités du jour zéro.

Implémentation de WAF/RASP dans l'application avec les applications Waffle in Go

Waffle est une bibliothèque qui active la fonctionnalité In-App WAF/RASP dans les applications Web Go.

Voyons comment intégrer Waffle dans votre application et comment il prévient les attaques.

Exemple d'application

Bien que cet exemple utilise le net/http de la bibliothèque standard, Waffle prend également en charge d'autres bibliothèques comme Gin et GORM.
Pour plus de détails, consultez la documentation des bibliothèques prises en charge.

L'application suivante présente une vulnérabilité d'injection SQL dans le point de terminaison /login :

POST /blog/post HTTP/1.1
...

{
  "title": "What is SQL ?"
  "body": "SQL example code: `SELECT * FROM users` ..."
}
Copier après la connexion
Copier après la connexion
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
}
Copier après la connexion

Intégration de Waffle pour empêcher l'injection SQL

Intégrons Waffle pour empêcher l'injection 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
Copier après la connexion

Modifiez main.go comme suit :

$ go get github.com/sitebatch/waffle-go
Copier après la connexion

Les changements sont minimes :

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
}
Copier après la connexion

Maintenant, lorsque nous essayons une attaque par injection SQL, Waffle la bloque :

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)
    }
Copier après la connexion

Ce code HTML est le message d'erreur renvoyé par défaut par Waffle et ressemble à ceci :

Introduction to Waffle: In-app WAF for Go Applications

Si vous utilisez des espaces réservés :

Lors de l'utilisation d'espaces réservés, Waffle reconnaît que l'injection SQL n'est pas possible et ne bloquera pas la requête :

$ 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>
Copier après la connexion
# 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
    }
Copier après la connexion

Notez que même dans ce cas, Waffle peut toujours détecter les tentatives d'injection SQL comme un WAF basé sur le cloud (bien qu'il ne la bloque pas) :

# 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
Copier après la connexion

Attaques détectées et empêchées par Waffle

Bien que nous ayons démontré la prévention des injections SQL, Waffle peut détecter et prévenir diverses attaques :

  • Reconnaissance par des scanners de sécurité connus
  • Parcours de répertoire
  • XSS
  • Injection SQL
  • Accès aux fichiers sensibles
  • SSRF
  • Reprise de compte

Pour plus de détails, consultez la documentation sur la liste des règles.

Les règles sont continuellement mises à jour et les contributions sont les bienvenues.

Conclusion

En intégrant Waffle dans votre application, vous pouvez détecter et prévenir avec précision les attaques.

Pour les guides de mise en œuvre spécifiques au framework et les instructions d'utilisation détaillées, reportez-vous à la section Guides de la documentation.

Waffle est en cours de développement actif. Nous apprécions les commentaires et les contributions.

  • https://github.com/sitebatch/waffle-go

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal