forked from corazawaf/coraza
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
278 lines (224 loc) · 7.39 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors
// SPDX-License-Identifier: Apache-2.0
package coraza
import (
"io/fs"
"github.com/corazawaf/coraza/v3/internal/corazawaf"
"github.com/corazawaf/coraza/v3/loggers"
"github.com/corazawaf/coraza/v3/types"
)
// WAFConfig controls the behavior of the WAF.
//
// Note: WAFConfig is immutable. Each WithXXX function returns a new instance including the corresponding change.
type WAFConfig interface {
// WithRules adds rules to the WAF.
WithRules(rules ...*corazawaf.Rule) WAFConfig
// WithDirectives parses the directives from the given string and adds them to the WAF.
WithDirectives(directives string) WAFConfig
// WithDirectivesFromFile parses the directives from the given file and adds them to the WAF.
WithDirectivesFromFile(path string) WAFConfig
// WithAuditLog configures audit logging.
WithAuditLog(config AuditLogConfig) WAFConfig
// WithContentInjection enables content injection.
WithContentInjection() WAFConfig
// WithRequestBodyAccess configures access to the request body.
WithRequestBodyAccess(config RequestBodyConfig) WAFConfig
// WithResponseBodyAccess configures access to the response body.
WithResponseBodyAccess(config ResponseBodyConfig) WAFConfig
// WithDebugLogger configures a debug logger.
WithDebugLogger(logger loggers.DebugLogger) WAFConfig
// WithErrorCallback configures an error callback that can be used
// to log errors triggered by the WAF.
// It contains the severity so the cb can decide to skip it or not
WithErrorCallback(logger func(rule types.MatchedRule)) WAFConfig
// WithRootFS configures the root file system.
WithRootFS(fs fs.FS) WAFConfig
}
// NewWAFConfig creates a new WAFConfig with the default settings.
func NewWAFConfig() WAFConfig {
return &wafConfig{}
}
// RequestBodyConfig controls access to the request body.
type RequestBodyConfig interface {
// WithLimit sets the maximum number of bytes that can be read from the request body.
// A request body going beyond WithInMemoryLimit will result in being buffered to disk.
WithLimit(limit int) RequestBodyConfig
// WithInMemoryLimit sets the maximum number of bytes that can be read from the request body and buffered in memory.
WithInMemoryLimit(limit int) RequestBodyConfig
}
// NewRequestBodyConfig returns a new RequestBodyConfig with the default settings.
func NewRequestBodyConfig() RequestBodyConfig {
return &requestBodyConfig{}
}
// ResponseBodyConfig controls access to the response body.
type ResponseBodyConfig interface {
// WithLimit sets the maximum number of bytes that can be read from the response body and buffered in memory.
// Keep in mind your machine architecture and memory/swap limits while setting it.
// E.g. 32-bit machine tested limit: 1073741824 (1GiB)
WithLimit(limit int) ResponseBodyConfig
// WithInMemoryLimit is not implemented for ResponseBody. The body will be just buffered in memory,
// therefore WithLimit already sets the in memory threshold
// WithMimeTypes sets the mime types of responses that will be processed.
WithMimeTypes(mimeTypes []string) ResponseBodyConfig
}
// NewResponseBodyConfig returns a new ResponseBodyConfig with the default settings.
func NewResponseBodyConfig() ResponseBodyConfig {
return &responseBodyConfig{}
}
// AuditLogConfig controls audit logging.
type AuditLogConfig interface {
// LogRelevantOnly enables audit logging only for relevant events.
LogRelevantOnly() AuditLogConfig
// WithParts configures the parts of the request/response to be logged.
WithParts(parts types.AuditLogParts) AuditLogConfig
// WithLogger configures the loggers.LogWriter to write logs to.
WithLogger(logger loggers.LogWriter) AuditLogConfig
}
// NewAuditLogConfig returns a new AuditLogConfig with the default settings.
func NewAuditLogConfig() AuditLogConfig {
return &auditLogConfig{}
}
type wafRule struct {
rule *corazawaf.Rule
str string
file string
}
type wafConfig struct {
rules []wafRule
auditLog *auditLogConfig
contentInjection bool
requestBody *requestBodyConfig
responseBody *responseBodyConfig
debugLogger loggers.DebugLogger
errorCallback func(rule types.MatchedRule)
fsRoot fs.FS
}
func (c *wafConfig) WithRules(rules ...*corazawaf.Rule) WAFConfig {
if len(rules) == 0 {
return c
}
ret := c.clone()
for _, r := range rules {
ret.rules = append(ret.rules, wafRule{rule: r})
}
return ret
}
func (c *wafConfig) WithDirectivesFromFile(path string) WAFConfig {
ret := c.clone()
ret.rules = append(ret.rules, wafRule{file: path})
return ret
}
func (c *wafConfig) WithDirectives(directives string) WAFConfig {
ret := c.clone()
ret.rules = append(ret.rules, wafRule{str: directives})
return ret
}
func (c *wafConfig) WithAuditLog(config AuditLogConfig) WAFConfig {
ret := c.clone()
ret.auditLog = config.(*auditLogConfig)
return ret
}
func (c *wafConfig) WithContentInjection() WAFConfig {
ret := c.clone()
ret.contentInjection = true
return ret
}
func (c *wafConfig) WithRequestBodyAccess(config RequestBodyConfig) WAFConfig {
ret := c.clone()
ret.requestBody = config.(*requestBodyConfig)
return ret
}
func (c *wafConfig) WithResponseBodyAccess(config ResponseBodyConfig) WAFConfig {
ret := c.clone()
ret.responseBody = config.(*responseBodyConfig)
return ret
}
func (c *wafConfig) WithDebugLogger(logger loggers.DebugLogger) WAFConfig {
ret := c.clone()
ret.debugLogger = logger
return ret
}
func (c *wafConfig) WithErrorCallback(logger func(rule types.MatchedRule)) WAFConfig {
ret := c.clone()
ret.errorCallback = logger
return ret
}
func (c *wafConfig) WithRootFS(fs fs.FS) WAFConfig {
ret := c.clone()
ret.fsRoot = fs
return ret
}
func (c *wafConfig) clone() *wafConfig {
ret := *c // copy
rules := make([]wafRule, len(c.rules))
copy(rules, c.rules)
ret.rules = rules
return &ret
}
type requestBodyConfig struct {
limit int
inMemoryLimit int
}
var _ RequestBodyConfig = (*requestBodyConfig)(nil)
func (c *requestBodyConfig) WithLimit(limit int) RequestBodyConfig {
ret := c.clone()
ret.limit = limit
return ret
}
func (c *requestBodyConfig) WithInMemoryLimit(limit int) RequestBodyConfig {
ret := c.clone()
ret.inMemoryLimit = limit
return ret
}
func (c *requestBodyConfig) clone() *requestBodyConfig {
ret := *c // copy
return &ret
}
type responseBodyConfig struct {
limit int
inMemoryLimit int
mimeTypes []string
}
func (c *responseBodyConfig) WithLimit(limit int) ResponseBodyConfig {
ret := c.clone()
ret.limit = limit
return ret
}
func (c *responseBodyConfig) WithInMemoryLimit(limit int) ResponseBodyConfig {
ret := c.clone()
ret.inMemoryLimit = limit
return ret
}
func (c *responseBodyConfig) WithMimeTypes(mimeTypes []string) ResponseBodyConfig {
ret := c.clone()
ret.mimeTypes = mimeTypes
return ret
}
func (c *responseBodyConfig) clone() *responseBodyConfig {
ret := *c // copy
return &ret
}
type auditLogConfig struct {
relevantOnly bool
parts types.AuditLogParts
logger loggers.LogWriter
}
func (c *auditLogConfig) LogRelevantOnly() AuditLogConfig {
ret := c.clone()
c.relevantOnly = true
return ret
}
func (c *auditLogConfig) WithParts(parts types.AuditLogParts) AuditLogConfig {
ret := c.clone()
ret.parts = parts
return ret
}
func (c *auditLogConfig) WithLogger(logger loggers.LogWriter) AuditLogConfig {
ret := c.clone()
ret.logger = logger
return ret
}
func (c *auditLogConfig) clone() *auditLogConfig {
ret := *c // copy
return &ret
}