reactjs / reactjs/react.dev

[Typo]: Suspense example code promoting data leakage when used in Next.js under app router

未關閉
#8,134 5 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

type: typos
主要語言
JavaScript
星號
11.8k
分支
7.9k
平均合併
1 天 11 小時
30 天內合併 PR
11

描述

Summary

The docs on React Suspense include examples that lead to data leakage when used in Next.js. The issue is that the cache map is constructed globally, which will remain across user sessions. Therefore, if any api fetch with user credentials happens, the returned data will leak to other users. This issue occurs both on app router's server and client components. I haven't tested the pages router yet.

Idk if Typo is the right type of issue. Feel free to tag it differently.

Page

https://react.dev/reference/react/Suspense

Details

In your documentation of React Suspense, you clearly state, users should use it in frameworks like Next.js:

Data fetching with Suspense-enabled frameworks like Relay and Next.js

Your example however fetches data like this:

let cache = new Map();

export function fetchData(url) {
  if (!cache.has(url)) {
    cache.set(url, getData(url));
  }
  return cache.get(url);
}

Which is then used like this:

const albums = use(fetchData(`/${artistId}/albums`));

I only tested this on the app router, but the pages router likely has similar issues. When this code is run server side, it will put the fetched data inside the cache and return the cached data in any new request. So, if I add authentication to this API fetch, we will get data leakage. The first user requests the page, data will be cached, and all subsequent fetches will expose the user data.

This also happens if "use client" is used in the app router. Because next will render static html and then hydrate it with React javascript.

In that sense, your example also kind of promotes fetching the api twice under the app router. Because both the server and the client will both fetch and suspend due to the api request.

Steps to reproduce

  • Create a next.js app with app router
    pnpm create next-app@latest my-app --yes
    cd my-app
    pnpm dev
    
  • Copy the example code into a component such as ArtistPage.js, Albums.js, data.js
  • Add a console.log to the getData function.
What happens:

If used blank, ArtistPage and Albums are treated as server components. The client won't fetch data and therefore doesn't console.log. The server will print once and then never again, since it has the data already.

If used under "use client" (add that to the top of ArtistPage.js and Albums.js), the server logging behaviour will stay the same, but the client will also log. (This shows the double fetching behaviour as well)

Why I think this is a big issue

Users looking at your docs usually won't know about all the intricacies of Next.js interacting with Suspense. Most users will just copy paste. I had several conversations with an LLM about this topic and it always assumes at first that the server wouldn't fetch, wouldn't store, wouldn't suspend, etc. This indicates that general human intuition would likely have the same assumptions.

Suggestions to fix

  • Moving the cache into a useRef + context. That would be re-constructed on every render and therefore fix the security issue.
  • Document the double fetching behaviour clearly. Or find a workaround such as moving the api fetch into a useEffect, which wouldn't run on the server.
  • Potentially negotiate something with the Next.js devs directly to make server rendering handle this differently. For example, I think it would make sense that the server html would include only the loading indicators and not fetch the data. But I believe that might be tricky in terms of implementation. Also because the js engine would run the promise trigger function before touching any React or Next.js functions.

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

檢視 https://react.dev/reference/react/Suspense 上的 Suspense 參考頁面,重點關注 fetchData 範例及其全域快取。按照 issue 中的 Next.js app-router 步驟重現該行為,然後更新文件,使快取生命週期以及伺服器/用戶端的 fetching 行為準確無誤,並確保範例不會暗示以不安全的方式處理已驗證資料。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
javascript, next.js, react
領域
documentation, security
Issue 類型
文件
難度
4/5
預估耗時
3-5 天
活躍度
停滯
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。