Open superstes opened 1 week ago
Of course - one could use WithErrorCallback
to override it with a custom format - but that might not be doable or be favourable for 'users'.
Basic callback for reference:
func createWAF() coraza.WAF {
waf, err := coraza.NewWAF(
coraza.NewWAFConfig().
WithErrorCallback(logErrorJSON),
)
if err != nil {
log.Fatal(err)
}
return waf
}
type errorLogJSON struct {
File string `json:"file"`
Line int `json:"line"`
ID int `json:"rule_id"`
Revision string `json:"rev"`
Msg string `json:"msg"`
Data string `json:"data"`
SeverityID int `json:"sev_id"`
Severity string `json:"sev"`
Version string `json:"ver"`
Maturity int `json:"mat"`
Accuracy int `json:"acc"`
Client string `json:"client"`
Disruptive bool `json:"disruptive"`
Tags []string `json:"tags"`
Server string `json:"server"`
URI string `json:"uri"`
UniqueID string `json:"unique_id"`
}
func logErrorJSON(mr types.MatchedRule) {
r := mr.Rule()
j, _ := json.Marshal(errorLogJSON{
File: r.File(),
Line: r.Line(),
ID: r.ID(),
Revision: r.Revision(),
Msg: mr.Message(),
Data: mr.Data(),
Severity: r.Severity().String(),
SeverityID: r.Severity().Int(),
Version: r.Version(),
Maturity: r.Maturity(),
Accuracy: r.Accuracy(),
Client: mr.ClientIPAddress(),
Server: mr.ServerIPAddress(),
Disruptive: mr.Disruptive(),
Tags: r.Tags(),
URI: mr.URI(),
UniqueID: mr.TransactionID(),
})
fmt.Println(string(j[:]))
}
Results in:
{"file":"coreruleset/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf","line":1210,"rule_id":941160,"rev":"","msg":"NoScript XSS InjectionChecker: HTML Injection","data":"Matched Data: \u003cscript found within REQUEST_HEADERS:Referer: http://localhost:8090/?a=\u003cscript\u003ealert(1)\u003c/script\u003e","sev_id":2,"sev":"critical","ver":"OWASP_CRS/4.7.0-dev","mat":0,"acc":0,"client":"[::1]","disruptive":false,"tags":["application-multi","language-multi","platform-multi","attack-xss","xss-perf-disable","paranoia-level/1","OWASP_CRS","capec/1000/152/242"],"server":"","uri":"/favicon.ico","unique_id":"YuxjbYnedOyrPYNkyFy"}
BTW: Looks like the ocsf-auditlog does something similar - https://github.com/corazawaf/coraza/blob/main/internal/auditlog/formats_ocsf.go#L84
Summary
I have not seen any option in the documentation to change the error/block log format.
JSON format would make sense for many use-cases. Also the audit-logs seem to already support it.
Basic example
It would be nice to get this as json object:
[client \"::ffff:95.214.55.x\"] Coraza: Warning. Host header is a numeric IP address [file \"/etc/coraza-spoa/coreruleset/rules/@owasp_crs/REQUEST-920-PROTOCOL-ENFORCEMENT.conf\"] [line \"1772\"] [id \"920350\"] [rev \"\"] [msg \"Host header is a numeric IP address\"] [data \"159.69.187.x\"] [severity \"warning\"] [ver \"OWASP_CRS/4.0.0-rc2\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-protocol\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"capec/1000/210/272\"] [tag \"PCI/6.5.10\"] [hostname \"::ffff:159.69.187.x\"] [uri \"/\"] [unique_id \"FMPGEMUVBOHBCEMH\"]
Motivation
JSON is much easier to parse than the stringified format. Log systems like Graylog can parse JSON natively & easily. That is very convenient - especially as such security-logs are very important to process.
From what I've read into the source - this is where the logs are written: https://github.com/corazawaf/coraza/blob/main/internal/corazarules/rule_match.go#L254
Related to: https://github.com/corazawaf/coraza/issues/856, https://github.com/corazawaf/coraza-caddy/issues/20, https://github.com/corazawaf/coraza-spoa/issues/91, https://github.com/corazawaf/coraza/issues/1150
I'm open to contribute.