Describe the bug
tldr;
- The existence of the
+layout.server.js tree will lead folks to put logic there rather than in +page.server.js.
- Because SvelteKit decides on the client what to fetch from the tree, there are edge cases where important (e.g., authorization) logic in
+layout.server.js is skipped.
- This may seem a contrived edge case, but it is an attack vector that needs to be addressed through documentation.
Consider the following case. (Repo link below)
src
└── routes
└── launch-codes
├── +layout.server.js
├── +page.server.js
└── +page.svelte
Let's say I naively (but I think quite naturally) do the following things:
- I place authentication/authorization logic in the
+layout.server.js file. Perhaps I plan to elaborate this section of the site with launch-codes/[id].
- Meanwhile, I use
+page.server.js to fetch a paged list of codes from the database.
Essentially I have separated the concerns of authorization and data collection.
Now this is totally secure as long as my user remains signed in. But let's say the following happens:
- The user goes to
/launch-codes. This first page view runs the authorization logic in +layout.server.ts.
- They are signed out, say on another tab, or because the cookie expires, or just by deleting the cookie in the console.
- In the original tab, now signed out, they go to
/launch-codes?page=2. The authorization logic in +layout.server.ts is skipped, and the signed out user is shown the launch codes.
I don't think there's a way to reliably fix this in the framework. The client side router decides what to fetch, and that AFAICT will always be manipulable. The only way to "fix" it is by documentation.
(Or we could get rid of the layout data tree notion entirely. Not a bad option, IMO, but a separate losing argument.)
I know all this may seem contrived, but:
- It's not that far-fetched for a developer to assume that separating authorization concerns is partly what
+layout.server.js is for.
- It's not that far-fetched to assume that some apps may require quick cookie expiration. Think your bank.
- It exists. It's an attack vector.
Reproduction
Reproduction here, as minimal as I could make it: https://github.com/cdcarson/yellow-submarine.git
git clone https://github.com/cdcarson/yellow-submarine.git
cd yellow-submarine
npm i
npm run dev
- Go to http://127.0.0.1:5173/launch-codes
- Assuming you are not signed in, you'll be redirected to a sign in page, and redirected back after clicking the button
- Navigate through the paginated list
- In the tab's console, delete the
signedIn cookie. (I.e. the cookie has expired or you've been signed out on another tab.)
- Without refreshing the page, click to another page in the list. You will be shown that page, rather than being redirected to
/sign-in
I made a separate route with a "non-naive" implementation, getting rid of layout.server.js and doing the authorization in +page.server.ts.
- Go to http://127.0.0.1:5173/launch-codes-fixed
- Replicate the steps above. This time, after deleting the cookie, subsequent navigations through the list at
/launch-codes-fixed will be redirected to /sign-in
Logs
No response
System Info
System:
OS: macOS 12.4
CPU: (8) arm64 Apple M1
Memory: 70.06 MB / 8.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
Browsers:
Chrome: 104.0.5112.101
Safari: 15.5
npmPackages:
@sveltejs/adapter-auto: next => 1.0.0-next.66
@sveltejs/kit: next => 1.0.0-next.442
svelte: ^3.44.0 => 3.49.0
vite: ^3.0.4 => 3.0.9
Severity
serious, but I can work around it
Additional Information
No response
Describe the bug
tldr;
+layout.server.jstree will lead folks to put logic there rather than in+page.server.js.+layout.server.jsis skipped.Consider the following case. (Repo link below)
Let's say I naively (but I think quite naturally) do the following things:
+layout.server.jsfile. Perhaps I plan to elaborate this section of the site withlaunch-codes/[id].+page.server.jsto fetch a paged list of codes from the database.Essentially I have separated the concerns of authorization and data collection.
Now this is totally secure as long as my user remains signed in. But let's say the following happens:
/launch-codes. This first page view runs the authorization logic in+layout.server.ts./launch-codes?page=2. The authorization logic in+layout.server.tsis skipped, and the signed out user is shown the launch codes.I don't think there's a way to reliably fix this in the framework. The client side router decides what to fetch, and that AFAICT will always be manipulable. The only way to "fix" it is by documentation.
(Or we could get rid of the layout data tree notion entirely. Not a bad option, IMO, but a separate losing argument.)
I know all this may seem contrived, but:
+layout.server.jsis for.Reproduction
Reproduction here, as minimal as I could make it: https://github.com/cdcarson/yellow-submarine.git
git clone https://github.com/cdcarson/yellow-submarine.git cd yellow-submarine npm i npm run devsignedIncookie. (I.e. the cookie has expired or you've been signed out on another tab.)/sign-inI made a separate route with a "non-naive" implementation, getting rid of
layout.server.jsand doing the authorization in+page.server.ts./launch-codes-fixedwill be redirected to/sign-inLogs
No response
System Info
System: OS: macOS 12.4 CPU: (8) arm64 Apple M1 Memory: 70.06 MB / 8.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm Browsers: Chrome: 104.0.5112.101 Safari: 15.5 npmPackages: @sveltejs/adapter-auto: next => 1.0.0-next.66 @sveltejs/kit: next => 1.0.0-next.442 svelte: ^3.44.0 => 3.49.0 vite: ^3.0.4 => 3.0.9Severity
serious, but I can work around it
Additional Information
No response
This is probably solved by using route-level user land server handle hooks and server-side route resolution to consistently trigger the handle hook.