fastify 3.25.0 → 3.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +25 -25
  3. package/docs/Guides/Ecosystem.md +5 -0
  4. package/docs/Guides/Fluent-Schema.md +2 -2
  5. package/docs/Guides/Index.md +2 -0
  6. package/docs/Guides/Prototype-Poisoning.md +391 -0
  7. package/docs/Guides/Recommendations.md +1 -1
  8. package/docs/Guides/Serverless.md +3 -3
  9. package/docs/Guides/Style-Guide.md +2 -2
  10. package/docs/Guides/Testing.md +1 -1
  11. package/docs/Reference/ContentTypeParser.md +1 -1
  12. package/docs/Reference/Decorators.md +3 -3
  13. package/docs/Reference/Errors.md +1 -1
  14. package/docs/Reference/Hooks.md +9 -1
  15. package/docs/Reference/Index.md +1 -1
  16. package/docs/Reference/Plugins.md +6 -6
  17. package/docs/Reference/Reply.md +2 -2
  18. package/docs/Reference/Request.md +3 -0
  19. package/docs/Reference/Routes.md +3 -3
  20. package/docs/Reference/Server.md +6 -6
  21. package/docs/Reference/TypeScript.md +7 -7
  22. package/docs/Reference/Validation-and-Serialization.md +1 -1
  23. package/docs/index.md +1 -1
  24. package/fastify.d.ts +1 -1
  25. package/fastify.js +6 -3
  26. package/lib/contentTypeParser.js +11 -6
  27. package/lib/decorate.js +1 -1
  28. package/lib/pluginUtils.js +5 -0
  29. package/lib/route.js +7 -0
  30. package/lib/symbols.js +1 -0
  31. package/lib/warnings.js +1 -1
  32. package/package.json +6 -6
  33. package/test/404s.test.js +1 -1
  34. package/test/als.test.js +74 -0
  35. package/test/bundler/esbuild/bundler-test.js +31 -0
  36. package/test/bundler/esbuild/package.json +10 -0
  37. package/test/bundler/esbuild/src/fail-plugin-version.js +12 -0
  38. package/test/bundler/esbuild/src/index.js +7 -0
  39. package/test/bundler/webpack/bundler-test.js +15 -4
  40. package/test/bundler/webpack/src/fail-plugin-version.js +1 -3
  41. package/test/bundler/webpack/src/index.js +1 -3
  42. package/test/custom-parser.test.js +30 -31
  43. package/test/decorator.test.js +20 -6
  44. package/test/http2/constraint.test.js +91 -0
  45. package/test/plugin.name.display.js +10 -0
  46. package/test/plugin.test.js +18 -0
  47. package/test/types/fastify.test-d.ts +16 -0
  48. package/test/types/hooks.test-d.ts +28 -4
  49. package/test/versioned-routes.test.js +27 -3
  50. package/types/hooks.d.ts +31 -20
  51. package/types/instance.d.ts +6 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016-2020 The Fastify Team
3
+ Copyright (c) 2016-2022 The Fastify Team
4
4
 
5
5
  The Fastify team members are listed at https://github.com/fastify/fastify#team
6
6
  and in the README file.
