|
1 | 1 | # Upgrading libddwaf |
2 | 2 |
|
| 3 | +## Upgrading from `1.14.0` to `1.15.0` |
| 4 | + |
| 5 | +### Interface changes |
| 6 | + |
| 7 | +With the introduction of ephemeral addresses, `ddwaf_run` now allows the caller to provide data as both persistent or ephemeral. The new signature can be seen below: |
| 8 | +```c |
| 9 | +DDWAF_RET_CODE ddwaf_run(ddwaf_context context, ddwaf_object *persistent_data, |
| 10 | + ddwaf_object *ephemeral_data, ddwaf_result *result, uint64_t timeout); |
| 11 | +``` |
| 12 | +
|
| 13 | +Both `persistent_data` and `ephemeral_data` are nullable, however at least one of them has to be non-null for the call to be valid. Otherwise the call to `ddwaf_run` will return the error `DDWAF_ERR_INVALID_ARGUMENT`. |
| 14 | +
|
| 15 | +The other interface change is the renaming of `ddwaf_required_addresses` to `ddwaf_known_addresses`, aside from the name change, the signature hasn't changed, as can be seen below: |
| 16 | +
|
| 17 | +```c |
| 18 | +const char* const* ddwaf_known_addresses(const ddwaf_handle handle, uint32_t *size); |
| 19 | +``` |
| 20 | + |
| 21 | +The reason for the name change is to better reflect the nature of the addresses provided by this function, which will now provide a list of all addresses seen by the WAF, regardless of whether they are required for rule, filter or processor evaluation, or whether they are optionally used when available, such as part of an exclusion filter for inputs or a processor mapping. A more accurate distinction, as well as a breakdown of the addresses required by each of the supported high-level features, is now provided as part of the diagnostics returned by `ddwaf_init` and `ddwaf_update`. |
| 22 | + |
| 23 | +Finally, `testPowerWAF` has been renamed to `waf_test`, while this isn't an interface change it might affect those building and testing the WAF directly. |
| 24 | + |
| 25 | +### Ephemeral addresses |
| 26 | + |
| 27 | +Ephemeral addresses is a new feature aimed at providing better support for protocols composed of a single request with multiple subrequests, such as gRPC client / server streaming or GraphQL. As the name implies, ephemeral addresses are short-lived: |
| 28 | +- These addresses are only used for evaluation of rules and exclusion filters during the `ddwaf_run` call in which they are provided; subsequent calls will have no access to these addresses. |
| 29 | +- At the end of `ddwaf_run` the memory associated with the ephemeral addresses is freed. |
| 30 | + |
| 31 | +As an example, these addresses can be used to evaluate independent gRPC messages within the context of the whole HTTP request. A call with the whole HTTP context and the first gRPC message could look as follows: |
| 32 | +```json |
| 33 | +{ |
| 34 | + "persistent": { |
| 35 | + "server.request.headers.no_cookies": [ "..." ], |
| 36 | + "server.request.uri.raw": "...", |
| 37 | + "http.client_ip": "..." |
| 38 | + }, |
| 39 | + "ephemeral": { |
| 40 | + "grpc.server.request.message": { "..." } |
| 41 | + } |
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | +Subsequent calls only need to provide the relevant gRPC message data: |
| 46 | +```json |
| 47 | +{ |
| 48 | + "ephemeral": { |
| 49 | + "grpc.server.request.message": { "..." } |
| 50 | + } |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +When using ephemeral addresses in this manner, each call is somewhat equivalent to creating a new context and providing all of the data at once for each message, however: |
| 55 | +- The new approach doesn't need to reevaluate the already evaluated persistent addresses for each gRPC message. |
| 56 | +- Consequently the new approach does not provide duplicate events for the already evaluated persistent addresses. |
| 57 | +- The performance impact should be much smaller when using the new approach since less rules need to be evaluated and the context can be reused rather than created & destroyed for each message. |
| 58 | + |
| 59 | +Finally, aside from the addresses themselves being ephemeral, the outcome of any evaluation with an ephemeral address is also ephemeral. The evaluation of any condition, from either rules, filters or processors, with ephemeral addresses will always be uncached, meaning that subsequent calls to `ddwaf_run` will reevaluate said conditions if relevant addresses are provided. |
| 60 | + |
| 61 | +Similarly, any address, object or rule excluded as a result of the evaluation of an ephemeral address, either due to the filter condition matching on an ephemeral address or the excluded address being ephemeral, will only have effect for the duration of the `ddwaf_run` call. As a result, subsequent calls to `ddwaf_run` will be able to evaluate those previously excluded rules or addresses, unless filtered again. |
| 62 | + |
| 63 | +### Address diagnostics |
| 64 | +In order to provide more visibility regarding the breakdown of addresses per feature and whether they are required or optional, the latest version of the WAF introduces address diagnostics. These diagnostics can typically be obtained through a call to `ddwaf_init` or `ddwaf_update` and are broken down per feature, for example: |
| 65 | + |
| 66 | +```json |
| 67 | + |
| 68 | +{ |
| 69 | + "rules": { |
| 70 | + "loaded": [ |
| 71 | + "a45b55fc-5b57-4002-90bf-58cdf296124c" |
| 72 | + ], |
| 73 | + "failed": [], |
| 74 | + "errors": {}, |
| 75 | + "addresses": { |
| 76 | + "required": [ |
| 77 | + "http.client_ip", |
| 78 | + "usr.id", |
| 79 | + "server.request.headers.no_cookies", |
| 80 | + "graphql.server.all_resolvers", |
| 81 | + "grpc.server.request.message", |
| 82 | + "server.request.path_params", |
| 83 | + "server.request.body", |
| 84 | + "server.request.query", |
| 85 | + "server.request.uri.raw", |
| 86 | + "server.response.status", |
| 87 | + "grpc.server.request.metadata" |
| 88 | + ], |
| 89 | + "optional": [] |
| 90 | + } |
| 91 | + } |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +The distinction between required and optional addresses depends on the feature: |
| 96 | +- Rules only have required addresses. |
| 97 | +- Exclusion filters have both required and optional addresses: |
| 98 | + - The required addresses correspond to those used within the filter conditions, i.e. those which are required for the filter to be evaluated altogether. |
| 99 | + - Currently the only optional addresses are those of the excluded inputs, e.g. a filter could exclude `http.client_ip` for a specific endpoint, this address would be optional since it's only used when available. |
| 100 | +- Processors also have both required and optional addresses: |
| 101 | + - The required addresses correspond to those used within the processor conditions. |
| 102 | + - The optional addresses correspond to each of the processor mappings, for example if a processor uses `server.request.body.raw` to generate `server.request.body`, the former would be considered optional. |
| 103 | + |
| 104 | +Other diagnostics, such as `rules_data` or `rules_override`, do not provide the addresses key. |
| 105 | + |
3 | 106 | ## Upgrading from `1.12.0` to `1.13.0` |
4 | 107 |
|
5 | 108 | ### Interface changes |
|
0 commit comments