-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hide "did you mean" suggestions via internal plugin to avoid leaking …
…schema information (#7916) It was previously discussed (see: #3919) to wait for graphql/graphql-js#2247 to close, however, that issue has not moved in years and in the mean time libraries and frameworks seem to have opted for implementing their own solutions (E.g. https://github.com/Escape-Technologies/graphql-armor/blob/main/packages/plugins/block-field-suggestions/src/index.ts). This should be a very low impact change that achieves the goal that would also be easy enough to rip out if this gets properly implemented in graphql-js later. Adds `hideSchemaDetailsFromClientErrors` option to ApolloServer to allow hiding of these suggestions. Before: `Cannot query field "helloo" on type "Query". Did you mean "hello"?` After: `Cannot query field "helloo" on type "Query".` Fixes #3919
- Loading branch information
1 parent
d8e6da5
commit 4686454
Showing
9 changed files
with
183 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
'@apollo/server': minor | ||
--- | ||
|
||
Add `hideSchemaDetailsFromClientErrors` option to ApolloServer to allow hiding 'did you mean' suggestions from validation errors. | ||
|
||
Even with introspection disabled, it is possible to "fuzzy test" a graph manually or with automated tools to try to determine the shape of your schema. This is accomplished by taking advantage of the default behavior where a misspelt field in an operation | ||
will be met with a validation error that includes a helpful "did you mean" as part of the error text. | ||
|
||
For example, with this option set to `true`, an error would read `Cannot query field "help" on type "Query".` whereas with this option set to `false` it would read `Cannot query field "help" on type "Query". Did you mean "hello"?`. | ||
|
||
We recommend enabling this option in production to avoid leaking information about your schema to malicious actors. | ||
|
||
To enable, set this option to `true` in your `ApolloServer` options: | ||
|
||
```javascript | ||
const server = new ApolloServer({ | ||
typeDefs, | ||
resolvers, | ||
hideSchemaDetailsFromClientErrors: true | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"name": "@apollo/server/plugin/disableSuggestions", | ||
"type": "module", | ||
"main": "../../dist/cjs/plugin/disableSuggestions/index.js", | ||
"module": "../../dist/esm/plugin/disableSuggestions/index.js", | ||
"types": "../../dist/esm/plugin/disableSuggestions/index.d.ts", | ||
"sideEffects": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
packages/server/src/__tests__/plugin/disableSuggestions/disableSuggestions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { ApolloServer, HeaderMap } from '../../..'; | ||
import { describe, it, expect } from '@jest/globals'; | ||
import assert from 'assert'; | ||
|
||
describe('ApolloServerPluginDisableSuggestions', () => { | ||
async function makeServer({ | ||
withPlugin, | ||
query, | ||
}: { | ||
withPlugin: boolean; | ||
query: string; | ||
}) { | ||
const server = new ApolloServer({ | ||
typeDefs: 'type Query {hello: String}', | ||
resolvers: { | ||
Query: { | ||
hello() { | ||
return 'asdf'; | ||
}, | ||
}, | ||
}, | ||
hideSchemaDetailsFromClientErrors: withPlugin, | ||
}); | ||
|
||
await server.start(); | ||
|
||
try { | ||
return await server.executeHTTPGraphQLRequest({ | ||
httpGraphQLRequest: { | ||
method: 'POST', | ||
headers: new HeaderMap([['apollo-require-preflight', 't']]), | ||
search: '', | ||
body: { | ||
query, | ||
}, | ||
}, | ||
context: async () => ({}), | ||
}); | ||
} finally { | ||
await server.stop(); | ||
} | ||
} | ||
|
||
it('should not hide suggestions when plugin is not enabled', async () => { | ||
const response = await makeServer({ | ||
withPlugin: false, | ||
query: `#graphql | ||
query { | ||
help | ||
} | ||
`, | ||
}); | ||
|
||
assert(response.body.kind === 'complete'); | ||
expect(JSON.parse(response.body.string).errors[0].message).toBe( | ||
'Cannot query field "help" on type "Query". Did you mean "hello"?', | ||
); | ||
}); | ||
|
||
it('should hide suggestions when plugin is enabled', async () => { | ||
const response = await makeServer({ | ||
withPlugin: true, | ||
query: `#graphql | ||
query { | ||
help | ||
} | ||
`, | ||
}); | ||
|
||
assert(response.body.kind === 'complete'); | ||
expect(JSON.parse(response.body.string).errors[0].message).toBe( | ||
'Cannot query field "help" on type "Query".', | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import type { ApolloServerPlugin } from '../../externalTypes/index.js'; | ||
import { internalPlugin } from '../../internalPlugin.js'; | ||
|
||
export function ApolloServerPluginDisableSuggestions(): ApolloServerPlugin { | ||
return internalPlugin({ | ||
__internal_plugin_id__: 'DisableSuggestions', | ||
__is_disabled_plugin__: false, | ||
async requestDidStart() { | ||
return { | ||
async validationDidStart() { | ||
return async (validationErrors) => { | ||
validationErrors?.forEach((error) => { | ||
error.message = error.message.replace( | ||
/ ?Did you mean(.+?)\?$/, | ||
'', | ||
); | ||
}); | ||
}; | ||
}, | ||
}; | ||
}, | ||
}); | ||
} |