Skip to content

Commit

Permalink
agent. Fix secrets obfuscation (#515)
Browse files Browse the repository at this point in the history
The flatten/unflatten library has a known bug that does not preserve
JSON arrays. This fix recursively walk the JSON decoded structure and
replaces sensitive fields in the same way.
  • Loading branch information
DavidePrincipi committed Nov 7, 2023
1 parent d12ecae commit a106115
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
60 changes: 46 additions & 14 deletions core/agent/htask.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"syscall"
"time"

"github.com/nqd/flat"
"github.com/NethServer/ns8-core/core/agent/models"
"github.com/NethServer/ns8-core/core/agent/validation"
"github.com/go-redis/redis/v8"
Expand Down Expand Up @@ -402,21 +401,54 @@ func publishStatus(client redis.Cmdable, progressChannel string, actionDescripto
}
}

func obscureTaskInput(payload string) string {
var jsonDyn map[string]interface{}
json.Unmarshal([]byte(payload), &jsonDyn)
flattenedInput, _ := flat.Flatten(jsonDyn, nil)
func obscureTaskInput(jsonStr string) string {
var jsonData map[string]interface{}
if err := json.Unmarshal([]byte(jsonStr), &jsonData); err != nil {
log.Println(SD_ERR+"Error unmarshalling JSON:", err)
return jsonStr
}

recursiveObscureSensitiveKeys(jsonData)

updatedJson, err := json.Marshal(jsonData)
if err != nil {
log.Println(SD_ERR+"Error marshalling JSON:", err)
return jsonStr
}

return string(updatedJson)
}

func isSensitive(target string) bool {
sensitiveList := []string{"password", "secret", "token"}
// search for sensitve data, in sensitive list
for k, _ := range flattenedInput {
for _, s := range sensitiveList {
if strings.HasPrefix(k, "data.") && strings.HasSuffix("." + strings.ToLower(k), strings.ToLower(s)) {
flattenedInput[k] = "XXX"
ltarget := strings.ToLower(target)
for _, sensitive := range sensitiveList {
if strings.HasSuffix(ltarget, sensitive) {
return true
}
}
return false
}

func recursiveObscureSensitiveKeys(data interface{}) {
switch v := data.(type) {
case map[string]interface{}:
// It's an object, so iterate through its key-value pairs
for key, value := range v {
// Recursively update the value
recursiveObscureSensitiveKeys(value)

// Check for sensitive keys
if isSensitive(key) {
v[key] = "XXX" // replace the secret value
}
}

case []interface{}:
// It's an array, so iterate through its elements
for _, item := range v {
// Recursively update the element
recursiveObscureSensitiveKeys(item)
}
}
obscuredTask, _ := flat.Unflatten(flattenedInput, nil)
// convert to JSON string
taskJson, _ := json.Marshal(obscuredTask)
return string(taskJson[:])
}
9 changes: 9 additions & 0 deletions core/agent/test/suite/10__obfuscate_input.robot
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,12 @@ Passwords are obfuscated in Redis context keys
When The command is received set obfuscate-test/context
Then The task context should contain XXX
And The task context should contain PRE-SERVED

Obfuscation does not alter the input structure
Given The task is submitted obfuscate-test {"tags":["t1","t2"],"account_info":{"password":"Nethesis,1234","claims":["c1","c2"],"ratio":1.2},"password_not_replaced":"PRE-SERVED"}
When The command is received set obfuscate-test/context
Then The task context should contain XXX
And The task context should contain PRE-SERVED
And The task context should contain ["t1","t2"]
And The task context should contain ["c1","c2"]
And The task context should contain 1.2

0 comments on commit a106115

Please sign in to comment.