Skip to content

Commit 7bf87bd

Browse files
committed
docs: update
Signed-off-by: Kohei Morita <moritakouhei@graffer.jp>
1 parent a2bed78 commit 7bf87bd

File tree

8 files changed

+395
-85
lines changed

8 files changed

+395
-85
lines changed

README.md

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,117 @@
11
# waffle-go
22

3-
Waffle is a library that provides in-app WAF (Web Application Firewall) and RASP (Runtime Application Self Protection) capabilities for your Go web applications.
3+
Waffle is a library for integrating a Web Application Firewall (WAF) into Go applications.
44

5-
## Features:
5+
By embedding the WAF directly within the application rather than at the network boundary, you can achieve more accurate and flexible detection and defense against attacks.
66

7-
- Adapts to your application stack without configuration
8-
- Protects against common attacks like injection, XSS, and account takeover
9-
- Context-aware precise detection
7+
## Features
8+
9+
- Integration with minimal code changes
10+
- Protection against common web attacks including XSS, SQL injection, and SSRF
11+
- Protection against business logic vulnerabilities like Account Takeover
12+
- Support for popular Go web frameworks and libraries
13+
14+
## Use Cases
15+
16+
- Protecting web applications and APIs from common web attacks
17+
- Alternative to traditional network-based WAFs for application-level protection
18+
- Enhanced security for applications using database access and file operations
1019

1120
## Getting Started
1221

