/
waf.go
194 lines (171 loc) · 6.09 KB
/
waf.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
// Copyright 2022 Juan Pablo Tosso and the OWASP Coraza contributors
// SPDX-License-Identifier: Apache-2.0
package types
import (
"errors"
"fmt"
"strings"
)
// AuditEngineStatus represents the functionality
// of the audit engine.
type AuditEngineStatus int
const (
// AuditEngineOn will audit each auditable event
AuditEngineOn AuditEngineStatus = iota
// AuditEngineOff will not audit any event
AuditEngineOff AuditEngineStatus = iota
// AuditEngineRelevantOnly will audit only relevant events
AuditEngineRelevantOnly AuditEngineStatus = iota
)
// ParseAuditEngineStatus parses the audit engine status
func ParseAuditEngineStatus(as string) (AuditEngineStatus, error) {
switch strings.ToLower(as) {
case "on":
return AuditEngineOn, nil
case "off":
return AuditEngineOff, nil
case "relevantonly":
return AuditEngineRelevantOnly, nil
}
return -1, fmt.Errorf("invalid audit engine status: %s", as)
}
// RuleEngineStatus represents the functionality
// of the rule engine.
type RuleEngineStatus int
const (
// RuleEngineOn will process each rule and may generate
// disruptive actions
RuleEngineOn RuleEngineStatus = iota
// RuleEngineDetectionOnly will process each rule but won't
// generate disruptive actions
RuleEngineDetectionOnly RuleEngineStatus = iota
// RuleEngineOff will not process any rule
RuleEngineOff RuleEngineStatus = iota
)
// ParseRuleEngineStatus parses the rule engine status
func ParseRuleEngineStatus(re string) (RuleEngineStatus, error) {
switch strings.ToLower(re) {
case "on":
return RuleEngineOn, nil
case "detectiononly":
return RuleEngineDetectionOnly, nil
case "off":
return RuleEngineOff, nil
}
return -1, fmt.Errorf("invalid rule engine status: %q", re)
}
// String returns the string representation of the
// rule engine status
func (re RuleEngineStatus) String() string {
switch re {
case RuleEngineOn:
return "On"
case RuleEngineDetectionOnly:
return "DetectionOnly"
case RuleEngineOff:
return "Off"
}
return "unknown"
}
// BodyLimitAction represents the action to take when
// the body size exceeds the configured limit.
type BodyLimitAction int
const (
// BodyLimitActionProcessPartial will process the body
// up to the limit and then ignores the remaining body bytes
BodyLimitActionProcessPartial BodyLimitAction = 0
// BodyLimitActionReject will reject the connection in case
// the body size exceeds the configured limit
BodyLimitActionReject BodyLimitAction = 1
)
type AuditLogPart byte
// AuditLogParts represents the parts of the audit log
// A: Audit log header (mandatory).
// B: Request headers.
// C: Request body
// D: Reserved for intermediary response headers; not implemented yet.
// E: Intermediary response body (not implemented yet).
// F: Final response headers
// G: Reserved for the actual response body; not implemented yet.
// H: Audit log trailer.
// I: This part is a replacement for part C.
// J: This part contains information about the files uploaded using multipart/form-data encoding.
// K: This part contains a full list of every rule that matched (one per line)
// Z: Final boundary, signifies the end of the entry (mandatory).
type AuditLogParts []AuditLogPart
var validOpts = map[AuditLogPart]struct{}{
AuditLogPartRequestHeaders: {},
AuditLogPartRequestBody: {},
AuditLogPartIntermediaryResponseHeaders: {},
AuditLogPartIntermediaryResponseBody: {},
AuditLogPartResponseHeaders: {},
AuditLogPartResponseBody: {},
AuditLogPartAuditLogTrailer: {},
AuditLogPartRequestBodyAlternative: {},
AuditLogPartUploadedFiles: {},
AuditLogPartRulesMatched: {},
}
// ParseAuditLogParts parses the audit log parts
func ParseAuditLogParts(opts string) (AuditLogParts, error) {
if !strings.HasPrefix(opts, "A") {
return nil, errors.New("audit log parts is required to start with A")
}
if !strings.HasSuffix(opts, "Z") {
return nil, errors.New("audit log parts is required to end with Z")
}
parts := opts[1 : len(opts)-1]
for _, p := range parts {
if _, ok := validOpts[AuditLogPart(p)]; !ok {
return AuditLogParts(""), fmt.Errorf("invalid audit log parts %q", opts)
}
}
return AuditLogParts(parts), nil
}
const (
// AuditLogPartRequestHeaders is the request headers part
AuditLogPartRequestHeaders AuditLogPart = 'B'
// AuditLogPartRequestBody is the request body part
AuditLogPartRequestBody AuditLogPart = 'C'
// AuditLogPartIntermediaryResponseHeaders is the intermediary response headers part
AuditLogPartIntermediaryResponseHeaders AuditLogPart = 'D'
// AuditLogPartIntermediaryResponseBody is the intermediary response body part
AuditLogPartIntermediaryResponseBody AuditLogPart = 'E'
// AuditLogPartResponseHeaders is the final response headers part
AuditLogPartResponseHeaders AuditLogPart = 'F'
// AuditLogPartResponseBody is the final response body part
AuditLogPartResponseBody AuditLogPart = 'G'
// AuditLogPartAuditLogTrailer is the audit log trailer part
AuditLogPartAuditLogTrailer AuditLogPart = 'H'
// AuditLogPartRequestBodyAlternative is the request body replaced part
AuditLogPartRequestBodyAlternative AuditLogPart = 'I'
// AuditLogPartUploadedFiles is the uploaded files part
AuditLogPartUploadedFiles AuditLogPart = 'J'
// AuditLogPartRulesMatched is the matched rules part
AuditLogPartRulesMatched AuditLogPart = 'K'
)
// Interruption is used to notify the Coraza implementation
// that the transaction must be disrupted, for example:
//
// if it := tx.Interruption; it != nil {
// return show403()
// }
type Interruption struct {
// Rule that caused the interruption
RuleID int
// drop, deny, redirect
Action string
// Force this status code
Status int
// Parameters used by proxy and redirect
Data string
}
// BodyBufferOptions is used to feed a coraza.BodyBuffer with parameters
type BodyBufferOptions struct {
// TmpPath is the path to store temporary files
TmpPath string
// MemoryLimit is the maximum amount of memory to be stored in memory
// Once the limit is reached, the file will be stored on disk
MemoryLimit int64
// Limit is the overall maximum amount of memory to be buffered
Limit int64
}