Getting StartedBasic

Getting Started

Here, we will explain how to protect an application using Waffle with a sample application.

Example application

The following examples use a web application built with standard libraries. However, you don’t need to be using these libraries specifically - Waffle can be used with other libraries such as Gin and GORM.
For a complete list of supported libraries, please refer to the contrib directory in the repository or supported libraries page.

Protecting example application

Full example code is available at example/basic directory

To protect an example application built with net/http, you simply need to add the Waffle middleware.

package main
 
import (
	"net/http"
 
	"github.com/sitebatch/waffle-go"
	waffleHttp "github.com/sitebatch/waffle-go/contrib/net/http"
)
 
func main() {
	// Start waffle with debug mode
    waffle.Start(waffle.WithDebug())
 
	srv := &http.Server{
		Addr:    ":8000",
		Handler: newHTTPHandler(),
	}
 
	srv.ListenAndServe()
}
 
func ping(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("pong"))
}
 
func newHTTPHandler() http.Handler {
	mux := http.NewServeMux()
	mux.Handle("/ping", http.HandlerFunc(ping))
 
    // Add Waffle middleware
	handler := waffleHttp.WafMiddleware(mux)
	return handler
}

To verify the effect of this middleware, run the following command.

$ go run main.go
 
# Access the server
$ curl -i http://localhost:8000/ping
HTTP/1.1 200 OK
Date: Thu, 26 Dec 2024 12:49:41 GMT
Content-Length: 4
Content-Type: text/plain; charset=utf-8
 
pong

Next, send a directory traversal attack request.

$ curl -i 'http://localhost:8000/ping?file=../../../../../etc/hosts'
HTTP/1.1 200 OK
Date: Thu, 26 Dec 2024 12:49:41 GMT
Content-Length: 4
Content-Type: text/plain; charset=utf-8
 
pong

This request attempts directory traversal, but the application does not have a file reading function.
Therefore, Waffle does not block this request. However, this request is logged.

level=INFO msg="[waffle] Threat detected: detected match \\.\\./" ruleID=directory-traversal-attempts inspector=regex clientIP=[::1]:55612 url="http://localhost:8000/ping?file=../../../"

Now, let’s see how to prevent attacks if the application has a file reading function.
Waffle can prevent attacks “more accurately” by propagating context. This context-aware approach allows you to maintain effective defense while reducing false positives.

package main
 
import (
	"net/http"
 
	"github.com/sitebatch/waffle-go"
	waffleHttp "github.com/sitebatch/waffle-go/contrib/net/http"
	waffleOs "github.com/sitebatch/waffle-go/contrib/os"
)
 
func main() {
	// Start waffle with debug mode
    waffle.Start(waffle.WithDebug())
 
	srv := &http.Server{
		Addr:    ":8000",
		Handler: newHTTPHandler(),
	}
 
	srv.ListenAndServe()
}
 
func ping(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("pong"))
}
 
// readFile reads a file from the path specified in the query parameter.
// This function has a vulnerability that allows any file to be read, but it is protected by Waffle.
func readFile(w http.ResponseWriter, r *http.Request) {
    path := r.URL.Query().Get("file")
 
    // Protect the file read operations
    if _, err := waffleOs.ProtectReadFile(r.Context(), path); err != nil {
        var actionErr *action.BlockError
        if errors.As(err, &actionErr) {
            return
        }
 
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
 
    w.Write([]byte("file read"))
}
 
func newHTTPHandler() http.Handler {
	mux := http.NewServeMux()
	mux.Handle("/ping", http.HandlerFunc(ping))
	mux.Handle("/get-file", http.HandlerFunc(readFile))
 
	handler := waffleHttp.WafMiddleware(mux)
	return handler
}

To verify that the attack request is blocked, run the following command.

$ curl -i 'http://localhost:8000/get-file?file=main.go'
HTTP/1.1 200 OK
Date: Thu, 26 Dec 2024 14:19:34 GMT
Content-Length: 9
Content-Type: text/plain; charset=utf-8
 
file read⏎
 
$ curl -i 'http://localhost:8000/get-file?file=/etc/hosts'
HTTP/1.1 403 Forbidden
Date: Fri, 03 Jan 2025 09:43:52 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>
	...

Waffle also provides features to prevent attacks such as SQL injection, SSRF and more.

Next Steps

For more information about protect your application, refer the guides.