API Mass Assignment Mitigation
## Background

I looked through the docs and existing issues, so forgive me if this feature already exists.

Our services are scanned by an external team. This team does penetration testing, and they claim our Apollo GraphQL services are vulnerable to something they deem _API Mass Assignment_. To quote their scan report:

> - **Risk**: API Mass Assignment exploitation may lead to privilege escalation, data tampering, bypass of security mechanisms.
> - **Cause**: API endpoints are vulnerable to Mass Assignment if they automatically convert client provided data into internal object properties without considering the sensitivity and the exposure level of these properties.
> - **Fix**: Avoid using functions that automatically bind client's input to code variables or internal objects. If applicable, explicitly define and enforce schema's for the input data payloads.

We understand their concern, and we've explained to them that Apollo _does indeed_ do schema validation, but it silently ignores any invalid fields passed in the request body.

This wasn't good enough. They expected a `400 Bad Request` response when invalid fields were added to the request body.

We ended up developing a custom solution. It's a plugin that hooks into the `didResolveSource` event, parses the request body, then validates the fields against an allow-list. If invalid fields are found, it responds with the relevant error. See snippet below.

## Question/feature

- Does Apollo have this feature built-in?
- If not, what are your thoughts on adding it?
- Otherwise, would you make any improvements to this approach?

Thanks for your time, and thanks for this server 👍 

## Snippet

<details><summary>Details</summary>

```ts
export class BadRequestGraphQLError extends GraphQLError {
  constructor(message: string) {
    super(message, {
      extensions: {
        code: 'BAD_REQUEST',
        http: {
          status: 400
        }
      }
    });
  }
}

const ALLOWED_BODY_FIELDS = ['operationName', 'variables', 'query', 'extensions'];

export const massApiAssignmentValidationPlugin = <TContext extends BaseContext>(params: {
  logger: Logger;
}): ApolloServerPlugin<TContext> => {
  const { logger } = params;

  return {
    async requestDidStart() {
      return {
        async didResolveSource(requestContext) {
          const body = (requestContext.request.http?.body ?? {}) as Record<string, unknown>;

          const invalidFields = Object.keys(body).filter((field) => {
            return !ALLOWED_BODY_FIELDS.some((allowedField) => {
              return field === allowedField;
            });
          });

          if (invalidFields.length > 0) {
            const message = `Invalid fields detected: ${invalidFields.join(', ')}`;
            logger.error(message);
            throw new BadRequestGraphQLError(message);
          }
        }
      };
    },

    // We have to re-throw the error, otherwise a generic 500 error is thrown.
    // See https://github.com/apollographql/apollo-server/issues/7278
    async unexpectedErrorProcessingRequest({ error }) {
      if (error instanceof BadRequestGraphQLError) {
        throw error;
      }
    }
  };
};

export interface ApolloServerContext {
  dataSources: {
    // existing data sources...
  };
}

const apolloServer = new ApolloServer<ApolloServerContext>({
  // existing configs...
  plugins: [
    // existing plugins...
    massApiAssignmentValidationPlugin<ApolloServerContext>({ logger })
  ]
});
```

</details> 