13-
You can find a getting started guide on [waffle website](https://sitebatch.github.io/waffle-website/).
22+
First, set up the Waffle library.
23+
24+
```bash
25+
go get github.com/sitebatch/waffle-go
26+
```
27+
28+
```go
29+
package main
30+
31+
import (
32+
"net/http"
33+
"github.com/sitebatch/waffle-go"
34+
)
35+
36+
func main() {
37+
// Start Waffle
38+
if err := waffle.Start(); err != nil {
39+
// handle error
40+
}
41+
}
42+
```
43+
44+
Finally, depending on which libraries your application uses, install the Waffle contrib package and apply the middleware or wrapper function.
45+
The following libraries are supported:
46+
47+
| Library | Contrib Package |
48+
| :----------- | :------------------------------------------------------------- |
49+
| Gin | [contrib/gin-gonic/gin](contrib/gin-gonic/gin/README.md) |
50+
| Echo | [contrib/labstack/echo](contrib/labstack/echo/README.md) |
51+
| net/http | [contrib/net/http](contrib/net/http/README.md) |
52+
| gqlgen | [contrib/99designs/gqlgen](contrib/99designs/gqlgen/README.md) |
53+
| database/sql | [contrib/database/sql](contrib/database/sql/README.md) |
54+
| os | [contrib/os](contrib/os/README.md) |
55+
56+
## Configuration
57+
58+
### Custom Rules
59+
60+
You can provide custom WAF rules:
61+
62+
```go
63+
waffle.Start(waffle.WithRule(customRuleJSON))
64+
```
65+
66+
### Error Handling
67+
68+
Set a custom handler to handle Waffle's internal errors.
69+
70+
```go
71+
waffle.SetErrorHandler(customErrorHandler)
72+
```
73+
74+
### Event Export
75+
76+
To retrieve events detected by Waffle, configure an exporter using `SetExporter()`.
77+
78+
Waffle provides built-in exporters like `StdoutExporter` for logging detection events and `ChanExporter` for writing to a specified channel, but you can also implement and configure your own custom exporter that meets the required interface.
79+
80+
```go
81+
waffle.SetExporter(customExporter)
82+
```
83+
84+
### Logging
85+
86+
Set a custom logger to capture Waffle's internal logs.
87+
88+
```go
89+
waffle.SetLogger(logger)
90+
```
91+
92+
## Handling blocking event
93+
94+
When Waffle detects an attack and blocks the request, it returns a `waf.SecurityBlockingError` error type. If you catch this error, you should handle it appropriately—for example, by returning a proper error response to the client.
95+
This error type can be checked using the `waf.IsSecurityBlockingError` function.
96+
97+
When Waffle's HTTP middleware blocks a request, it automatically returns an HTTP 403 Forbidden response, but it is your responsibility to handle the blocked function call.
98+
For instance, if a function called during processing at an endpoint attempts to execute a potentially vulnerable SQL query (such as SQL Injection), that function call will be blocked and terminated by returning an error of type `waf.SecurityBlockingError`.
99+
You can determine whether the block was initiated by the WAF using either `errors.As` or `waf.IsSecurityBlockingError`.
100+
101+
```go
102+
// Example of handling a blocked SQL query
103+
104+
// Will be blocked due to SQL Injection attempt
105+
userInput := "1 OR 1 = 1"
106+
_, err := db.QueryContext(ctx, fmt.Sprintf("SELECT * FROM users WHERE id = '%s'", userInput))
107+
if err != nil {
108+
if waf.IsSecurityBlockingError(err) {
109+
// Handle blocked request
110+
log.Printf("Blocked request: %v", err)
111+
return
112+
}
113+
114+
// Handle other errors
115+
log.Fatal(err)
116+
}
117+
```

contrib/99designs/gqlgen/README.md

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,59 @@
22

33
This package provides a Waffle middleware for [gqlgen](https://gqlgen.com/).
44

5-
If you are using gqlgen, you can apply protection by Waffle using the `WafMiddleware` provided by this package.
5+
If you are using gqlgen for GraphQL server, you can apply WAF protection using the `WafMiddleware` provided by this package.
6+
7+
## Installation
8+
9+
```bash
10+
go get github.com/sitebatch/waffle-go/contrib/99designs/gqlgen
11+
```
612

713
## Usage
814

915
```go
16+
package main
17+
1018
import (
19+
"net/http"
20+
"github.com/99designs/gqlgen/graphql/handler"
21+
22+
"github.com/sitebatch/waffle-go"
1123
"github.com/sitebatch/waffle-go/contrib/99designs/gqlgen"
1224
waffleHttp "github.com/sitebatch/waffle-go/contrib/net/http"
1325
)
1426

15-
mux := http.NewServeMux()
27+
func main() {
28+
mux := http.NewServeMux()
1629

17-
gqlHandler := func() http.HandlerFunc {
18-
srv := handler.New(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
19-
srv.AddTransport(transport.Options{})
20-
srv.AddTransport(transport.GET{})
21-
srv.AddTransport(transport.POST{})
30+
gqlHandler := func() http.HandlerFunc {
31+
srv := handler.New(graph.NewExecutableSchema(graph.Config{
32+
Resolvers: &graph.Resolver{},
33+
}))
2234

23-
srv.SetQueryCache(lru.New[*ast.QueryDocument](1000))
35+
// Apply Waffle WAF middleware for GraphQL
36+
srv.Use(gqlgen.WafMiddleware{})
2437

25-
// Apply WAF middleware for gqlgen
26-
srv.Use(gqlgen.WafMiddleware{})
38+
return func(w http.ResponseWriter, r *http.Request) {
39+
srv.ServeHTTP(w, r)
40+
}
41+
}
2742

28-
srv.Use(extension.Introspection{})
29-
srv.Use(extension.AutomaticPersistedQuery{
30-
Cache: lru.New[string](100),
31-
})
43+
mux.Handle("/query", gqlHandler())
3244

33-
return func(w http.ResponseWriter, r *http.Request) {
34-
srv.ServeHTTP(w, r)
45+
// Apply WAF middleware for the HTTP server
46+
handler := waffleHttp.WafMiddleware(mux)
47+
48+
// Start Waffle
49+
if err := waffle.Start(); err != nil {
50+
panic(err)
3551
}
36-
}
3752

38-
mux.Handle("/query", gqlHandler())
39-
// Apply WAF middleware for the HTTP Server
40-
handler := waffleHttp.WafMiddleware(mux)
53+
srv := &http.Server{
54+
Addr: ":8080",
55+
Handler: handler,
56+
}
57+
58+
srv.ListenAndServe()
59+
}
4160
```

contrib/database/sql/README.md

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,67 @@
11
# database/sql
22

3-
This package provides a wrapper for [`database/sql`](https://pkg.go.dev/database/sql) protected by Waffle. By replacing it with a drop-in, you can prevent SQL injection if you are using `database/sql`.
3+
This package provides a wrapper for [`database/sql`](https://pkg.go.dev/database/sql) protected by Waffle. By using this drop-in replacement, you can prevent SQL injection attacks when using `database/sql`.
44

5-
# Usage
5+
## Installation
66

7-
When executing a statement, use the Waffle database driver instead of `database/sql`. At this time, you need to pass the Waffle's operation `context`.
7+
```bash
8+
go get github.com/sitebatch/waffle-go/contrib/database/sql
9+
```
10+
11+
## Usage
12+
13+
Replace your standard `database/sql` imports with the this package.
814

915
```go
16+
package main
17+
1018
import (
11-
waffleSQL "github.com/sitebatch/waffle-go/contrib/database/sql"
19+
"context"
20+
"fmt"
21+
"log"
22+
23+
"github.com/sitebatch/waffle-go"
24+
waffleSQL "github.com/sitebatch/waffle-go/contrib/database/sql"
25+
"github.com/sitebatch/waffle-go/waf"
1226

1327
_ "github.com/mattn/go-sqlite3" // or any other database driver
1428
)
1529

16-
db, err := waffleSQL.Open("<driver>", "<dataSourceName>")
17-
_, err := database.QueryContext(ctx, "<query>")
18-
```
30+
func main() {
31+
// Start Waffle
32+
if err := waffle.Start(); err != nil {
33+
log.Fatal(err)
34+
}
1935

20-
If you are using a prepared statement, you can assume that SQL injection will not occur, and Waffle does not check for SQL injection.
36+
// Open database connection using Waffle wrapper
37+
db, err := waffleSQL.Open("sqlite3", "file::memory:?cache=shared")
38+
if err != nil {
39+
log.Fatal(err)
40+
}
2141

22-
```go
23-
import (
24-
waffleSQL "github.com/sitebatch/waffle-go/contrib/database/sql"
42+
// Create a sample table
43+
if _, err := db.Exec("CREATE TABLE users(id int, email text, password text);"); err != nil {
44+
panic(err)
45+
}
46+
defer db.Close()
2547

26-
_ "github.com/mattn/go-sqlite3" // or any other database driver
27-
)
48+
ctx := context.Background()
2849

29-
db, err := waffleSQL.Open("<driver>", "<dataSourceName>")
30-
// Waffle does not check for SQL injection in prepared statements.
31-
_, err := database.PrepareContext(ctx, "<query>")
32-
```
50+
// Execute queries - Waffle will prevent SQL injection
51+
userID := "1' OR '1'='1"
52+
query := fmt.Sprintf("SELECT * FROM users WHERE id = '%s'", userID)
3353

34-
# Example
54+
rows, err := db.QueryContext(ctx, query)
55+
if err != nil {
56+
if waf.IsSecurityBlockingError(err) {
57+
// Handle blocked query
58+
log.Printf("Blocked SQL injection attempt: %v", err)
59+
return
60+
}
3561

36-
See [example/sql](../../../example/sql/).
62+
log.Fatal(err)
63+
return
64+
}
65+
defer rows.Close()
66+
}
67+
```

contrib/gin-gonic/gin/README.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
This package provides a Waffle middleware for [gin](https://gin-gonic.com/).
44

5-
If you are using gin, you can apply protection by Waffle using the `WafMiddleware` provided by this package.
5+
If you are using Gin web framework, you can apply WAF protection using the `WafMiddleware` provided by this package.
6+
7+
## Installation
8+
9+
```bash
10+
go get github.com/sitebatch/waffle-go/contrib/gin-gonic/gin
11+
```
612

713
## Usage
814

@@ -15,10 +21,17 @@ import (
1521
ginWaf "github.com/sitebatch/waffle-go/contrib/gin-gonic/gin"
1622
)
1723

18-
r := gin.Default()
19-
r.Use(ginWaf.WafMiddleware())
24+
func main() {
25+
r := gin.Default()
26+
27+
// Apply Waffle WAF middleware
28+
r.Use(ginWaf.WafMiddleware())
2029

21-
waffle.Start()
30+
// Start Waffle
31+
if err := waffle.Start(); err != nil {
32+
panic(err)
33+
}
2234

23-
r.Run(":8000")
35+
r.Run(":8000")
36+
}
2437
```

0 commit comments

Comments
 (0)