-
Notifications
You must be signed in to change notification settings - Fork 1.1k
READY - Stop DOS attacks by making the lexer stop early on evil input. #2892
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
Conversation
The questions to be answered here is whether to track the whitespace and line comment channels or not. They are fast BUT they still take some time BUT not like the grammar channel does. when we run the ParserBadSituations program with unlimited tokens the numbers for whitespace and comments are something like
So it starts to creep up BUT nothing like the grammar file which is 2 orders of magnitude slower! This is what is discovered debugging. Channel 0 (grammar tokens) get put into the parse tree and this is quite costly when you have 10s of 1000s of them. The cost is in the lexing AND in the parse tree building so it makes total sense for them to be strongly limited. However there is 2 other channels - whitespace and line comments ( And then when the parser is called back - this line means we throw them away.
So they accumulate fast enough and then are never used. The line comments are also accumulated, not as fast because they are actually used in the parser tree.
By default (even for queries) we keep the line comments. So an attack vector is to send in
However as the numbers above show even this is fast-ish. My fear is around whitespace. That 15,000 whitespace characters will catch some queries out. I mean some queries might be say 512KB in size - they will likely be below 15,000 grammar tokens BUT could they be 1/3 whitespace - (170,000 whitespace chars say) - yeah why not. So this PR as it is (counting whitespace the same as grammar tokens or line comments) will stop them sending in such a query. I think this leads us towards having 2 |
…ce counts separate from token counts
…ce counts separate from token counts - tweaks
…ce counts separate from token counts - tweaks
…ce counts separate from token counts - tweaks
After chats with Andi and Donna, we decided to
|
…ad of map with comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1: Small naming change
2: I think with introducing defaultOperationParserOptions we should rethink the SchemaParser.parseImpl
where we overwrite the maxTokens
. I think we don't need this anymore if we have two different ParserOptions.
@@ -46,6 +49,11 @@ | |||
@PublicApi | |||
public class Parser { | |||
|
|||
@Internal | |||
public static final int CHANNEL_COMMENTS = 2; | |||
@Internal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets call this also whitespace channel and not ignored ones to make it consistent with the options.
* If you want to allow more, then {@link #setDefaultParserOptions(ParserOptions)} allows you to change this | ||
* JVM wide. | ||
*/ | ||
public static final int MAX_WHITESPACE_TOKENS = 200_000; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should name this SDL
parser options or so to make clear it will be used for Schema Parsing. See also my general review comment.
Do you have( or are planning to create) a CVE for this? |
We don't have concrete plans - mainly because we are unsure of the process and the work involved. If you know more about this works and could coach us on process that would great because we aren't against the idea, we just know very little about the how of it |
UPD. CVE-2022-37734 is assigned. Hi @bbakerman , |
@act1on3 I'd like to update the CVE with all versions containing the fix: v19.0/19.1/19.2, v18.3, and v17.4. I've never had to update a CVE before - do you have any way to edit the text from your end? |
Hi @dondonz , |
Considering the different packports, is the range correct? Ie: are users with 17.x versions that have the backport vulnerable? |
Thanks @act1on3, I ended up contacting MITRE to fix it. @yeikel Yes version v17.4 contains the backport, see the release notes https://github.com/graphql-java/graphql-java/releases/tag/v17.4 |
If that's the case, then we should explicitly state that in the CVE. Otherwise, scanning systems will flag versions that are safe |
@yeikel I agree, I'm getting automated tickets myself at work. The CVE text has been updated to reference the backported versions.
https://www.cve.org/CVERecord?id=CVE-2022-37734 I am also speaking to Snyk to fix their recommendation. |
* 19.3: (709 commits) use class loader in getResource (graphql-java#3038) Stable port of graphql-java#2940 (graphql-java#2947) Stable port of Diff counts are the same (graphql-java#2946) Stable port of Fix printing directives when they contain something like a formatting specifier (graphql-java#2919) (graphql-java#2920) (graphql-java#2945) Stable port of Fix field visibility bug with enum with enum args (graphql-java#2926) (graphql-java#2944) Stable fix for graphql-java#2943 (graphql-java#2943) Added test fore intersection Xuorig Fix PR - Edge case with GraphQLTypeReference and Schema Transforms (graphql-java#2906) Fix typo in description of skip directive (graphql-java#2915) Add smaller set first optimisation Cheaper calculation for narrowing down possible objects in ENO Handles isDeprecated not being present in the json Defaults Locale when calling validation (graphql-java#2908) DF SelectionSet Benchmark (graphql-java#2893) Test stability (graphql-java#2903) Donna's catch! (graphql-java#2900) Deprecate Apollo Cache Control READY - Stop DOS attacks by making the lexer stop early on evil input. (graphql-java#2892) Bump java-dataloader ahead of release State is passed explicitly to instrumentation and parameters are NOT mutated (graphql-java#2769) ... # Conflicts: # README.md # build.gradle # src/main/java/graphql/GraphQL.java # src/main/java/graphql/Scalars.java # src/main/java/graphql/execution/ValuesResolver.java # src/main/java/graphql/relay/SimpleListConnection.java # src/main/java/graphql/schema/DataFetchingEnvironmentImpl.java
This is related to #2888
The bug was that we do indeed have a max token counting mechanism in graphql-java BUt it was being enacted too late.
Testing showed that the max token code was indeed being hit BUT the ANTLR lexing and parsing code was taking proportionally longer to get to the max token state as the input size increased
This is cause bv the greedy nature of the ANTLR Lexer - it will look ahead and store tokens in memory under certain grammar conditions and butted directives like
@lol@lol
are one of them. This meant that the lexer was the code contributing to CPU time and not the parser - BUT the max token code check was in the parser.This PR puts the same max token checks on the lexer as it does in the parser. In fact it debatable if the parser checks should still be retained (since the lexer will be the main way this will be hit) but the logic is common so I left it in place.
The current existing billion
@lols
test still parse with this change - The difference is where cancel parse exception is being thrown.The use of the lexer as the place to count means the counting checks are done in constant time. As soon as the max tokens is encountered, the parse is stopped.
graphql-java also uses 3 channels for tokens (0 for the grammar and 2 and 3 for comments and whitespace). The lexing of whitespace and comments also take up CPU time so they counters have been put in place to watch tokens on those channels as well.
This will stop a "mostly whitespace" attack, even though whitespace costs less to aggregate in practice