coraza-proxy-wasm icon indicating copy to clipboard operation
coraza-proxy-wasm copied to clipboard

Setting custom response with local_reply_config not working

Open ropnop opened this issue 9 months ago • 4 comments

Hello! Not sure if this an Envoy issue or Coraza proxy wasm issue, but hoping for some guidance. We use Envoy's local_reply_config setting to return JSON formatted messages on local replies that include a request ID. For other filters like RBAC, this works fine, but for Coraza, when it blocks a request the body of the response is cut off and not sent.

To reproduce, add the following to the example envoy config, under the http_connection_manager's typed config:

local_reply_config:
  body_format:
    json_format:
      status: "%RESPONSE_CODE%"
      message: "%LOCAL_REPLY_BODY%"
      host: "%REQ(:authority)%"
  mappers:
    - filter:
        status_code_filter:
          comparison:
            op: EQ
            value:
              default_value: 403
              runtime_key: http.local_reply.status_code
      headers_to_add:
        - header:
            key: "x-envoy-unauthorized"
            value: "true"
      body:
        inline_string: "unauthorized"

This should "intercept" any 403 local reply from Envoy and replace with a JSON reply with a message of "unauthorized"

Running go run mage.go runEnvoyExample to load the config, curl unexpectedly ends before the response body is received:

$ curl -vv "http://localhost:8080/anything?arg=<script>alert(0)</script>"
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /anything?arg=<script>alert(0)</script> HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 403 Forbidden
< custom_header: custom_value
< x-envoy-unauthorized: true
< content-length: 185
< content-type: application/json
< date: Fri, 10 May 2024 02:41:21 GMT
< server: envoy
<
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
* Failure writing output to destination, passed 185 returned 4294967295
* Closing connection

The response headers are being set correctly by the local_reply_config (e.g. content-type, content-length and the custom x-envoy-unauthorized) but the response body is being sent as null bytes

Any ideas?

ropnop avatar May 10 '24 02:05 ropnop

This is expected, if we block the response body should not being sent, however sometimes things like content-length has been sent already and our only chance is to return a null byte body to not to keep the client hanging.

On Fri, May 10, 2024 at 4:43 AM Ronnie Flathers @.***> wrote:

Hello! Not sure if this an Envoy issue or Coraza proxy wasm issue, but hoping for some guidance. We use Envoy's local_reply_config setting to return JSON formatted messages on local replies that include a request ID. For other filters like RBAC, this works fine, but for Coraza, when it blocks a request the body of the response is cut off and not sent.

To reproduce, add the following to the example envoy config https://github.com/corazawaf/coraza-proxy-wasm/blob/main/example/envoy/envoy-config.yaml, under the http_connection_manager's typed config:

local_reply_config: body_format: json_format: status: "%RESPONSE_CODE%" message: "%LOCAL_REPLY_BODY%" host: "%REQ(:authority)%" mappers: - filter: status_code_filter: comparison: op: EQ value: default_value: 403 runtime_key: http.local_reply.status_code headers_to_add: - header: key: "x-envoy-unauthorized" value: "true" body: inline_string: "unauthorized"

This should "intercept" any 403 local reply from Envoy and replace with a JSON reply with a message of "unauthorized"

Running go run mage.go runEnvoyExample to load the config, curl unexpectedly ends before the response body is received:

$ curl -vv "http://localhost:8080/anything?arg="

  • Host localhost:8080 was resolved.
  • IPv6: ::1
  • IPv4: 127.0.0.1
  • Trying [::1]:8080...
  • Connected to localhost (::1) port 8080

GET /anything?arg= HTTP/1.1 Host: localhost:8080 User-Agent: curl/8.7.1 Accept: /

  • Request completely sent off < HTTP/1.1 403 Forbidden < custom_header: custom_value < x-envoy-unauthorized: true < content-length: 185 < content-type: application/json < date: Fri, 10 May 2024 02:41:21 GMT < server: envoy < Warning: Binary output can mess up your terminal. Use "--output -" to tell Warning: curl to output it to your terminal anyway, or consider "--output Warning: <FILE>" to save to a file.
  • Failure writing output to destination, passed 185 returned 4294967295
  • Closing connection

The response headers are being set correctly by the local_reply_config (e.g. content-type, content-length and the custom x-envoy-unauthorized) but the response body is being sent as null bytes

Any ideas?

— Reply to this email directly, view it on GitHub https://github.com/corazawaf/coraza-proxy-wasm/issues/273, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXOYAWLLY2EDXBC62WQWDTZBQX5LAVCNFSM6AAAAABHP23IWWVHI2DSMVQWIX3LMV43ASLTON2WKOZSGI4DQOBQG4YTIMI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

jcchavezs avatar May 10 '24 22:05 jcchavezs

I see. Is that behavior specific to Coraza's interruptions or just general to proxy-wasm behavior in Envoy?

I did see that it sends a nil body with the response code here, but assumed that Envoy would still treat that response as a "local reply" and it would be caught and handled by the config the HttpConnectionManager. Do you know if the HttpResponse from proxy-wasm filters are somehow treated differently than, say, the responses from the builtin RBAC or JWT filters that could also return a 403?

ropnop avatar May 11 '24 01:05 ropnop

Okay i may have found the answer to my own question. The bulitin filters are calling a function sendLocalReply, so that explains how Envoy is handling them. I don't see anything available in the proxy-wasm Go SDK that could provide that functionality, so maybe the proxy-wasm interface doesn't expose a way to do "local replies" directly in Envoy where this could be used

ropnop avatar May 11 '24 01:05 ropnop

I see. Is that behavior specific to Coraza's interruptions or just general to proxy-wasm behavior in Envoy?

In general we should not set response but since we already sent the content-length we have to honour the body length and the only option is to null it.

so maybe the proxy-wasm interface doesn't expose a way to do "local replies" directly in Envoy where this could be used

local reply is an envoy thing and proxy-wasm was supposed to be interoperable.

jcchavezs avatar Jun 14 '24 05:06 jcchavezs