Hi all,

I forgot to put a recursion limit in the new OAuth parsers; the
server-side depth checks don't apply to the client, and it's not using
the incremental parser to move the burden from the stack to the heap.
Luckily, we track the nesting level already, so a fix (attached) can
be pretty small.

(Eventually I'd like to set a limit via the client-side JSONAPI, or
maybe port the server's stack checks? That's 19 material.)

Enforcing a limit is relatively easy, but choosing the limit is
somewhat harder, because OAuth will continue to evolve and add
extensions that we're supposed to gracefully ignore. The most typical
depth I've seen in practice is 2 (an object containing arrays of
strings). I took a look through the IANA registry [1], and I think the
maximum nesting depth we can get today is if someone plops an entire
JSON Web Key Set into their discovery document. That could bring the
depth up to 6 with some of the newer key types.

Hopefully the extension depth doesn't continue to grow unbounded, but
it's easy for spec writers to find ways to nest new stuff, so I've
chosen a max depth of 16. Probably overkill. Hopefully overkill?

For the SASL parser, which is only speaking OAUTHBEARER to a Postgres
server/proxy, I think we can be way more strict. We expect a nesting
depth of only 1 there. I've put in a limit of 8, to try to avoid a
backport in the case that some nested extension is published and
suddenly gains popularity, but I could easily be talked downwards.

And if we ever have to revisit these limits, I think that would be
reason enough to switch from the recursive descent parser over to the
incremental parser, anyway.

= Postmortem =

As an aside: I was curious why libfuzzer didn't catch this, since I've
been using it as a safety net. The answer was a depressingly simple
"you ignored a printed warning":

    INFO: -max_len is not provided; libFuzzer will not generate inputs
larger than 4096 bytes

It looks like this default limit is variable, based on the corpus you
already have, and 4K is not enough to run my machine out of stack. But
setting it explicitly to our response limit of 256K allows libfuzzer
to find this issue very quickly, and I will do that going forward.

(If anyone has run libfuzzer before and has a "favorite
configuration", I'd love to hear it!)

Thanks,
--Jacob

[1] 
https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#authorization-server-metadata

Attachment: 0001-oauth-Limit-JSON-parsing-depth-in-the-client.patch
Description: Binary data

Reply via email to