package/README.md CHANGED
@@ -156,7 +156,7 @@ In a similar way, all Fastify **v2.x** related changes should be based on [**`br
156
156
 
157
157
  > ## Note
158
158
  > `.listen` binds to the local host, `localhost`, interface by default (`127.0.0.1` or `::1`, depending on the operating system configuration). If you are running Fastify in a container (Docker, [GCP](https://cloud.google.com/), etc.), you may need to bind to `0.0.0.0`. Be careful when deciding to listen on all interfaces; it comes with inherent [security risks](https://web.archive.org/web/20170711105010/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
159
- > See [the documentation](./docs/Server.md#listen) for more information.
159
+ > See [the documentation](./docs/Reference/Server.md#listen) for more information.
160
160
 
161
161
  ### Core features
162
162
 
@@ -192,36 +192,36 @@ matters to you.
192
192
  * <a href="./docs/Guides/Getting-Started.md"><code><b>Getting Started</b></code></a>
193
193
  * <a href="./docs/Guides/Index.md"><code><b>Guides</b></code></a>
194
194
  * <a href="./docs/Reference/Server.md"><code><b>Server</b></code></a>
195
- * <a href="./docs/Routes.md"><code><b>Routes</b></code></a>
195
+ * <a href="./docs/Reference/Routes.md"><code><b>Routes</b></code></a>
196
196
  * <a href="./docs/Reference/Encapsulation.md"><code><b>Encapsulation</b></code></a>
197
- * <a href="./docs/Logging.md"><code><b>Logging</b></code></a>
198
- * <a href="./docs/Middleware.md"><code><b>Middleware</b></code></a>
199
- * <a href="./docs/Hooks.md"><code><b>Hooks</b></code></a>
200
- * <a href="./docs/Decorators.md"><code><b>Decorators</b></code></a>
201
- * <a href="./docs/Validation-and-Serialization.md"><code><b>Validation and Serialization</b></code></a>
202
- * <a href="./docs/Fluent-Schema.md"><code><b>Fluent Schema</b></code></a>
203
- * <a href="./docs/Lifecycle.md"><code><b>Lifecycle</b></code></a>
204
- * <a href="./docs/Reply.md"><code><b>Reply</b></code></a>
205
- * <a href="./docs/Request.md"><code><b>Request</b></code></a>
206
- * <a href="./docs/Errors.md"><code><b>Errors</b></code></a>
207
- * <a href="./docs/ContentTypeParser.md"><code><b>Content Type Parser</b></code></a>
208
- * <a href="./docs/Plugins.md"><code><b>Plugins</b></code></a>
209
- * <a href="./docs/Testing.md"><code><b>Testing</b></code></a>
210
- * <a href="./docs/Benchmarking.md"><code><b>Benchmarking</b></code></a>
211
- * <a href="./docs/Write-Plugin.md"><code><b>How to write a good plugin</b></code></a>
212
- * <a href="./docs/Plugins-Guide.md"><code><b>Plugins Guide</b></code></a>
213
- * <a href="./docs/HTTP2.md"><code><b>HTTP2</b></code></a>
214
- * <a href="./docs/LTS.md"><code><b>Long Term Support</b></code></a>
215
- * <a href="./docs/TypeScript.md"><code><b>TypeScript and types support</b></code></a>
216
- * <a href="./docs/Serverless.md"><code><b>Serverless</b></code></a>
217
- * <a href="./docs/Recommendations.md"><code><b>Recommendations</b></code></a>
197
+ * <a href="./docs/Reference/Logging.md"><code><b>Logging</b></code></a>
198
+ * <a href="./docs/Reference/Middleware.md"><code><b>Middleware</b></code></a>
199
+ * <a href="./docs/Reference/Hooks.md"><code><b>Hooks</b></code></a>
200
+ * <a href="./docs/Reference/Decorators.md"><code><b>Decorators</b></code></a>
201
+ * <a href="./docs/Reference/Validation-and-Serialization.md"><code><b>Validation and Serialization</b></code></a>
202
+ * <a href="./docs/Guides/Fluent-Schema.md"><code><b>Fluent Schema</b></code></a>
203
+ * <a href="./docs/Reference/Lifecycle.md"><code><b>Lifecycle</b></code></a>
204
+ * <a href="./docs/Reference/Reply.md"><code><b>Reply</b></code></a>
205
+ * <a href="./docs/Reference/Request.md"><code><b>Request</b></code></a>
206
+ * <a href="./docs/Reference/Errors.md"><code><b>Errors</b></code></a>
207
+ * <a href="./docs/Reference/ContentTypeParser.md"><code><b>Content Type Parser</b></code></a>
208
+ * <a href="./docs/Reference/Plugins.md"><code><b>Plugins</b></code></a>
209
+ * <a href="./docs/Guides/Testing.md"><code><b>Testing</b></code></a>
210
+ * <a href="./docs/Guides/Benchmarking.md"><code><b>Benchmarking</b></code></a>
211
+ * <a href="./docs/Guides/Write-Plugin.md"><code><b>How to write a good plugin</b></code></a>
212
+ * <a href="./docs/Guides/Plugins-Guide.md"><code><b>Plugins Guide</b></code></a>
213
+ * <a href="./docs/Reference/HTTP2.md"><code><b>HTTP2</b></code></a>
214
+ * <a href="./docs/Reference/LTS.md"><code><b>Long Term Support</b></code></a>
215
+ * <a href="./docs/Reference/TypeScript.md"><code><b>TypeScript and types support</b></code></a>
216
+ * <a href="./docs/Guides/Serverless.md"><code><b>Serverless</b></code></a>
217
+ * <a href="./docs/Guides/Recommendations.md"><code><b>Recommendations</b></code></a>
218
218
 
219
219
  中文文档[地址](https://github.com/fastify/docs-chinese/blob/HEAD/README.md)
220
220
 
221
221
  ## Ecosystem
222
222
 
223
- - [Core](./docs/Ecosystem.md#core) - Core plugins maintained by the _Fastify_ [team](#team).
224
- - [Community](./docs/Ecosystem.md#community) - Community supported plugins.
223
+ - [Core](./docs/Guides/Ecosystem.md#core) - Core plugins maintained by the _Fastify_ [team](#team).
224
+ - [Community](./docs/Guides/Ecosystem.md#community) - Community supported plugins.
225
225
  - [Live Examples](https://github.com/fastify/example) - Multirepo with a broad set of real working examples.
226
226
  - [Discord](https://discord.gg/D3FZYPy) - Join our discord server and chat with the maintainers.
227
227
 
@@ -242,6 +242,8 @@ section.
242
242
  Fastify feature flags plugin with multiple providers support (e.g. env,
243
243
  [config](https://lorenwest.github.io/node-config/),
244
244
  [unleash](https://unleash.github.io/)).
245
+ - [`fastify-file-routes`](https://github.com/spa5k/fastify-file-routes)
246
+ Get Next.js based file system routing into fastify.
245
247
  - [`fastify-file-upload`](https://github.com/huangang/fastify-file-upload)
246
248
  Fastify plugin for uploading files.
247
249
  - [`fastify-firebase`](https://github.com/now-ims/fastify-firebase) Fastify
@@ -259,6 +261,8 @@ section.
259
261
  - [`fastify-get-head`](https://github.com/MetCoder95/fastify-get-head) Small
260
262
  plugin to set a new HEAD route handler for each GET route previously
261
263
  registered in Fastify.
264
+ - [`fastify-get-only`](https://github.com/DanieleFedeli/fastify-get-only) Small
265
+ plugin used to make fastify accept only GET requests
262
266
  - [`fastify-good-sessions`](https://github.com/Phara0h/fastify-good-sessions) A
263
267
  good Fastify sessions plugin focused on speed.
264
268
  - [`fastify-google-cloud-storage`](https://github.com/carlozamagni/fastify-google-cloud-storage)
@@ -440,6 +444,7 @@ section.
440
444
  client plugin for Fastify.
441
445
  - [`fastify-socket.io`](https://github.com/alemagio/fastify-socket.io) a
442
446
  Socket.io plugin for Fastify.
447
+ - [`fastify-split-validator`](https://github.com/MetCoder95/fastify-split-validator) Small plugin to allow you use multiple validators in one route based on each HTTP part of the request.
443
448
  - [`fastify-sse`](https://github.com/lolo32/fastify-sse) to provide Server-Sent
444
449
  Events with `reply.sse( … )` to Fastify.
445
450
  - [`fastify-sse-v2`](https://github.com/nodefactoryio/fastify-sse-v2) to provide
@@ -3,7 +3,7 @@
3
3
  ## Fluent Schema
4
4
 
5
5
  The [Validation and
6
- Serialization](/docs/Reference/Validation-and-Serialization.md) documentation
6
+ Serialization](../Reference/Validation-and-Serialization.md) documentation
7
7
  outlines all parameters accepted by Fastify to set up JSON Schema Validation to
8
8
  validate the input, and JSON Schema Serialization to optimize the output.
9
9
 
@@ -59,7 +59,7 @@ With `fluent-json-schema` you can manipulate your schemas more easily and
59
59
  programmatically and then reuse them thanks to the `addSchema()` method. You can
60
60
  refer to the schema in two different manners that are detailed in the
61
61
  [Validation and
62
- Serialization](./Validation-and-Serialization.md#adding-a-shared-schema)
62
+ Serialization](../Reference/Validation-and-Serialization.md#adding-a-shared-schema)
63
63
  documentation.
64
64
 
65
65
  Here are some usage examples:
@@ -20,6 +20,8 @@ This table of contents is in alphabetical order.
20
20
  Fastify v3 from earlier versions.
21
21
  + [Plugins Guide](./Plugins-Guide.md): An informal introduction to writing
22
22
  Fastify plugins.
23
+ + [Prototype Poisoning](./Prototype-Poisoning.md): A description of how the
24
+ prototype poisoning attack works and is mitigated.
23
25
  + [Recommendations](./Recommendations.md): Recommendations for how to deploy
24
26
  Fastify into production environments.
25
27
  + [Serverless](./Serverless.md): Details on how to deploy Fastify applications
@@ -0,0 +1,391 @@
1
+ > The following is an article written by Eran Hammer.
2
+ > It is reproduced here for posterity [with permission](https://github.com/fastify/fastify/issues/1426#issuecomment-817957913).
3
+ > It has been reformatted from the original HTML source to Markdown source,
4
+ > but otherwise remains the same. The original HTML can be retrieved from the
5
+ > above permission link.
6
+
7
+ ## A Tale of (prototype) Poisoning
8
+ <a id="pp"></a>
9
+
10
+ This story is a behind-the-scenes look at the process and drama created by a
11
+ particularity interesting web security issue. It is also a perfect illustration
12
+ of the efforts required to maintain popular pieces of open source software and
13
+ the limitations of existing communication channels.
14
+
15
+ But first, if you use a JavaScript framework to process incoming JSON data, take
16
+ a moment to read up on [Prototype
17
+ Poisoning](https://medium.com/intrinsic/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96)
18
+ in general, and the specific [technical
19
+ details](https://github.com/hapijs/hapi/issues/3916) of this issue. I'll explain
20
+ it all in a bit, but since this could be a critical issue, you might want to
21
+ verify your own code first. While this story is focused on a specific framework,
22
+ any solution that uses `JSON.parse()` to process external data is potentially at
23
+ risk.
24
+
25
+ ### BOOM
26
+ <a id="pp-boom"></a>
27
+
28
+ Our story begins with a bang.
29
+
30
+ The engineering team at Lob (long time generous supporters of my work!) reported
31
+ a critical security vulnerability they identified in our data validation
32
+ module — [joi](https://github.com/hapijs/joi). They provided some technical
33
+ details and a proposed solution.
34
+
35
+ The main purpose of a data validation library is to ensure the output fully
36
+ complies with the rules defined. If it doesn't, validation fails. If it passes,
37
+ your can blindly trust that the data you are working with is safe. In fact, most
38
+ developers treat validated input as completely safe from a system integrity
39
+ perspective. This is crucial.
40
+
41
+ In our case, the Lob team provided an example where some data was able to sneak
42
+ by the validation logic and pass through undetected. This is the worst possible
43
+ defect a validation library can have.
44
+
45
+ ### Prototype in a nutshell
46
+ <a id="pp-nutshell"></a>
47
+
48
+ To understand this story, you need to understand how JavaScript works a bit.
49
+ Every object in JavaScript can have a prototype. It is a set of methods and
50
+ properties it "inherits" from another object. I put inherits in quotes because
51
+ JavaScript isn't really an object oriented language.
52
+
53
+ A long time ago, for a bunch of irrelevant reasons, someone decided that it
54
+ would be a good idea to use the special property name `__proto__` to access (and
55
+ set) an object's prototype. This has since been deprecated but nevertheless,
56
+ fully supported.
57
+
58
+ To demonstrate:
59
+
60
+ ```
61
+ > const a = { b: 5 };
62
+ > a.b;
63
+ 5
64
+ > a.__proto__ = { c: 6 };
65
+ > a.c;
66
+ 6
67
+ > a;
68
+ { b: 5 }
69
+ ```
70
+
71
+ As you can see, the object doesn't have a `c` property, but its prototype does.
72
+ When validating the object, the validation library ignores the prototype and
73
+ only validates the object's own properties. This allows `c` to sneak in via the
74
+ prototype.
75
+
76
+ Another important part of this story is the way `JSON.parse()` — a utility
77
+ provided by the language to convert JSON formatted text into objects  —  handles
78
+ this magic `__proto__` property name.
79
+
80
+ ```
81
+ > const text = '{ "b": 5, "__proto__": { "c": 6 } }';
82
+ > const a = JSON.parse(text);
83
+ > a;
84
+ { b: 5, __proto__: { c: 6 } }
85
+ ```
86
+
87
+ Notice how `a` has a `__proto__` property. This is not a prototype reference. It
88
+ is a simple object property key, just like `b`. As we've seen from the first
89
+ example, we can't actually create this key through assignment as that invokes
90
+ the prototype magic and sets an actual prototype. `JSON.parse()` however, sets a
91
+ simple property with that poisonous name.
92
+
93
+ By itself, the object created by `JSON.parse()` is perfectly safe. It doesn't
94
+ have a prototype of its own. It has a seemingly harmless property that just
95
+ happens to overlap with a built-in JavaScript magic name.
96
+
97
+ However, other methods are not as lucky:
98
+
99
+ ```
100
+ > const x = Object.assign({}, a);
101
+ > x;
102
+ { b: 5}
103
+ > x.c;
104
+ 6;
105
+ ```
106
+
107
+ If we take the `a` object created earlier by `JSON.parse()` and pass it to the
108
+ helpful `Object.assign()` method (used to perform a shallow copy of all the top
109
+ level properties of `a` into the provided empty `{}` object), the magic
110
+ `__proto__` property "leaks" and becomes `x` 's actual prototype.
111
+
112
+ Surprise!
113
+
114
+ Put together, if you get some external text input, parse it with `JSON.parse()`
115
+ then perform some simple manipulation of that object (say, shallow clone and add
116
+ an `id` ), and then pass it to our validation library, anything passed through
117
+ via `__proto__` would sneak in undetected.
118
+
119
+ ### Oh joi!
120
+ <a id="pp-oh-joi">
121
+
122
+ The first question is, of course, why does the validation module **joi** ignore
123
+ the prototype and let potentially harmful data through? We asked ourselves the
124
+ same question and our instant thought was "it was an oversight". A bug. A really
125
+ big mistake. The joi module should not have allowed this to happen. But…
126
+
127
+ While joi is used primarily for validating web input data, it also has a
128
+ significant user base using it to validate internal objects, some of which have
129
+ prototypes. The fact that joi ignores the prototype is a helpful "feature". It
130
+ allows validating the object's own properties while ignoring what could be a
131
+ very complicated prototype structure (with many methods and literal properties).
132
+
133
+ Any solution at the joi level would mean breaking some currently working code.
134
+
135
+ ### The right thing
136
+ <a id="pp-right-thing"></a>
137
+
138
+ At this point, we were looking at a devastatingly bad security vulnerability.
139
+ Right up there in the upper echelons of epic security failures. All we knew is
140
+ that our extremely popular data validation library fails to block harmful data,
141
+ and that this data is trivial to sneak through. All you need to do is add
142
+ `__proto__` and some crap to a JSON input and send it on its way to an
143
+ application built using our tools.
144
+
145
+ (Dramatic pause)
146
+
147
+ We knew we had to fix joi to prevent this but given the scale of this issue, we
148
+ had to do it in a way that will put a fix out without drawing too much attention
149
+ to it — without making it too easy to exploit — at least for a few days until
150
+ most systems received the update.
151
+
152
+ Sneaking a fix isn't the hardest thing to accomplish. If you combine it with an
153
+ otherwise purposeless refactor of the code, and throw in a few unrelated bug
154
+ fixes and maybe a cool new feature, you can publish a new version without
155
+ drawing attention to the real issue being fixed.
156
+
157
+ The problem was, the right fix was going to break valid use cases. You see, joi
158
+ has no way of knowing if you want it to ignore the prototype you set, or block
159
+ the prototype set by an attacker. A solution that fixes the exploit will break
160
+ code and breaking code tends to get a lot of attention.
161
+
162
+ On the other hand, if we released a proper ([semantically
163
+ versioned](https://semver.org/)) fix, mark it as a breaking change, and add a
164
+ new API to explicitly tell joi what you want it to do with the prototype, we
165
+ will share with the world how to exploit this vulnerability while also making it
166
+ more time consuming for systems to upgrade (breaking changes never get applied
167
+ automatically by build tools).
168
+
169
+ Lose — Lose.
170
+
171
+ ### A detour
172
+ <a id="pp-detour"></a>
173
+
174
+ While the issue at hand was about incoming request payloads, we had to pause and
175
+ check if it could also impact data coming via the query string, cookies, and
176
+ headers. Basically, anything that gets serialized into objects from text.
177
+
178
+ We quickly confirmed node default query string parser was fine as well as its
179
+ header parser. I identified one potential issue with base64-encoded JSON cookies
180
+ as well as the usage of custom query string parsers. We also wrote some tests to
181
+ confirm that the most popular third-party query string parser  —
182
+ [qs](https://www.npmjs.com/package/qs) —  was not vulnerable (it is not!).
183
+
184
+ ### A development
185
+ <a id="pp-a-development"></a>
186
+
187
+ Throughout this triage, we just assumed that the offending input with its
188
+ poisoned prototype was coming into joi from hapi, the web framework connecting
189
+ the hapi.js ecosystem. Further investigation by the Lob team found that the
190
+ problem was a bit more nuanced.
191
+
192
+ hapi used `JSON.parse()` to process incoming data. It first set the result
193
+ object as a `payload` property of the incoming request, and then passed that
194
+ same object for validation by joi before being passed to the application
195
+ business logic for processing. Since `JSON.parse()` doesn't actually leak the
196
+ `__proto__` property, it would arrive to joi with an invalid key and fail
197
+ validation.
198
+
199
+ However, hapi provides two extension points where the payload data can be
200
+ inspected (and processed) prior to validation. It is all properly documented and
201
+ well understood by most developers. The extension points are there to allow you
202
+ to interact with the raw inputs prior to validation for legitimate (and often
203
+ security related) reasons.
204
+
205
+ If during one of these two extension points, a developer used `Object.assign()`
206
+ or a similar method on the payload, the `__proto__` property would leak and
207
+ become an actual prototype.
208
+
209
+ ### Sigh of relief
210
+ <a id="pp-sigh-of-relief"></a>
211
+
212
+ We were now dealing with a much different level of awfulness. Manipulating the
213
+ payload object prior to validation is not common which meant this was no longer
214
+ a doomsday scenario. It was still potentially catastrophic but the exposure
215
+ dropped from every joi user to some very specific implementations.
216
+
217
+ We were no longer looking at a secretive joi release. The issue in joi is still
218
+ there, but we can now address it properly with a new API and breaking release
219
+ over the next few weeks.
220
+
221
+ We also knew that we can easily mitigate this vulnerability at the framework
222
+ level since it knows which data is coming from the outside and which is
223
+ internally generated. The framework is really the only piece that can protect
224
+ developers against making such unexpected mistakes.
225
+
226
+ ### Good news, bad news, no news?
227
+ <a id="pp-good-news-no-news"></a>
228
+
229
+ The good news was that this wasn't our fault. It wasn't a bug in hapi or joi. It
230
+ was only possible through a complex combination of actions that was not unique
231
+ to hapi or joi. This can happen with every other JavaScript framework. If hapi
232
+ is broken, then the world is broken.
233
+
234
+ Great — we solved the blame game.
235
+
236
+ The bad news is that when there is nothing to blame (other than JavaScript
237
+ itself), it is much harder getting it fixed.
238
+
239
+ The first question people ask once a security issue is found is if there is
240
+ going to be a CVE published. A CVE — Common Vulnerabilities and Exposures — is a
241
+ [database](https://cve.mitre.org/) of known security issues. It is a critical
242
+ component of web security. The benefit of publishing a CVE is that it
243
+ immediately triggers alarms and informs and often breaks automated builds until
244
+ the issue is resolved.
245
+
246
+ But what do we pin this to?
247
+
248
+ Probably, nothing. We are still debating whether we should tag some versions of
249
+ hapi with a warning. The "we" is the node security process. Since we now have a
250
+ new version of hapi that mitigate the problem by default, it can be considered a
251
+ fix. But because the fix isn't to a problem in hapi itself, it is not exactly
252
+ kosher to declare older versions harmful.
253
+
254
+ Publishing an advisory on previous versions of hapi for the sole purpose of
255
+ nudging people into awareness and upgrade is an abuse of the advisory process.
256
+ I'm personally fine with abusing it for the purpose of improving security but
257
+ that's not my call. As of this writing, it is still being debated.
258
+
259
+ ### The solution business
260
+ <a id="pp-solution-business"></a>
261
+
262
+ Mitigating the issue wasn't hard. Making it scale and safe was a bit more
263
+ involved. Since we knew where harmful data can enter the system, and we knew
264
+ where we used the problematic `JSON.parse()` we could replace it with a safe
265
+ implementation.
266
+
267
+ One problem. Validating data can be costly and we are now planning on validating
268
+ every incoming JSON text. The built-in `JSON.parse()` implementation is fast.
269
+ Really really fast. It is unlikely we can build a replacement that will be more
270
+ secure and anywhere as fast. Especially not overnight and without introducing
271
+ new bugs.
272
+
273
+ It was obvious we were going to wrap the existing `JSON.parse()` method with
274
+ some additional logic. We just had to make sure it was not adding too much
275
+ overhead. This isn't just a performance consideration but also a security one.
276
+ If we make it easy to slow down a system by simply sending specific data, we
277
+ make it easy to execute a [DoS
278
+ attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) at very low
279
+ cost.
280
+
281
+ I came up with a stupidly simple solution: first parse the text using the
282
+ existing tools. If this didn't fail, scan the original raw text for the
283
+ offending string "__proto__". Only if we find it, perform an actual scan of the
284
+ object. We can't block every reference to "__proto__" — sometimes it is
285
+ perfectly valid value (like when writing about it here and sending this text
286
+ over to Medium for publication).
287
+
288
+ This made the "happy path" practically as fast as before. It just added one
289
+ function call, a quick text scan (again, very fast built-in implementation), and
290
+ a conditional return. The solution had negligible impact on the vast majority of
291
+ data expected to pass through it.
292
+
293
+ Next problem. The prototype property doesn't have to be at the top level of the
294
+ incoming object. It can be nested deep inside. This means we cannot just check
295
+ for the presence of it at the top level. We need to recursively iterate through
296
+ the object.
297
+
298
+ While recursive functions are a favorite tool, they could be disastrous when
299
+ writing security-conscious code. You see, recursive function increase the size
300
+ of the runtime call stack. The more times you loop, the longer the call stack
301
+ gets. At some point — KABOOM— you reach the maximum length and the process dies.
302
+
303
+ If you cannot guarantee the shape of the incoming data, recursive iteration
304
+ becomes an open threat. An attacker only needs to craft a deep enough object to
305
+ crash your servers.
306
+
307
+ I used a flat loop implementation that is both more memory efficient (less
308
+ function calls, less passing of temporary arguments) and more secure. I am not
309
+ pointing this out to brag, but to highlight how basic engineering practices can
310
+ create (or avoid) security pitfalls.
311
+
312
+ ### Putting it to the test
313
+ <a id="pp-putting-to-test"></a>
314
+
315
+ I sent the code to two people. First to [Nathan
316
+ LaFreniere](https://github.com/nlf) to double check the security properties of
317
+ the solution, and then to [Matteo Collina](https://github.com/mcollina) to
318
+ review the performance. They are among the very best at what they do and often
319
+ my go-to people.
320
+
321
+ The performance benchmarks confirmed that the "happy path" was practically
322
+ unaffected. The interesting findings was that removing the offending values was
323
+ faster then throwing an exception. This raised the question of what should be
324
+ the default behavior of the new module — which I called
325
+ [**bourne**](https://github.com/hapijs/bourne) —  error or sanitize.
326
+
327
+ The concern, again, was exposing the application to a DoS attack. If sending a
328
+ request with `__proto__` makes things 500% slower, that could be an easy vector
329
+ to exploit. But after a bit more testing we confirmed that sending **any**
330
+ invalid JSON text was creating a very similar cost.
331
+
332
+ In other words, if you parse JSON, invalid values are going to cost you more,
333
+ regardless of what makes them invalid. It is also important to remember that
334
+ while the benchmark showed the significant % cost of scanning suspected objects,
335
+ the actual cost in CPU time was still in the fraction of milliseconds. Important
336
+ to note and measure but not actually harmful.
337
+
338
+ ### hapi ever-after
339
+ <a id="pp-hapi-ever-after"></a>
340
+
341
+ There are a bunch of things to be grateful for.
342
+
343
+ The initial disclosure by the Lob team was perfect. It was reported privately,
344
+ to the right people, with the right information. They followed up with
345
+ additional findings, and gave us the time and space to resolve it the right way.
346
+ Lob also was a major sponsor of my work on hapi over the years and that
347
+ financial support is critical to allow everything else to happen. More on that
348
+ in a bit.
349
+
350
+ Triage was stressful but staffed with the right people. Having folks like
351
+ [Nicolas Morel](https://github.com/Marsup), Nathan, and Matteo, available and
352
+ eager to help is critical. This isn't easy to deal with without the pressure,
353
+ but with it, mistakes are likely without proper team collaboration.
354
+
355
+ We got lucky with the actual vulnerability. What started up looking like a
356
+ catastrophic problem, ended up being a delicate but straight-forward problem to
357
+ address.
358
+
359
+ We also got lucky by having full access to mitigate it at the source — didn't
360
+ need to send emails to some unknown framework maintainer and hope for a quick
361
+ answer. hapi's total control over all of its dependencies proved its usefulness
362
+ and security again. Not using [hapi](http://hapijs.com)? [Maybe you
363
+ should](https://hueniverse.com/why-you-should-consider-hapi-6163689bd7c2).
364
+
365
+ ### The after in happy ever-after
366
+ <a id="pp-after-ever-after"></a>
367
+
368
+ This is where I have to take advantage of this incident to reiterate the cost
369
+ and need for sustainable and secure open source.
370
+
371
+ My time alone on this one issue exceeded 20 hours. That's half a working week.
372
+ It came at the end of a month were I already spent over 30 hours publishing a
373
+ new major release of hapi (most of the work was done in December). This puts me
374
+ at a personal financial loss of over $5000 this month (I had to cut back on paid
375
+ client work to make time for it).
376
+
377
+ If you rely on code I maintain, this is exactly the level of support, quality,
378
+ and commitment you want (and lets be honest — expect). Most of you take it for
379
+ granted — not just my work but the work of hundreds of other dedicated open
380
+ source maintainers.
381
+
382
+ Because this work is important, I decided to try and make it not just
383
+ financially sustainable but to grow and expand it. There is so much to improve.
384
+ This is exactly what motivates me to implement the new [commercial licensing
385
+ plan](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-licensing-a-preview-f982662ee898)
386
+ coming in March. You can ready more about it
387
+ [here](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-licensing-a-preview-f982662ee898).
388
+
389
+ Of all the time consuming things, security is at the very top. I hope this story
390
+ successful conveyed not just the technical details, but also the human drama and
391
+ what it takes to keep the web secure.
@@ -255,7 +255,7 @@ server {
255
255
  # group specified above. Note the additional headers that forward
256
256
  # information about the original request. You might want to set
257
257
  # trustProxy to the address of your NGINX server so the X-Forwarded
258
- * fields are used by fastify.
258
+ # fields are used by fastify.
259
259
  location / {
260
260
  # more info: http://nginx.org/en/docs/http/ngx_http_proxy_module.html
261
261
  proxy_http_version 1.1;
@@ -64,7 +64,7 @@ if (require.main === module) {
64
64
 
65
65
  When executed in your lambda function we do not need to listen to a specific
66
66
  port, so we just export the wrapper function `init` in this case. The
67
- [`lambda.js`](https://www.fastify.io/docs/latest/Serverless/#lambda-js) file
67
+ [`lambda.js`](#lambdajs) file
68
68
  will use this export.
69
69
 
70
70
  When you execute your Fastify application like always, i.e. `node app.js` *(the
@@ -93,7 +93,7 @@ exports.handler = proxy;
93
93
  We just require
94
94
  [aws-lambda-fastify](https://github.com/fastify/aws-lambda-fastify) (make sure
95
95
  you install the dependency `npm i --save aws-lambda-fastify`) and our
96
- [`app.js`](https://www.fastify.io/docs/latest/Serverless/#app-js) file and call
96
+ [`app.js`](#appjs) file and call
97
97
  the exported `awsLambdaFastify` function with the `app` as the only parameter.
98
98
  The resulting `proxy` function has the correct signature to be used as a lambda
99
99
  `handler` function. This way all the incoming events (API Gateway requests) are
@@ -111,7 +111,7 @@ found
111
111
  ### Considerations
112
112
 
113
113
  - API Gateway does not support streams yet, so you are not able to handle
114
- [streams](https://www.fastify.io/docs/latest/Reply/#streams).
114
+ [streams](../Reference/Reply.md#streams).
115
115
  - API Gateway has a timeout of 29 seconds, so it is important to provide a reply
116
116
  during this time.
117
117
 
@@ -70,12 +70,12 @@ markdown.
70
70
  **Example**
71
71
 
72
72
  ```
73
- To learn more about hooks, see [Fastify hooks](https://www.fastify.io/docs/latest/Hooks).
73
+ To learn more about hooks, see [Fastify hooks](https://www.fastify.io/docs/latest/Reference/Hooks/).
74
74
  ```
75
75
 
76
76
  Result:
77
77
  >To learn more about hooks, see [Fastify
78
- >hooks](https://www.fastify.io/docs/latest/Hooks/).
78
+ >hooks](https://www.fastify.io/docs/latest/Reference/Hooks/).
79
79
 
80
80
 
81
81
 
@@ -49,7 +49,7 @@ const server = require('./app')({
49
49
 
50
50
  server.listen(3000, (err, address) => {
51
51
  if (err) {
52
- console.log(err)
52
+ server.log.error(err)
53
53
  process.exit(1)
54
54
  }
55
55
  })
@@ -112,7 +112,7 @@ existing content type parsers. In the example below we achieve exactly the same
112
112
  as in the example above except that we do not need to specify each content type
113
113
  to delete. Just like `removeContentTypeParser`, this API supports encapsulation.
114
114
  The API is especially useful if you want to register a [catch-all content type
115
- parser](#Catch-All) that should be executed for every content type and the
115
+ parser](#catch-all) that should be executed for every content type and the
116
116
  built-in parsers should be ignored as well.
117
117
 
118
118
  ```js
@@ -72,7 +72,7 @@ topic.
72
72
  #### `decorate(name, value, [dependencies])`
73
73
  <a id="decorate"></a>
74
74
 
75
- This method is used to customize the Fastify [server](./Reference/Server.md)
75
+ This method is used to customize the Fastify [server](./Server.md)
76
76
  instance.
77
77
 
78
78
  For example, to attach a new method to the server instance:
@@ -100,8 +100,8 @@ fastify.utility()
100
100
  console.log(fastify.conf.db)
101
101
  ```
102
102
 
103
- The decorated [Fastify server](./Reference/Server.md) is bound to `this` in
104
- route [route](Routes.md) handlers:
103
+ The decorated [Fastify server](./Server.md) is bound to `this` in
104
+ route [route](./Routes.md) handlers:
105
105
 
106
106
  ```js
107
107
  fastify.decorate('db', new DbConnection())
@@ -96,7 +96,7 @@ The parser for this content type was already registered.
96
96
  The request body is larger than the provided limit.
97
97
 
98
98
  This setting can be defined in the Fastify server instance:
99
- [`bodyLimit`](./Server.md#bodyLimit)
99
+ [`bodyLimit`](./Server.md#bodylimit)
100
100
 
101
101
  #### FST_ERR_CTP_EMPTY_TYPE
102
102
  <a id="FST_ERR_CTP_EMPTY_TYPE"></a>
@@ -397,12 +397,20 @@ Triggered when `fastify.close()` is invoked to stop the server. It is useful
397
397
  when [plugins](./Plugins.md) need a "shutdown" event, for example, to close an
398
398
  open connection to a database.
399
399
 
400
- The first argument is the Fastify instance, the second one the `done` callback.
400
+ The hook function takes the Fastify instance as a first argument,
401
+ and a `done` callback for synchronous hook functions.
401
402
  ```js
403
+ // callback style
402
404
  fastify.addHook('onClose', (instance, done) => {
403
405
  // Some code
404
406
  done()
405
407
  })
408
+
409
+ // or async/await style
410
+ fastify.addHook('onClose', async (instance) => {
411
+ // Some async code
412
+ await closeDatabaseConnections()
413
+ })
406
414
  ```
407
415
 
408
416
  ### onRoute