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

wasi-http: Filter forbidden headers #7538

Merged

Conversation

elliottt
Copy link
Member

@elliottt elliottt commented Nov 14, 2023

Make sure that forbidden headers don't show up in either incoming-request or outgoing-response values. One place that this PR doesn't currently address is incoming trailers. The future-trailers.get method returns a new fields resource every time it's called once it has resolved, and it's not clear where the best place to filter forbidden headers is in that case. I think the right fix for that would be to make future-trailers.get method return a result exactly once, like our other future-*.get methods, enabling us to apply the filter when we create the new owned fields resource.

@elliottt elliottt requested a review from a team as a code owner November 14, 2023 21:11
@elliottt elliottt requested review from alexcrichton and pchickey and removed request for a team November 14, 2023 21:11
Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be backported to Wasmtime 15 as well?

@elliottt elliottt added this pull request to the merge queue Nov 14, 2023
Merged via the queue into bytecodealliance:main with commit 3db4c91 Nov 14, 2023
18 checks passed
@elliottt elliottt deleted the trevor/filter-out-forbidden-headrs branch November 14, 2023 22:51
elliottt added a commit to elliottt/wasmtime that referenced this pull request Nov 14, 2023
elliottt added a commit that referenced this pull request Nov 15, 2023
* wasi-http: Implement http-error-code, and centralize error conversions (#7534)
* Filter out forbidden headers on incoming request and response resources (#7538)
@sporkmonger
Copy link

sporkmonger commented Dec 21, 2023

I'm wondering if this is the really the right place for this logic, particularly on incoming requests (as opposed to outgoing requests). I'm using the incoming request type in the context of detections (rather than in request handlers) where it's preferred that these headers aren't stripped because they may carry information indicating malicious behavior by a client. If they're stripped in a constructor before they can be inspected, detections will be potentially working with missing crucial information. I want to be able to compose detection logic with request handlers, which is why I'm using the same type.

@dicej
Copy link
Collaborator

dicej commented Aug 27, 2024

@elliottt Sorry for chiming in super late here, but @bacongobbler and I tripped over this code today and have some questions about it.

For context: we're currently working on porting an ASP.NET Core app to WASI. This app happens to use Dapr, which in turn uses gRPC, which sets a TE: trailers header on outgoing requests, which is currently rejected by is_forbidden_header by way of HostFields::from_list.

Our questions:

  • In your PR summary, you said "Make sure that forbidden headers don't show up in either incoming-request or outgoing-response values," but this code also affects outgoing requests as well since is_forbidden_header is used when constructing headers for any purpose. Was that intentional? I'm assuming so, but wanted to verify.
  • I can see that the WasiHttpView trait also has an is_forbidden_header function, presumably so embedders can override it, but AFAICT the WasiHttpView version is never used -- only the top-level function is used. Am I missing something? Or, if not, was that also intentional?
  • Where did the FORBIDDEN_HEADERS list come from? I found https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name and see some overlap, but it's not an exact match.

I have other questions about how to use gRPC via wasi-http, but they're probably off topic here, so I'll ask those elsewhere.

@elliottt
Copy link
Member Author

elliottt commented Aug 27, 2024

  • In your PR summary, you said "Make sure that forbidden headers don't show up in either incoming-request or outgoing-response values," but this code also affects outgoing requests as well since is_forbidden_header is used when constructing headers for any purpose. Was that intentional? I'm assuming so, but wanted to verify.

That was intentional. The list seemed pretty small, and the overlap between requests and responses seemed acceptable.

  • I can see that the WasiHttpView trait also has an is_forbidden_header function, presumably so embedders can override it, but AFAICT the WasiHttpView version is never used -- only the top-level function is used. Am I missing something? Or, if not, was that also intentional?

It's called in types_impl.rs, but called as is_forbidden_header(self, ...) rather than as a method of self.

if is_forbidden_header(self, &header) {

That function ultimately bottoms out in the view's function here:

FORBIDDEN_HEADERS.contains(name) || view.is_forbidden_header(name)

There's a test that ensures it's working by adding a custom forbidden header.

async fn wasi_http_proxy_tests() -> anyhow::Result<()> {
let req = hyper::Request::builder()
.header("custom-forbidden-header", "yes")
.uri("http://example.com:8080/test-path")
.method(http::Method::GET);

It grew slightly over time, and was informed by some folks that @lukewagner coordinated with in Fastly, he might remember more context about where the full list came from.

(edited to add the link to the actual call to view.is_forbidden_header)

@dicej
Copy link
Collaborator

dicej commented Aug 27, 2024

Thanks, @elliottt! As I learn more about gRPC, I'm realizing that gRPC-on-wasi-http isn't possible given the current state of wasi-http, so we'll pursue the wasi-sockets route instead.

@lukewagner
Copy link
Collaborator

It grew slightly over time, and was informed by some folks that @lukewagner coordinated with in Fastly, he might remember more context about where the full list came from.

FWIW, the list is in this doc, this section. Ideally I think this list would go into the wasi-http spec itself, but what's in the doc was the result of asking various HTTP folks (inside and outside Fastly).

@pchickey
Copy link
Contributor

It's unfortunate that wasi-http can't support gRPC as currently specified! Concretely, it seems to me that setting a header TE: trailers (directives list here https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE) and other values should be "ok" if the underlying http implementation is actually able to accept those (e.g. whatwg fetch cannot support TE: trailers, but hyper can). Should we refine the spec to allow this behavior?

@dicej
Copy link
Collaborator

dicej commented Aug 27, 2024

We'll also need some way for the guest to require HTTP/2.

And yeah, I'd definitely be in favor of making wasi-http gRPC-compatible!

@lukewagner
Copy link
Collaborator

Yes, agreed on the goal of making wasi-http gRPC-compatible; that has been a goal since the beginning (and the reason we have trailers in the first place).

The goal of putting TE in the definitely-forbidden list is so that the host is empowered to set this as a transport-/implementation-detail (similar to Transport-Encoding). Could we perhaps have some "expect-trailers" flag on outgoing-request that clients can set that tells the host impl to both set TE: trailers and also require H2 (or, reading RFC 9110 6.5.1, maybe it even works for HTTP/1.1?).

@dicej
Copy link
Collaborator

dicej commented Aug 27, 2024

I think the trailers issue and the "require H2" issue are somewhat orthogonal. The latter is because gRPC is defined to use HTTP/2 specifically.

@pavelsavara
Copy link

This will be impossible or interesting in JCO because of browser fetch limitations.

@dicej
Copy link
Collaborator

dicej commented Aug 28, 2024

This will be impossible or interesting in JCO because of browser fetch limitations.

That's true, but a wasi-aockets-based solution would also be difficult or impossible. The grpc-web protocol exists specifically to handle the browser case, so presumably an app intended to be maximally portable would be prepared to fall back to that.

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

Successfully merging this pull request may close these issues.

7 participants