Skip to content

Commit f547dc1

Browse files
fix: ignore byte array fields and add ddwaf:ignore struct tag (#68)
Co-authored-by: Romain Marcadier <[email protected]>
1 parent 3ac659c commit f547dc1

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed

_tools/libddwaf-updater/update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func main() {
8989
written += wrote
9090
}
9191

92-
fmt.Println("All done! Don't forget to check in changes to include/ and internal/lib/, check the libddwaf upgrade guide to update bindings!")
92+
fmt.Println("All done! Don't forget to check in changes to internal/lib/ and internal/log/ddhaf.h, check the libddwaf upgrade guide to update bindings!")
9393
}
9494

9595
// createEmbedSource creates the embed source file for the given target.

context.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func (d RunAddressData) isEmpty() bool {
7070
// matches as a JSON string (usually opaquely used) along with the corresponding actions in any. In case of an error,
7171
// matches and actions can still be returned, for instance in the case of a timeout error. Errors can be tested against
7272
// the RunError type.
73+
// Struct fields having the tag `ddwaf:"ignore"` will not be encoded and sent to the WAF
7374
func (context *Context) Run(addressData RunAddressData, timeout time.Duration) (res Result, err error) {
7475
if addressData.isEmpty() {
7576
return

encoder.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ const (
4040
ObjectTooDeep
4141
)
4242

43+
const (
44+
AppsecFieldTag = "ddwaf"
45+
AppsecFieldTagValueIgnore = "ignore"
46+
)
47+
4348
type native interface {
4449
int64 | uint64 | uintptr
4550
}
@@ -159,8 +164,11 @@ func (encoder *encoder) encode(value reflect.Value, obj *wafObject, depth int) e
159164
// Strings
160165
case kind == reflect.String: // string type
161166
encoder.encodeString(value.String(), obj)
162-
case value.Type() == reflect.TypeOf([]byte(nil)): // byte array -> string
163-
encoder.encodeString(string(value.Bytes()), obj)
167+
168+
case value.Type() == reflect.TypeOf([]byte(nil)):
169+
// Byte Arrays are skipped voluntarily because they are often used
170+
// to do partial parsing which leads to false positives
171+
return nil
164172

165173
// Containers (internal nodes of the tree)
166174

@@ -240,7 +248,9 @@ func (encoder *encoder) encodeStruct(value reflect.Value, obj *wafObject, depth
240248

241249
fieldType := typ.Field(i)
242250
fieldName, usable := getFieldNameFromType(fieldType)
243-
if !usable {
251+
if tag, ok := fieldType.Tag.Lookup(AppsecFieldTag); !usable || ok && tag == AppsecFieldTagValueIgnore {
252+
// Either the struct field is ignored by json marshaling so can we,
253+
// or the field was explicitly set with `ddwaf:ignore`
244254
continue
245255
}
246256

encoder_decoder_test.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ func TestEncodeDecode(t *testing.T) {
128128
Input: "hello, waf",
129129
},
130130
{
131-
Name: "byte-slice",
132-
Input: []byte("hello, waf"),
133-
Output: "hello, waf",
131+
Name: "byte-slice",
132+
Input: []byte("hello, waf"),
133+
DecodeError: errUnsupportedValue,
134134
},
135135
{
136136
Name: "nil-byte-slice",
@@ -253,6 +253,23 @@ func TestEncodeDecode(t *testing.T) {
253253
"A": "A",
254254
},
255255
},
256+
{
257+
Name: "struct-with-ignored-values",
258+
Input: struct {
259+
Public string `ddwaf:"ignore"`
260+
private string
261+
a string
262+
A string
263+
}{
264+
Public: "Public",
265+
private: "private",
266+
a: "a",
267+
A: "A",
268+
},
269+
Output: map[string]any{
270+
"A": "A",
271+
},
272+
},
256273
{
257274
Name: "struct-with-unsupported-values",
258275
Input: struct {
@@ -268,6 +285,19 @@ func TestEncodeDecode(t *testing.T) {
268285
},
269286
DecodeError: errUnsupportedValue,
270287
},
288+
{
289+
Name: "struct-with-unsupported-ignored-values",
290+
Input: struct {
291+
Public string
292+
A chan any `ddwaf:"ignore"`
293+
}{
294+
Public: "Public",
295+
A: make(chan any),
296+
},
297+
Output: map[string]any{
298+
"Public": "Public",
299+
},
300+
},
271301
} {
272302
t.Run(tc.Name, func(t *testing.T) {
273303
if tc.Output == nil {

0 commit comments

Comments
 (0)