Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return an error when parsing an Include directive using a glob pattern that doesn't match any file #1250

Closed
gantony opened this issue Dec 17, 2024 · 7 comments

Comments

@gantony
Copy link
Contributor

gantony commented Dec 17, 2024

Summary

Coraza gives us a nice (and helpful!) error message when a file we want to include is not found.

For example, Include Ncoraza.conf, where Ncoraza.conf does not exists, we get the following error:

invalid WAF config from file: failed to parse string: failed to readfile: open Ncoraza.conf: no such file or directory

However, when using a glob like in Include coreruleset-default/*.conf, when coreruleset-default does not exist, we get no error whatsoever. The existing logic only returns an error is the glob expression is malformed, as commented in fs.Glob:

// Glob ignores file system errors such as I/O errors reading directories.
// The only possible returned error is [path.ErrBadPattern], reporting that
// the pattern is malformed.

My suggestion is to add an extra check, and create an "no matched files error" when an Include directive with a blob does not match any file.

Basic example

Evaluating Include coreruleset-default/*.conf, where there is no match, would return an error like:

invalid WAF config from file: failed to parse string: empty glob: coreruleset-default/*.conf does no match any file

Currently, the operation succeeds (no file is loaded, Import directive has no effect and no error is provided).

Motivation

Doing this for consistency between importing a file and importing multiple files with a glob pattern. If we add an import directive, the expectation is that it will either import something or report an error.

Discussion

I am happy to implement that change, but want to discuss it first to make sure it's acceptable.
Should it be the default behavior? I think so, but maybe some folks could be afraid of breaking existing configuration. If this is a strong concern, we could make this validation optional with an optional parameter. This wouldn't be my preference, but that would be better that not having anything...

@M4tteoP
Copy link
Member

M4tteoP commented Dec 18, 2024

Hey @gantony, thanks for reporting this!
At first glance, it seems very reasonable and would help avoid the misconception that some rules are up and running when they’re not due to an incorrect path. At the very least, we should verify that the path exists. That said, the idea of expecting at least one rule also looks interesting, and right now I do not see why it could be useful to include a directive with no rules. Let’s wait for others to weigh in :)

@gantony
Copy link
Contributor Author

gantony commented Dec 18, 2024

Thanks for the feedback.

At the very least, we should verify that the path exists.

We could dig a hole for ourselves here too 😅. Maybe the path is valid but we typed coreruleset-default/*.comf instead of coreruleset-default/*.conf. Hence the suggestion to report an error when we include a directive with no rules.

A bit like a compile error for an unused variable in go 😄.

@jcchavezs
Copy link
Member

What middleware and what version are you using?

@gantony
Copy link
Contributor Author

gantony commented Dec 20, 2024

I am using the latest github.com/corazawaf/coraza/v3.

I guess an example would help describe the issue. This program:

package main

import (
	"fmt"
	"testing/fstest"

	"github.com/corazawaf/coraza/v3"
)

func main() {
	m := fstest.MapFS{
		"crs/sample.conf":     &fstest.MapFile{Data: []byte("SecRuleEngine DetectionOnly\n")},
		"valid.conf":          &fstest.MapFile{Data: []byte("Include crs/sample.conf\n")},
		"valid-glob.conf":     &fstest.MapFile{Data: []byte("Include crs/*.conf\n")},
		"invalid-error.conf":  &fstest.MapFile{Data: []byte("Include crs/demo.conf\n")},
		"invalid-silent.conf": &fstest.MapFile{Data: []byte("Include rules/*.conf\n")},
	}

	setupCoraza := func(config string) {
		_, err := coraza.NewWAF(coraza.NewWAFConfig().
			WithRootFS(m).
			WithDirectives(config))
		if err != nil {
			fmt.Println(err)
		}
	}

	// This works
	setupCoraza(`Include valid.conf`)

	// This works (glob)
	setupCoraza(`Include valid-glob.conf`)

	// This doesn't work, but we get the expected error
	setupCoraza(`Include invalid-error.conf`)

	// This doesn't work (no file imported), but it does so silently
	// Would like to add an error when an Include with a glob has no effect (import no files)
	setupCoraza(`Include invalid-silent.conf`)
}

provides the following output:

invalid WAF config from string: failed to parse string: failed to readfile: open crs/demo.conf: file does not exist

and I would propose to update Coraza to provide the following output:

invalid WAF config from string: failed to parse string: failed to readfile: open crs/demo.conf: file does not exist
invalid WAF config from string: failed to parse string: empty glob: rules/*.conf does not match any file

Of course, I'm open to suggestion for the exact wording around empty glob: rules/*.conf does not match any file. And also making that check opt-in only, although I would prefer it to be the default.

@gantony
Copy link
Contributor Author

gantony commented Dec 20, 2024

Enhancements

Do you intend to add a new feature or change an existing one?

  • Suggest your change in the Discussion and start writing code.
  • Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.

Sorry, looks like I should have opened a discussion instead of opening an issue 😓.

The fix (if desirable) is very small so will open a PR for consideration.

@superstes
Copy link

superstes commented Dec 28, 2024

As I ran into a similar issue:

Example: Include /etc/coraza-spoa/crs/v4.7.0/@owasp_crs/*.conf

If the coraza service-user has no read-permissions for the directory containing the config-files (@owasp_crs in this case) there is no error that would indicate a problem. This makes troubleshooting unnecessarily complicated.

Versions: coraza v3.2.2, coraza-spoa main

@gantony
Copy link
Contributor Author

gantony commented Dec 30, 2024

PR is merged, so I believe this issue can be closed.

@gantony gantony closed this as completed Dec 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants