Skip to content

Commit 376474a

Browse files
authored
appsec: various improvements (#763)
1 parent 6fd655f commit 376474a

4 files changed

Lines changed: 109 additions & 17 deletions

File tree

crowdsec-docs/docs/appsec/configuration.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,88 @@ inband_rules:
5858
#...
5959
```
6060

61+
## Disabling rules at runtime
62+
63+
Even though we try to provide rules without false positives, sometimes a virtual patching rule can block legitimate requests on a website.
64+
65+
You can disable rules at runtime, either globally (for all requests) or based on specific conditions (source IP, URI, ...).
66+
67+
You can can disable rules by:
68+
- Name with `RemoveInBandRuleByName`: Intended for disabling rules provided by crowdsec (the name is the name of the appsec-rule as seen in `cscli appsec-rules list`).
69+
- ID with `RemoveInBandRuleByID`: Intended for disabling seclang rules
70+
- Tag with `RemoveInBandRuleByTag`: Intended for disabling seclang rules
71+
72+
The same functions exist for out-of-band rules, prefixed with `RemovedOutBandRuleBy...`
73+
74+
To disable a rule, we'll first create a new `appsec-config` to avoid tainting the configuration from the hub (if you are already using a custom configuration, you can update this one instead).
75+
76+
```yaml title="/etc/crowdsec/appsec-configs/my_config.yaml"
77+
name: custom/my_config
78+
on_load:
79+
- apply:
80+
- RemoveInBandRuleByName("crowdsecurity/vpatch-env-access")
81+
pre_eval:
82+
- filter: IsInBand == true && req.URL.Path startsWith "/bar/"
83+
apply:
84+
- RemoveInBandRuleByName("crowdsecurity/generic-wordpress-uploads-php")
85+
```
86+
87+
We are using the [hooks](/docs/appsec/hooks.md) provided by the appsec to modify the configuration in 2 places:
88+
- `on_load`: Expressions here will be applied when crowdsec loads the configuration, effectively disabling the rule `crowdsecurity/vpatch-env-access` globally.
89+
- `pre_eval`: Expressions here will be applied only if the provided filter matches. In this example, we are disabling the rule `crowdsecurity/generic-wordpress-uploads-php` only if the request URI starts with `/blog/` and if we are currently processing in-band rules.
90+
91+
You can also disable native (seclang) rules by providing their ID with the `RemoveInBandRuleByID` helper. See the [hooks](appsec/hooks.md) documentation for a list of available helpers.
92+
93+
Also note that we are not loading any rules in our custom config: the rules are loaded by the `crowdsecurity/appsec-default` config, and we are just modifying the runtime behavior with this config.
94+
95+
Finally, we need to tell crowdsec to load our new config:
96+
97+
```yaml title="/etc/crowdsec/acquis.d/appsec.yaml"
98+
appsec_configs:
99+
- crowdsecurity/appsec-default
100+
- custom/my_config
101+
labels:
102+
type: appsec
103+
listen_addr: 127.0.0.1:7422
104+
source: appsec
105+
```
106+
107+
## Allowlisting
108+
109+
### Fully allow a specific IP or range
110+
111+
If you want to ignore all rule matches for a specific IP or range, you can use a [centralized allowlist](local_api/allowlists.md).
112+
113+
Rules will be processed as usual, but the request will not be blocked even if a rule matches.
114+
115+
### Disable specific rules for a specific IP/range
116+
117+
If you want to disable rule(s) for a specific IP (or range), you will need to use the `pre_eval` hook (refer to the section above for more details):
118+
119+
```yaml title="/etc/crowdsec/appsec-configs/my_config.yaml"
120+
name: custom/my_config
121+
pre_eval:
122+
- filter: req.RemoteAddr == "1.2.3.4"
123+
apply:
124+
- RemoveInBandRuleByName("crowdsecurity/generic-wordpress-uploads-php")
125+
```
126+
127+
### Disable appsec for a specific FQDN
128+
129+
If your reverse-proxy forwards all requests to crowdsec, regardless of the FQDN, you can disable the appsec for specific domain with a custom appsec-config (ie, the request will be always allowed):
130+
131+
```yaml title="/etc/crowdsec/appsec-configs/my_config.yaml"
132+
name: custom/my_config
133+
on_match:
134+
- filter: req.URL.Host == "foo.com"
135+
apply:
136+
- CancelEvent()
137+
- CancelAlert()
138+
- SetRemediation("allow")
139+
```
140+
141+
With this config, the rules will still be evaluated, but if a rule matches no alert or event will be generated, and the remediation will be set to `allow`(ie, instruct the bouncer to let the request through).
142+
61143
## Appsec configuration
62144

63145
The AppSec configuration is referenced by the acquisition configuration (`appsec_config`, `appsec_configs` or `appsec_config_path`):

crowdsec-docs/docs/appsec/hooks.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,14 @@ Any other values (including `ban` and `captcha`) are transmitted as-is to the re
211211

212212

213213

214+
### `req` object
214215

216+
The `pre_eval`, `on_match` and `post_eval` hooks have access to a `req` variable that represents the HTTP request that was forwarded to the appsec.
217+
218+
It's a Go [http.Request](https://pkg.go.dev/net/http#Request) object, so you can directly access all the details about the request.
219+
220+
For example:
221+
- To get the requested URI: `req.URL.Path`
222+
- To get the client IP: `req.RemoteAddr`
223+
- To get the HTTP method: `req.Method`
224+
- To get the FQDN: `req.URL.Host`

crowdsec-docs/docs/appsec/intro.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ You can follow our quick start guides depending on your web server:
7070
Or consider learning more about the AppSec capabilities:
7171

7272
- **Rules**: [How to read, write and debug rules](/appsec/rules_syntax.md)
73-
<!-- TODO -->
74-
- **Scenarios**: How to create scenarios that leverage the AppSec Component events
75-
- **Hooks**: [For advanced use let's talk about possible Hooks](/appsec/hooks.md)
73+
- **Scenarios**: [How to create scenarios that leverage the AppSec Component events](/appsec/alerts_and_scenarios.md)
74+
- **Hooks**: [To customise behavior of the AppSec at runtime](/appsec/hooks.md)
7675
- **Troubleshoot**: [How to troubleshoot the behavior of the AppSec Component](/appsec/troubleshooting.md)
7776
- **AppSec Protocol**: [if you're maintaining or creating a remedation component and want to add the AppSec capabilities](/appsec/protocol.md)

crowdsec-docs/docs/appsec/protocol.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ This documentation can be useful in case you want to write your own remediation
2222

2323
To work with the CrowdSec application security component, some HTTP headers are require, in addition to the other HTTP headers and the body of the original request.
2424

25-
| Header Name | Description |
26-
| --------------------------- | -------------------------------------------------------------------------- |
27-
| `X-Crowdsec-Appsec-Ip` | The Real IP address of the original HTTP request |
28-
| `X-Crowdsec-Appsec-Uri` | The URI of the original HTTP request |
29-
| `X-Crowdsec-Appsec-Host` | The Host of the original HTTP request |
30-
| `X-Crowdsec-Appsec-Verb` | The Method of the original HTTP request |
31-
| `X-Crowdsec-Appsec-Api-Key` | The API Key to communicate with the CrowdSec application security component |
32-
| `X-Crowdsec-Appsec-User-Agent`| The User-Agent of the original HTTP request |
25+
| Header Name | Description |
26+
| -------------------------------- | ------------------------------------------------------------------------------------- |
27+
| `X-Crowdsec-Appsec-Ip` | The Real IP address of the original HTTP request |
28+
| `X-Crowdsec-Appsec-Uri` | The URI of the original HTTP request |
29+
| `X-Crowdsec-Appsec-Host` | The Host of the original HTTP request |
30+
| `X-Crowdsec-Appsec-Verb` | The Method of the original HTTP request |
31+
| `X-Crowdsec-Appsec-Api-Key` | The API Key to communicate with the CrowdSec application security component |
32+
| `X-Crowdsec-Appsec-User-Agent` | The User-Agent of the original HTTP request |
33+
| `X-Crowdsec-Appsec-Http-Version` | The HTTP version used by the original HTTP request (in integer form `10`, `11`, ...) |
3334

3435
:::note
3536

@@ -96,11 +97,11 @@ username=admin' OR '1'='1' -- &password=password
9697

9798
According to the result of the processing of the HTTP request, the application security component will respond with a different HTTP code and body.
9899

99-
| HTTP Code | Description | Body |
100-
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
101-
| `200` | The HTTP request is allowed | `{"action" : "allow"}` |
102-
| `403` | The HTTP request triggered one or more application security component rules | `{"action" : "ban", "http_status": 403}` or `{"action" : "captcha", "http_status": 403}` |
103-
| `500` | An error occurred in the application security component. The remediation component must support a `APPSEC_FAILURE_ACTION` parameter to handle this case | `null` |
104-
| `401` | The remediation component is not authenticated. It must use the same API Key that was generated to pull the local API request | `null` |
100+
| HTTP Code | Description | Body |
101+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
102+
| `200` | The HTTP request is allowed | `{"action" : "allow"}` |
103+
| `403` | The HTTP request triggered one or more application security component rules | `{"action" : "ban", "http_status": 403}` or `{"action" : "captcha", "http_status": 403}` |
104+
| `500` | An error occurred in the application security component. The remediation component must support a `APPSEC_FAILURE_ACTION` parameter to handle this case | `null` |
105+
| `401` | The remediation component is not authenticated. It must use the same API Key that was generated to pull the local API request | `null` |
105106

106107
In case of a `403` response, the body will contain the action to take and the HTTP status code to return to the client.

0 commit comments

Comments
 (0)