Skip to content

Commit 6c6f323

Browse files
rattrayalexbenjie
andauthored
Update Persisted Operations section (#271)
Co-authored-by: Benjie Gillam <benjie@jemjie.com>
1 parent b72b21c commit 6c6f323

1 file changed

Lines changed: 35 additions & 71 deletions

File tree

src/pages/postgraphile/production.md

Lines changed: 35 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -189,77 +189,41 @@ app.use(postgraphile(pool, "public", { ... }));
189189

190190
#### Simple: Query Allowlist ("persisted queries" / "persisted operations")
191191

192-
If you do not intend to open your API up to third parties to run arbitrary
193-
queries against then using persisted queries as a query whitelist to protect
194-
your GraphQL endpoint is a great and highly recommended solution. This technique
195-
ensures that only the queries you use in your own applications can be executed
196-
on the server (but you can of course change the variables).
197-
198-
This technique has a few caveats:
199-
200-
- Your API will only accept queries that you've approved, so it's not suitable
201-
if you want third parties to run arbitrary queries
202-
- You must be able to generate a unique ID from each query; e.g. a hash
203-
- You must use "static GraphQL queries" - that is the queries must be known at
204-
build time of your application/webpage, and only the variables fed to those
205-
queries can change at run-time
206-
- You must have a way of sharing these queries between the application and the
207-
server
208-
- You must be careful not to use variables in dangerous places; for example
209-
don't write `allUsers(first: $myVar)` as a malicious attacker could set
210-
`$myVar` to 2147483647 in order to cause your server to process as much data
211-
as possible.
212-
213-
_**THIS SECTION IS OUT OF DATE**; please refer to the new
214-
[@graphile/persisted-operations project](https://github.com/graphile/persisted-operations)
215-
for up to date information and implementation details._
216-
217-
~~PostGraphile currently doesn't have this functionality built in, but it's
218-
fairly easy to add it when using PostGraphile as an express middleware, a simple
219-
implementation might look like this:~~
220-
221-
```js{9-18}
222-
const postgraphile = require("postgraphile");
223-
const express = require("express");
224-
const bodyParser = require("body-parser");
225-
226-
const app = express();
227-
app.use(bodyParser.json());
228-
229-
/**** BEGINNING OF CUSTOMIZATION ****/
230-
const persistedQueries = require("./persistedQueries.json");
231-
232-
app.use("/graphql", async (req, res, next) => {
233-
// TODO: validate req.body is of the right form
234-
req.body.query = {}.hasOwnProperty.call(persistedQueries, req.body.id)
235-
? persistedQueries[req.body.id]
236-
: null;
237-
next();
238-
});
239-
/**** END OF CUSTOMIZATION *** */
240-
241-
app.use(postgraphile());
242-
243-
app.listen(5000);
244-
```
245-
246-
~~i.e. a simple middleware mounted before postgraphile that manipulates the
247-
request body.~~
248-
249-
~~I (Benjie) personally use my forks of Apollo's `persistgraphql` tools to help
250-
me manage the persisted queries themselves:~~
251-
252-
- ~~https://github.com/benjie/persistgraphql~~
253-
- ~~https://github.com/benjie/persistgraphql-webpack-plugin~~
254-
255-
~~These forks generate hashes rather than numbers; which make the persisted
256-
queries consistent across multiple builds and applications (website, mobile,
257-
browser plugin, ...).~~
258-
259-
**NOTE**: even if you're using persisted operations, it can still be wise to
260-
implement advanced protections as it enables you to catch unnecessarily
261-
expensive queries during development, before you start facing performance
262-
bottlenecks down the line.
192+
If you do not intend to allow third parties to run arbitrary operations against
193+
your API then using
194+
[persisted operations](https://github.com/graphile/persisted-operations) as a
195+
query allowlist is a highly recommended solution to protect your GraphQL
196+
endpoint. This technique ensures that only the operations you use in your own
197+
applications can be executed on the server, preventing malicious (or merely
198+
curious) actors from executing operations which may be more expensive than those
199+
you have written.
200+
201+
This technique is suitable for the vast majority of use cases and supports many
202+
GraphQL clients, but it does have a few caveats:
203+
204+
- Your API will only accept operations that you've approved, so it's not
205+
suitable if you want third parties to run arbitrary custom operations.
206+
- You must be able to generate a unique ID (e.g. a hash) from each operation at
207+
build time of your application/web page - your GraphQL operations must be
208+
"static". It's important to note this only applies to the operation document
209+
itself, the variables can of course change at runtime.
210+
- You must have a way of sharing these static operations from the application
211+
build process to the server so that the server will know what operation the ID
212+
represents.
213+
- You must be careful not to use variables in dangerous places within your
214+
operation; for example if you were to use `allUsers(first: $myVar)` a
215+
malicious attacker could set `$myVar` to 2147483647 to cause your server to
216+
process as much data as possible. Use fixed limits, conditions and orders
217+
where possible, even if it means having additional static operations.
218+
- It does not protect you from writing expensive queries yourself; it may be
219+
wise to combine this technique with a cost estimation technique such as that
220+
provided by the [Graphile Pro plugin](/postgraphile/pricing/) to help guide
221+
your developers and avoid accidentally writing expensive queries.
222+
223+
PostGraphile has first-party support for persisted operations via the open
224+
source
225+
[@graphile/persisted-operations](https://github.com/graphile/persisted-operations)
226+
plugin; we recommend its use to the vast majority of our users.
263227

264228
#### Advanced
265229

0 commit comments

Comments
 (0)