[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"i-ri:search-line":3,"i-ri:moon-line":8,"i-ri:sun-line":10,"i-ri:menu-3-line":12,"i-ri:close-line":14,"notes-module-items-react":16,"notes-page-react-13-production-readiness\u002F02-auth-and-web-security":494,"i-ri:arrow-left-s-line":1358,"i-ri:menu-2-line":1360,"i-ri:arrow-right-s-line":1362,"i-ep:copy-document":1364},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7m-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938A8 8 0 0 0 4 12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-2a4 4 0 1 0 0-8a4 4 0 0 0 0 8M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636L5.636 7.05zM16.95 18.364l1.414-1.414l2.121 2.121l-1.414 1.414zm2.121-14.85l1.414 1.415l-2.121 2.121l-1.414-1.414zM5.636 16.95l1.414 1.414l-2.121 2.121l-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm6 7h12v2H9zm-6 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"\u002F>",[17,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290,294,298,302,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,462,466,470,474,478,482,486,490],{"path":18,"title":19,"meta":20},"\u002Fnotes\u002Freact\u002F01-basics\u002F01-how-to-read-this-repo","如何阅读本仓库（学习路径与章节依赖）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},"2026-11-05T09:47:15.000Z",{"path":23,"title":24,"meta":25},"\u002Fnotes\u002Freact\u002F01-basics\u002F02-render-vs-commit","React 渲染两阶段：Render vs Commit（总览）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":27,"title":28,"meta":29},"\u002Fnotes\u002Freact\u002F01-basics\u002F03-update-pipeline-birdview","从“更新”到“页面变更”：一次 setState 的全链路鸟瞰",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":31,"title":32,"meta":33},"\u002Fnotes\u002Freact\u002F01-basics","基础入门（建议先读）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":35,"title":36,"meta":37},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F01-browser-multi-process","浏览器多进程架构",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":39,"title":40,"meta":41},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F02-event-loop-overview","事件循环概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":43,"title":44,"meta":45},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F03-call-stack","函数调用栈",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":47,"title":48,"meta":49},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F04-threads","线程介绍",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":51,"title":52,"meta":53},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F05-refresh-rate-and-queues","刷新率与执行队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":55,"title":56,"meta":57},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F06-settimeout","setTimeout 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":59,"title":60,"meta":61},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F07-promise","Promise 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":63,"title":64,"meta":65},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F08-event-loop-in-practice","事件循环机制（综合）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":67,"title":68,"meta":69},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F09-priority-queues","优先级队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":71,"title":72,"meta":73},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F01-concept","并发模式：概念",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":75,"title":76,"meta":77},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F02-demo","案例演示并发模式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":79,"title":80,"meta":81},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F03-high-priority-preemption","高优先级插队",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":83,"title":84,"meta":85},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F04-preemption-vs-interruption","插队的影响、与中断的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":87,"title":88,"meta":89},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F05-shouldYield","中断条件：shouldYield",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":91,"title":92,"meta":93},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F06-react-tasks-and-queues","React 中的任务与队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":95,"title":96,"meta":97},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F07-ensureRootIsScheduled","ensureRootIsScheduled",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":99,"title":100,"meta":101},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F08-batch-updates-merge","合并多个更新触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":103,"title":104,"meta":105},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F09-taskQueue-lifecycle","taskQueue 队列循环的启动与结束",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":107,"title":108,"meta":109},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F10-time-slicing","时间切片是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":111,"title":112,"meta":113},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F11-workLoop-full","workLoop 循环完整逻辑",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":115,"title":116,"meta":117},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F12-priority-design","React 中的优先级设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":119,"title":120,"meta":121},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F13-lane-model","lane 模型",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":123,"title":124,"meta":125},"\u002Fnotes\u002Freact\u002F04-fiber\u002F01-three-node-types","三种节点对象",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":127,"title":128,"meta":129},"\u002Fnotes\u002Freact\u002F04-fiber\u002F02-fiberRootNode","FiberRootNode",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":131,"title":132,"meta":133},"\u002Fnotes\u002Freact\u002F04-fiber\u002F03-fiber-tree","Fiber 树",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":135,"title":136,"meta":137},"\u002Fnotes\u002Freact\u002F04-fiber\u002F04-initial-mount-build","Fiber 树初始构建过程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":139,"title":140,"meta":141},"\u002Fnotes\u002Freact\u002F04-fiber\u002F05-workLoopConcurrent","workLoopConcurrent",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":143,"title":144,"meta":145},"\u002Fnotes\u002Freact\u002F04-fiber\u002F06-stack-and-workInProgress","栈结构 与 workInProgress",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":147,"title":148,"meta":149},"\u002Fnotes\u002Freact\u002F04-fiber\u002F07-executionContext","执行上下文 executionContext",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":151,"title":152,"meta":153},"\u002Fnotes\u002Freact\u002F04-fiber\u002F08-update-lanes","update lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":155,"title":156,"meta":157},"\u002Fnotes\u002Freact\u002F04-fiber\u002F09-render-lanes","render lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":159,"title":160,"meta":161},"\u002Fnotes\u002Freact\u002F04-fiber\u002F10-fiber-lanes","fiber lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":163,"title":164,"meta":165},"\u002Fnotes\u002Freact\u002F04-fiber\u002F11-flags-appendix","附录：flags",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":167,"title":168,"meta":169},"\u002Fnotes\u002Freact\u002F05-hooks\u002F01-background","hook 背景",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":171,"title":172,"meta":173},"\u002Fnotes\u002Freact\u002F05-hooks\u002F02-categories","hook 分类",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":175,"title":176,"meta":177},"\u002Fnotes\u002Freact\u002F05-hooks\u002F03-closures","hook 与闭包",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":179,"title":180,"meta":181},"\u002Fnotes\u002Freact\u002F05-hooks\u002F04-hooks-and-fiber","hook 与 fiber",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":183,"title":184,"meta":185},"\u002Fnotes\u002Freact\u002F05-hooks\u002F05-renderWithHooks","renderWithHooks",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":187,"title":188,"meta":189},"\u002Fnotes\u002Freact\u002F05-hooks\u002F06-init-state-hook","初始化 State Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":191,"title":192,"meta":193},"\u002Fnotes\u002Freact\u002F05-hooks\u002F07-init-effect-hook","初始化 effect Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":195,"title":196,"meta":197},"\u002Fnotes\u002Freact\u002F05-hooks\u002F08-circular-linked-list","环形链表详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":199,"title":200,"meta":201},"\u002Fnotes\u002Freact\u002F05-hooks\u002F09-useReducer-vs-useState","useReducer 与 useState 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":203,"title":204,"meta":205},"\u002Fnotes\u002Freact\u002F05-hooks\u002F10-update-linked-list","update 链表",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":207,"title":208,"meta":209},"\u002Fnotes\u002Freact\u002F05-hooks\u002F11-mount-state-updates","初始阶段的状态更新",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":211,"title":212,"meta":213},"\u002Fnotes\u002Freact\u002F05-hooks\u002F12-baseQueue-vs-pending","baseQueue 与 queue.pending",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":215,"title":216,"meta":217},"\u002Fnotes\u002Freact\u002F05-hooks\u002F13-dispatch-in-update","更新阶段的 dispatch",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":219,"title":220,"meta":221},"\u002Fnotes\u002Freact\u002F05-hooks\u002F14-commitRoot","commitRoot",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":223,"title":224,"meta":225},"\u002Fnotes\u002Freact\u002F06-diff\u002F01-update-overview","React 更新机制概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":227,"title":228,"meta":229},"\u002Fnotes\u002Freact\u002F06-diff\u002F02-diff-strategy","diff 策略",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":231,"title":232,"meta":233},"\u002Fnotes\u002Freact\u002F06-diff\u002F03-node-compare","节点比较方式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":235,"title":236,"meta":237},"\u002Fnotes\u002Freact\u002F06-diff\u002F04-reconcileChildFibers","reconcileChildFibers",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":239,"title":240,"meta":241},"\u002Fnotes\u002Freact\u002F06-diff\u002F05-reconcileSingleElement","reconcileSingleElement",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":243,"title":244,"meta":245},"\u002Fnotes\u002Freact\u002F06-diff\u002F06-reconcileChildrenArray","reconcileChildrenArray",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":247,"title":248,"meta":249},"\u002Fnotes\u002Freact\u002F06-diff\u002F07-why-not-number-key","为什么不建议使用数字作为 key",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":251,"title":252,"meta":253},"\u002Fnotes\u002Freact\u002F07-event-system\u002F01-overview","事件系统概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":255,"title":256,"meta":257},"\u002Fnotes\u002Freact\u002F07-event-system\u002F02-event-plugin","事件插件",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":259,"title":260,"meta":261},"\u002Fnotes\u002Freact\u002F07-event-system\u002F03-event-pooling","事件池",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":263,"title":264,"meta":265},"\u002Fnotes\u002Freact\u002F07-event-system\u002F04-root-listeners","根节点事件绑定",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":267,"title":268,"meta":269},"\u002Fnotes\u002Freact\u002F07-event-system\u002F05-event-dispatch","事件触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":271,"title":272,"meta":273},"\u002Fnotes\u002Freact\u002F08-interview\u002F01-useEffect-vs-useLayoutEffect","useEffect 与 useLayoutEffect 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":275,"title":276,"meta":277},"\u002Fnotes\u002Freact\u002F08-interview\u002F02-why-no-conditional-hooks","为什么 hook 不能写在条件判断里",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":279,"title":280,"meta":281},"\u002Fnotes\u002Freact\u002F08-interview\u002F03-understanding-concurrency","聊聊在 React 中，你对并发模式的理解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":283,"title":284,"meta":285},"\u002Fnotes\u002Freact\u002F08-interview\u002F04-update-mechanism","聊聊 React 的更新机制原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":287,"title":288,"meta":289},"\u002Fnotes\u002Freact\u002F08-interview\u002F05-setState-sync-or-async","setState 是同步还是异步的？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":291,"title":292,"meta":293},"\u002Fnotes\u002Freact\u002F08-interview\u002F06-useState-vs-useReducer","聊聊 useState 与 useReducer 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":295,"title":296,"meta":297},"\u002Fnotes\u002Freact\u002F08-interview\u002F07-closure-trap","聊聊闭包陷阱问题，以及如何解决",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":299,"title":300,"meta":301},"\u002Fnotes\u002Freact\u002F08-interview\u002F08-time-slicing-details","时间分片是如何实现的（任务拆分\u002F中断\u002F恢复）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":303,"title":304,"meta":305},"\u002Fnotes\u002Freact\u002F08-interview\u002F09-batched-updates-useState","聊聊 useState 的批处理更新机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":307,"title":308,"meta":309},"\u002Fnotes\u002Freact\u002F08-interview\u002F10-jsx-to-dom","JSX 是如何转变成为真实 DOM 的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":311,"title":312,"meta":313},"\u002Fnotes\u002Freact\u002F08-interview\u002F11-useCallback-impl","useCallback 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":315,"title":316,"meta":317},"\u002Fnotes\u002Freact\u002F08-interview\u002F12-scheduling-mechanism","详细聊聊 React 的调度机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":319,"title":320,"meta":321},"\u002Fnotes\u002Freact\u002F08-interview\u002F13-priority-and-lanes","聊聊 React 的优先级机制（Lane 模型）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":323,"title":324,"meta":325},"\u002Fnotes\u002Freact\u002F08-interview\u002F14-diff-algorithm","React 的 Diff 算法是什么样的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":327,"title":328,"meta":329},"\u002Fnotes\u002Freact\u002F08-interview\u002F15-event-system","详细聊聊 React 的事件系统是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":331,"title":332,"meta":333},"\u002Fnotes\u002Freact\u002F08-interview\u002F16-portals-bubbling","React Portals 上的事件是否会冒泡到父组件，原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":335,"title":336,"meta":337},"\u002Fnotes\u002Freact\u002F08-interview\u002F17-useEffect-impl","useEffect 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":339,"title":340,"meta":341},"\u002Fnotes\u002Freact\u002F08-interview\u002F18-useContext-impl","请聊聊 useContext 的实现原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":343,"title":344,"meta":345},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F01-automatic-batching-and-flushsync","React 18 自动批处理（Automatic Batching）与 flushSync",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":347,"title":348,"meta":349},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects","React StrictMode：为什么会“双调用”？（源码\u002F机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":351,"title":352,"meta":353},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F03-transition-useTransition-useDeferredValue","Transition：startTransition \u002F useTransition \u002F useDeferredValue（机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":355,"title":356,"meta":357},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F04-suspense-loading-boundary-design","Suspense：加载态边界如何设计（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":359,"title":360,"meta":361},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery","Error Boundary：兜底、重试与上报（自研 vs Sentry）（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":363,"title":364,"meta":365},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice","React 18 实战（并发特性与默认行为）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":367,"title":368,"meta":369},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F01-routing-and-url-state-mental-model","路由与 URL State：统一心智模型（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":371,"title":372,"meta":373},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F02-tanstack-router-route-tree-search-loader-prefetch","TanStack Router（Vite \u002F SPA）：Route Tree \u002F Search \u002F Loader \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":375,"title":376,"meta":377},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F03-next-app-router-segments-layout-loading-error-not-found-prefetch","Next.js App Router：Segments \u002F Layouts \u002F Loading-Error-NotFound \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":379,"title":380,"meta":381},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation","路由与导航（TanStack Router \u002F Next App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":383,"title":384,"meta":385},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F01-state-layering-ui-server-url-global","状态分层：UI \u002F Server \u002F URL \u002F Global（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":387,"title":388,"meta":389},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F02-tanstack-query-caching-and-invalidation","TanStack Query：缓存模型与失效策略（Caching & Invalidation）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":391,"title":392,"meta":393},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F03-optimistic-updates-and-consistency","TanStack Query：乐观更新与一致性（Optimistic Updates & Consistency）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":395,"title":396,"meta":397},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F04-form-architecture-react-hook-form-validation-performance-testability","表单架构：React Hook Form 的受控\u002F非受控、校验、性能与可测试性（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":399,"title":400,"meta":401},"\u002Fnotes\u002Freact\u002F11-data-layer","数据层（Server State \u002F 表单 \u002F 状态分层）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":403,"title":404,"meta":405},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-hydration-mismatch","Hydration mismatch（React \u002F Next.js）：成因、检测、排查清单与工程化规避",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":407,"title":408,"meta":409},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-nextjs-cache-revalidate-consistency-online-not-updating","Next.js 缓存\u002F重验证与一致性：避免「线上怎么不更新」事故（App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":411,"title":412,"meta":413},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F02-csr-ssr-ssg-isr-how-to-choose","CSR vs SSR vs SSG vs ISR：怎么选？边界是什么？（体验 + 成本 + 一致性）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":415,"title":416,"meta":417},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense","Streaming SSR + Suspense：提升前端感知性能的利器",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":419,"title":420,"meta":421},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery","渲染与交付（CSR\u002FSSR\u002FStreaming\u002FHydration\u002F缓存）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":423,"title":424,"meta":425},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F01-observability-logging-metrics-tracing","前端可观测性体系：日志、指标与链路追踪",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":427,"title":428,"meta":429},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F02-auth-and-web-security","鉴权与 Web 安全：OAuth, JWT, XSS, CSRF, CSP",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":431,"title":432,"meta":433},"\u002Fnotes\u002Freact\u002F13-production-readiness","生产可用性（错误\u002F可观测\u002F鉴权\u002F安全）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":435,"title":436,"meta":437},"\u002Fnotes\u002Freact\u002F14-performance\u002F01-performance-playbook-and-metrics","前端性能定位 Playbook：从指标到归因",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":439,"title":440,"meta":441},"\u002Fnotes\u002Freact\u002F14-performance\u002F02-rendering-optimization-memo-context-virtualization","React 渲染性能优化：Memo, Context, 与虚拟化",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":443,"title":444,"meta":445},"\u002Fnotes\u002Freact\u002F14-performance\u002F03-asset-and-bundle-optimization","资源与 Bundle 优化：代码分割、图片与 CDN",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":447,"title":448,"meta":449},"\u002Fnotes\u002Freact\u002F14-performance","性能体系（定位 → 优化 → 度量）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":451,"title":452,"meta":453},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F01-component-system-and-design-system","组件体系与设计系统：构建规模化前端的基石",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":455,"title":456,"meta":457},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F02-testing-strategy-rtl-e2e-testability","前端测试体系：RTL, E2E 与可测性设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":459,"title":460,"meta":461},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F03-monorepo-and-dependency-management","Monorepo 与依赖治理：pnpm 和 Turborepo",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":463,"title":464,"meta":465},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F04-cicd-and-quality-gates","CI\u002FCD 与质量门禁：构建可靠的自动化流程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":467,"title":468,"meta":469},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F05-bff-and-api-design","BFF 与 API 设计：前端架构师的视角",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":471,"title":472,"meta":473},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture","工程与架构治理（规模化）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":475,"title":476,"meta":477},"\u002Fnotes\u002Freact\u002F16-advanced\u002F01-rsc-and-server-actions-deep-dive","RSC\u002FServer Actions 深水区：边界、约束与缓存一致性",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":479,"title":480,"meta":481},"\u002Fnotes\u002Freact\u002F16-advanced\u002F02-micro-frontend-governance","微前端治理：样式、路由与通信",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":483,"title":484,"meta":485},"\u002Fnotes\u002Freact\u002F16-advanced\u002F03-realtime-and-offline","实时与离线：WebSocket, PWA 与 Service Worker",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":487,"title":488,"meta":489},"\u002Fnotes\u002Freact\u002F16-advanced\u002F04-a11y-i18n-compliance","a11y, i18n 与合规：构建负责任的全球化应用",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":491,"title":492,"meta":493},"\u002Fnotes\u002Freact\u002F16-advanced","进阶专题（按业务需要选做）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"id":495,"type":496,"sourcePath":497,"routePath":427,"path":427,"title":428,"updatedAt":21,"meta":498,"body":500,"toc":1345},"bm90ZTpub3Rlcy9yZWFjdC8xMy1wcm9kdWN0aW9uLXJlYWRpbmVzcy8wMi1hdXRoLWFuZC13ZWItc2VjdXJpdHkubWQ","note","notes\u002Freact\u002F13-production-readiness\u002F02-auth-and-web-security.md",{"id":495,"type":496,"sourcePath":497,"slug":499,"title":428,"updatedAt":21,"lastUpdated":21},"react\u002F13-production-readiness\u002F02-auth-and-web-security",{"type":501,"children":502},"root",[503,511,527,531,538,543,568,587,590,596,601,608,613,627,693,710,716,885,888,894,900,910,919,970,976,985,993,1075,1081,1086,1096,1105,1214,1223,1252,1255,1261,1339],{"type":504,"tag":505,"props":506,"children":508},"element","h1",{"id":507},"鉴权与-web-安全oauth-jwt-xss-csrf-csp",[509],{"type":510,"value":428},"text",{"type":504,"tag":512,"props":513,"children":514},"blockquote",{},[515],{"type":504,"tag":516,"props":517,"children":518},"p",{},[519,525],{"type":504,"tag":520,"props":521,"children":522},"strong",{},[523],{"type":510,"value":524},"一句话结论",{"type":510,"value":526},"：采用基于 Token 的标准鉴权流程 (如 OAuth 2.0 + JWT) 保护用户身份，并实施一套由 CSP (内容安全策略)、HttpOnly Cookies 和其他最佳实践构成的纵深防御体系，是保护现代 Web 应用免受 XSS、CSRF 等主流攻击的基石。",{"type":504,"tag":528,"props":529,"children":530},"hr",{},[],{"type":504,"tag":532,"props":533,"children":535},"h2",{"id":534},"_1-鉴权-authentication-vs-授权-authorization",[536],{"type":510,"value":537},"1. 鉴权 (Authentication) vs 授权 (Authorization)",{"type":504,"tag":516,"props":539,"children":540},{},[541],{"type":510,"value":542},"在进入技术细节前，必须先厘清这两个概念：",{"type":504,"tag":544,"props":545,"children":546},"ul",{},[547,558],{"type":504,"tag":548,"props":549,"children":550},"li",{},[551,556],{"type":504,"tag":520,"props":552,"children":553},{},[554],{"type":510,"value":555},"鉴权 (Authentication)",{"type":510,"value":557},"：你是谁？(Who are you?) —— 验证用户身份的过程，通常通过用户名密码、社交登录等方式。",{"type":504,"tag":548,"props":559,"children":560},{},[561,566],{"type":504,"tag":520,"props":562,"children":563},{},[564],{"type":510,"value":565},"授权 (Authorization)",{"type":510,"value":567},"：你有什么权限？(What are you allowed to do?) —— 验证用户是否有权访问特定资源或执行特定操作的过程。",{"type":504,"tag":516,"props":569,"children":570},{},[571,573,578,580,585],{"type":510,"value":572},"本文重点讨论前端相关的",{"type":504,"tag":520,"props":574,"children":575},{},[576],{"type":510,"value":577},"鉴权",{"type":510,"value":579},"机制和通用的 ",{"type":504,"tag":520,"props":581,"children":582},{},[583],{"type":510,"value":584},"Web 安全",{"type":510,"value":586},"防护。",{"type":504,"tag":528,"props":588,"children":589},{},[],{"type":504,"tag":532,"props":591,"children":593},{"id":592},"_2-基于-token-的鉴权oauth-20-与-jwt",[594],{"type":510,"value":595},"2. 基于 Token 的鉴权：OAuth 2.0 与 JWT",{"type":504,"tag":516,"props":597,"children":598},{},[599],{"type":510,"value":600},"传统的 Session-Cookie 机制在分布式、跨域的现代应用中面临挑战。基于 Token 的无状态 (stateless) 鉴权是目前的主流方案。",{"type":504,"tag":602,"props":603,"children":605},"h3",{"id":604},"a-jwt-json-web-token",[606],{"type":510,"value":607},"A. JWT (JSON Web Token)",{"type":504,"tag":516,"props":609,"children":610},{},[611],{"type":510,"value":612},"JWT 是一个开放标准 (RFC 7519)，它定义了一种紧凑且自包含的方式，用于在各方之间安全地传输信息（称为 claims）。",{"type":504,"tag":516,"props":614,"children":615},{},[616,618,625],{"type":510,"value":617},"一个 JWT 由三部分组成，由 ",{"type":504,"tag":619,"props":620,"children":622},"code",{"className":621},[],[623],{"type":510,"value":624},".",{"type":510,"value":626}," 分隔：",{"type":504,"tag":628,"props":629,"children":630},"ol",{},[631,641,675],{"type":504,"tag":548,"props":632,"children":633},{},[634,639],{"type":504,"tag":520,"props":635,"children":636},{},[637],{"type":510,"value":638},"Header (头部)",{"type":510,"value":640},"：包含 token 类型和使用的签名算法 (如 HMAC SHA256 或 RSA)。",{"type":504,"tag":548,"props":642,"children":643},{},[644,649,651,657,659,665,667,673],{"type":504,"tag":520,"props":645,"children":646},{},[647],{"type":510,"value":648},"Payload (载荷)",{"type":510,"value":650},"：包含 claims。这是关于实体（通常是用户）和其他数据的声明。常见的 claims 有 ",{"type":504,"tag":619,"props":652,"children":654},{"className":653},[],[655],{"type":510,"value":656},"sub",{"type":510,"value":658}," (主题, 即用户ID)、",{"type":504,"tag":619,"props":660,"children":662},{"className":661},[],[663],{"type":510,"value":664},"exp",{"type":510,"value":666}," (过期时间)、",{"type":504,"tag":619,"props":668,"children":670},{"className":669},[],[671],{"type":510,"value":672},"iat",{"type":510,"value":674}," (签发时间)。",{"type":504,"tag":548,"props":676,"children":677},{},[678,683,685,691],{"type":504,"tag":520,"props":679,"children":680},{},[681],{"type":510,"value":682},"Signature (签名)",{"type":510,"value":684},"：用于验证消息在传递过程中没有被篡改。计算方式是：",{"type":504,"tag":619,"props":686,"children":688},{"className":687},[],[689],{"type":510,"value":690},"HMACSHA256(base64UrlEncode(header) + \".\" + base64UrlEncode(payload), secret)",{"type":510,"value":692},"。",{"type":504,"tag":516,"props":694,"children":695},{},[696,701,703,708],{"type":504,"tag":520,"props":697,"children":698},{},[699],{"type":510,"value":700},"核心优势",{"type":510,"value":702},"：",{"type":504,"tag":520,"props":704,"children":705},{},[706],{"type":510,"value":707},"自包含",{"type":510,"value":709},"。服务器无需查询数据库或缓存，仅通过验证签名就能确认 token 的有效性和用户的身份。",{"type":504,"tag":602,"props":711,"children":713},{"id":712},"b-鉴权流程-oauth-20-implicit-or-auth-code-flow",[714],{"type":510,"value":715},"B. 鉴权流程 (OAuth 2.0 \"Implicit\" or \"Auth Code\" Flow)",{"type":504,"tag":628,"props":717,"children":718},{},[719,729,739,784,837,867],{"type":504,"tag":548,"props":720,"children":721},{},[722,727],{"type":504,"tag":520,"props":723,"children":724},{},[725],{"type":510,"value":726},"用户登录",{"type":510,"value":728},"：用户在前端页面提交凭据（用户名\u002F密码）或通过第三方登录 (Google\u002FGitHub)。",{"type":504,"tag":548,"props":730,"children":731},{},[732,737],{"type":504,"tag":520,"props":733,"children":734},{},[735],{"type":510,"value":736},"服务器验证",{"type":510,"value":738},"：服务器验证用户凭据。",{"type":504,"tag":548,"props":740,"children":741},{},[742,747,749,754,756,761,763],{"type":504,"tag":520,"props":743,"children":744},{},[745],{"type":510,"value":746},"签发 Token",{"type":510,"value":748},"：验证成功后，服务器生成一个 ",{"type":504,"tag":520,"props":750,"children":751},{},[752],{"type":510,"value":753},"Access Token",{"type":510,"value":755}," (通常是 JWT) 和一个 ",{"type":504,"tag":520,"props":757,"children":758},{},[759],{"type":510,"value":760},"Refresh Token",{"type":510,"value":762},"。\n",{"type":504,"tag":544,"props":764,"children":765},{},[766,775],{"type":504,"tag":548,"props":767,"children":768},{},[769,773],{"type":504,"tag":520,"props":770,"children":771},{},[772],{"type":510,"value":753},{"type":510,"value":774},"：生命周期短（如 15 分钟），用于访问受保护的 API 资源。",{"type":504,"tag":548,"props":776,"children":777},{},[778,782],{"type":504,"tag":520,"props":779,"children":780},{},[781],{"type":510,"value":760},{"type":510,"value":783},"：生命周期长（如 7 天），用于在 Access Token 过期后，无感地获取一个新的 Access Token。",{"type":504,"tag":548,"props":785,"children":786},{},[787,792,794],{"type":504,"tag":520,"props":788,"children":789},{},[790],{"type":510,"value":791},"Token 存储 (前端)",{"type":510,"value":793},"：\n",{"type":504,"tag":544,"props":795,"children":796},{},[797,813],{"type":504,"tag":548,"props":798,"children":799},{},[800,804,806,811],{"type":504,"tag":520,"props":801,"children":802},{},[803],{"type":510,"value":753},{"type":510,"value":805},": 存储在",{"type":504,"tag":520,"props":807,"children":808},{},[809],{"type":510,"value":810},"内存",{"type":510,"value":812},"中（例如，React Context 或 Zustand\u002FRedux store）。这是最安全的方式，因为它不会被 XSS 攻击轻易窃取。",{"type":504,"tag":548,"props":814,"children":815},{},[816,820,822,827,829,835],{"type":504,"tag":520,"props":817,"children":818},{},[819],{"type":510,"value":760},{"type":510,"value":821},": 存储在 ",{"type":504,"tag":520,"props":823,"children":824},{},[825],{"type":510,"value":826},"HttpOnly Cookie",{"type":510,"value":828}," 中。",{"type":504,"tag":619,"props":830,"children":832},{"className":831},[],[833],{"type":510,"value":834},"HttpOnly",{"type":510,"value":836}," 标志使该 Cookie 无法通过 JavaScript 访问，从而有效防御 XSS 攻击。",{"type":504,"tag":548,"props":838,"children":839},{},[840,845,847,853,855],{"type":504,"tag":520,"props":841,"children":842},{},[843],{"type":510,"value":844},"API 请求",{"type":510,"value":846},"：前端在发起受保护的 API 请求时，将 Access Token 附加在 ",{"type":504,"tag":619,"props":848,"children":850},{"className":849},[],[851],{"type":510,"value":852},"Authorization",{"type":510,"value":854}," 请求头中。\n",{"type":504,"tag":856,"props":857,"children":861},"pre",{"className":858,"code":860,"language":510},[859],"language-text","Authorization: Bearer \u003Caccess_token>\n",[862],{"type":504,"tag":619,"props":863,"children":865},{"__ignoreMap":864},"",[866],{"type":510,"value":860},{"type":504,"tag":548,"props":868,"children":869},{},[870,875,877,883],{"type":504,"tag":520,"props":871,"children":872},{},[873],{"type":510,"value":874},"Token 刷新",{"type":510,"value":876},"：当 API 返回 401 Unauthorized 错误时，前端的请求拦截器会自动触发一个到特定刷新端点 (",{"type":504,"tag":619,"props":878,"children":880},{"className":879},[],[881],{"type":510,"value":882},"\u002Frefresh_token",{"type":510,"value":884},") 的请求。这个请求会携带 HttpOnly Cookie 中的 Refresh Token。服务器验证 Refresh Token 后，返回一个新的 Access Token，前端更新内存中的 Access Token 并重发失败的请求。",{"type":504,"tag":528,"props":886,"children":887},{},[],{"type":504,"tag":532,"props":889,"children":891},{"id":890},"_3-常见-web-攻击与防御",[892],{"type":510,"value":893},"3. 常见 Web 攻击与防御",{"type":504,"tag":602,"props":895,"children":897},{"id":896},"a-xss-cross-site-scripting",[898],{"type":510,"value":899},"A. XSS (Cross-Site Scripting)",{"type":504,"tag":516,"props":901,"children":902},{},[903,908],{"type":504,"tag":520,"props":904,"children":905},{},[906],{"type":510,"value":907},"攻击原理",{"type":510,"value":909},"：攻击者向你的网站注入恶意脚本，当其他用户浏览该页面时，这些脚本会在用户的浏览器中执行，从而窃取用户信息（如 LocalStorage 中的 token）、操作用户行为等。",{"type":504,"tag":516,"props":911,"children":912},{},[913,918],{"type":504,"tag":520,"props":914,"children":915},{},[916],{"type":510,"value":917},"防御策略",{"type":510,"value":702},{"type":504,"tag":628,"props":920,"children":921},{},[922,932,950,960],{"type":504,"tag":548,"props":923,"children":924},{},[925,930],{"type":504,"tag":520,"props":926,"children":927},{},[928],{"type":510,"value":929},"永远不要相信用户输入",{"type":510,"value":931},"：对所有用户生成的内容 (UGC) 进行严格的转义 (HTML escaping) 或过滤。",{"type":504,"tag":548,"props":933,"children":934},{},[935,940,942,948],{"type":504,"tag":520,"props":936,"children":937},{},[938],{"type":510,"value":939},"框架内置防御",{"type":510,"value":941},"：现代前端框架（如 React）默认会对 JSX 中的内容进行转义，能有效防御大部分 XSS。",{"type":504,"tag":619,"props":943,"children":945},{"className":944},[],[946],{"type":510,"value":947},"dangerouslySetInnerHTML",{"type":510,"value":949}," 是一个危险信号，必须确保其内容是可信的。",{"type":504,"tag":548,"props":951,"children":952},{},[953,958],{"type":504,"tag":520,"props":954,"children":955},{},[956],{"type":510,"value":957},"HttpOnly Cookies",{"type":510,"value":959},"：如上所述，将敏感的 Refresh Token 存储在 HttpOnly Cookie 中，即使发生 XSS，攻击者也无法通过 JS 读取它。",{"type":504,"tag":548,"props":961,"children":962},{},[963,968],{"type":504,"tag":520,"props":964,"children":965},{},[966],{"type":510,"value":967},"内容安全策略 (CSP)",{"type":510,"value":969},"：终极防御。见下文。",{"type":504,"tag":602,"props":971,"children":973},{"id":972},"b-csrf-cross-site-request-forgery",[974],{"type":510,"value":975},"B. CSRF (Cross-Site Request Forgery)",{"type":504,"tag":516,"props":977,"children":978},{},[979,983],{"type":504,"tag":520,"props":980,"children":981},{},[982],{"type":510,"value":907},{"type":510,"value":984},"：攻击者诱导已登录的用户访问一个恶意网站，该网站向你的应用发送一个伪造的请求（例如，转账、修改密码）。由于用户的浏览器会自动携带你的应用的 Cookie，这个请求会被服务器视为合法请求。",{"type":504,"tag":516,"props":986,"children":987},{},[988,992],{"type":504,"tag":520,"props":989,"children":990},{},[991],{"type":510,"value":917},{"type":510,"value":702},{"type":504,"tag":628,"props":994,"children":995},{},[996,1047],{"type":504,"tag":548,"props":997,"children":998},{},[999,1004,1006,1012,1014],{"type":504,"tag":520,"props":1000,"children":1001},{},[1002],{"type":510,"value":1003},"SameSite Cookies",{"type":510,"value":1005},"：为你的 Cookies 设置 ",{"type":504,"tag":619,"props":1007,"children":1009},{"className":1008},[],[1010],{"type":510,"value":1011},"SameSite",{"type":510,"value":1013}," 属性。\n",{"type":504,"tag":544,"props":1015,"children":1016},{},[1017,1028],{"type":504,"tag":548,"props":1018,"children":1019},{},[1020,1026],{"type":504,"tag":619,"props":1021,"children":1023},{"className":1022},[],[1024],{"type":510,"value":1025},"SameSite=Strict",{"type":510,"value":1027},"：完全禁止第三方网站携带该 Cookie 发起请求。最安全，但可能影响某些跨站链接体验。",{"type":504,"tag":548,"props":1029,"children":1030},{},[1031,1037,1039,1045],{"type":504,"tag":619,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":510,"value":1036},"SameSite=Lax",{"type":510,"value":1038},"：允许用户通过常规导航（如点击链接）从外部站点进入你的网站时携带 Cookie，但禁止在 ",{"type":504,"tag":619,"props":1040,"children":1042},{"className":1041},[],[1043],{"type":510,"value":1044},"POST",{"type":510,"value":1046}," 等“危险”请求中携带。这是目前大多数浏览器的默认值，能防御大部分 CSRF。",{"type":504,"tag":548,"props":1048,"children":1049},{},[1050,1055,1057],{"type":504,"tag":520,"props":1051,"children":1052},{},[1053],{"type":510,"value":1054},"Anti-CSRF Tokens",{"type":510,"value":1056}," (也称 Synchronizer Token Pattern)：\n",{"type":504,"tag":544,"props":1058,"children":1059},{},[1060,1065,1070],{"type":504,"tag":548,"props":1061,"children":1062},{},[1063],{"type":510,"value":1064},"服务器在渲染表单或页面时，生成一个随机的、一次性的 token，并将其嵌入页面和用户的 Session\u002FCookie 中。",{"type":504,"tag":548,"props":1066,"children":1067},{},[1068],{"type":510,"value":1069},"当用户提交表单时，前端必须将这个 token 作为请求参数或请求头一并发送。",{"type":504,"tag":548,"props":1071,"children":1072},{},[1073],{"type":510,"value":1074},"服务器在处理请求时，会比较请求中的 token 和 Session\u002FCookie 中的 token 是否匹配。由于攻击者无法获取这个随机 token，伪造的请求就会失败。",{"type":504,"tag":602,"props":1076,"children":1078},{"id":1077},"c-内容安全策略-csp-content-security-policy",[1079],{"type":510,"value":1080},"C. 内容安全策略 (CSP - Content Security Policy)",{"type":504,"tag":516,"props":1082,"children":1083},{},[1084],{"type":510,"value":1085},"CSP 是一个强大的 HTTP 响应头，它允许你定义一个“白名单”，声明哪些来源的资源（脚本、样式、图片、字体等）是可信的，从而可以被浏览器加载和执行。",{"type":504,"tag":516,"props":1087,"children":1088},{},[1089,1094],{"type":504,"tag":520,"props":1090,"children":1091},{},[1092],{"type":510,"value":1093},"核心作用",{"type":510,"value":1095},"：即使 XSS 攻击成功注入了恶意脚本，由于该脚本的来源不在白名单内，浏览器也会拒绝执行它，从而提供了最后一道坚固的防线。",{"type":504,"tag":516,"props":1097,"children":1098},{},[1099,1104],{"type":504,"tag":520,"props":1100,"children":1101},{},[1102],{"type":510,"value":1103},"示例 CSP 头",{"type":510,"value":702},{"type":504,"tag":856,"props":1106,"children":1110},{"className":1107,"code":1108,"language":1109,"meta":864,"style":864},"language-http shiki shiki-themes github-light github-dark","Content-Security-Policy:\n  default-src 'self'; \u002F* 默认只信任同源资源 *\u002F\n  script-src 'self' https:\u002F\u002Fapis.google.com; \u002F* 脚本只信任同源和 googleapis.com *\u002F\n  style-src 'self' 'unsafe-inline'; \u002F* 样式信任同源和内联样式 *\u002F\n  img-src 'self' https:\u002F\u002F*.my-cdn.com; \u002F* 图片信任同源和 my-cdn.com 的所有子域名 *\u002F\n  connect-src 'self' https:\u002F\u002Fapi.my-app.com; \u002F* API 请求只信任同源和 api.my-app.com *\u002F\n  frame-ancestors 'none'; \u002F* 禁止页面被嵌入到 iframe 中，防御 Clickjacking *\u002F\n  form-action 'self'; \u002F* 表单提交只允许到同源 *\u002F\n  base-uri 'self';\n  object-src 'none'; \u002F* 禁止加载 \u003Cobject>, \u003Cembed>, \u003Capplet> *\u002F\n","http",[1111],{"type":504,"tag":619,"props":1112,"children":1113},{"__ignoreMap":864},[1114,1132,1142,1151,1160,1169,1178,1187,1196,1205],{"type":504,"tag":1115,"props":1116,"children":1119},"span",{"class":1117,"line":1118},"line",1,[1120,1126],{"type":504,"tag":1115,"props":1121,"children":1123},{"style":1122},"--shiki-default:#22863A;--shiki-dark:#85E89D",[1124],{"type":510,"value":1125},"Content-Security-Policy",{"type":504,"tag":1115,"props":1127,"children":1129},{"style":1128},"--shiki-default:#D73A49;--shiki-dark:#F97583",[1130],{"type":510,"value":1131},":\n",{"type":504,"tag":1115,"props":1133,"children":1135},{"class":1117,"line":1134},2,[1136],{"type":504,"tag":1115,"props":1137,"children":1139},{"style":1138},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[1140],{"type":510,"value":1141},"  default-src 'self'; \u002F* 默认只信任同源资源 *\u002F\n",{"type":504,"tag":1115,"props":1143,"children":1145},{"class":1117,"line":1144},3,[1146],{"type":504,"tag":1115,"props":1147,"children":1148},{"style":1138},[1149],{"type":510,"value":1150},"  script-src 'self' https:\u002F\u002Fapis.google.com; \u002F* 脚本只信任同源和 googleapis.com *\u002F\n",{"type":504,"tag":1115,"props":1152,"children":1154},{"class":1117,"line":1153},4,[1155],{"type":504,"tag":1115,"props":1156,"children":1157},{"style":1138},[1158],{"type":510,"value":1159},"  style-src 'self' 'unsafe-inline'; \u002F* 样式信任同源和内联样式 *\u002F\n",{"type":504,"tag":1115,"props":1161,"children":1163},{"class":1117,"line":1162},5,[1164],{"type":504,"tag":1115,"props":1165,"children":1166},{"style":1138},[1167],{"type":510,"value":1168},"  img-src 'self' https:\u002F\u002F*.my-cdn.com; \u002F* 图片信任同源和 my-cdn.com 的所有子域名 *\u002F\n",{"type":504,"tag":1115,"props":1170,"children":1172},{"class":1117,"line":1171},6,[1173],{"type":504,"tag":1115,"props":1174,"children":1175},{"style":1138},[1176],{"type":510,"value":1177},"  connect-src 'self' https:\u002F\u002Fapi.my-app.com; \u002F* API 请求只信任同源和 api.my-app.com *\u002F\n",{"type":504,"tag":1115,"props":1179,"children":1181},{"class":1117,"line":1180},7,[1182],{"type":504,"tag":1115,"props":1183,"children":1184},{"style":1138},[1185],{"type":510,"value":1186},"  frame-ancestors 'none'; \u002F* 禁止页面被嵌入到 iframe 中，防御 Clickjacking *\u002F\n",{"type":504,"tag":1115,"props":1188,"children":1190},{"class":1117,"line":1189},8,[1191],{"type":504,"tag":1115,"props":1192,"children":1193},{"style":1138},[1194],{"type":510,"value":1195},"  form-action 'self'; \u002F* 表单提交只允许到同源 *\u002F\n",{"type":504,"tag":1115,"props":1197,"children":1199},{"class":1117,"line":1198},9,[1200],{"type":504,"tag":1115,"props":1201,"children":1202},{"style":1138},[1203],{"type":510,"value":1204},"  base-uri 'self';\n",{"type":504,"tag":1115,"props":1206,"children":1208},{"class":1117,"line":1207},10,[1209],{"type":504,"tag":1115,"props":1210,"children":1211},{"style":1138},[1212],{"type":510,"value":1213},"  object-src 'none'; \u002F* 禁止加载 \u003Cobject>, \u003Cembed>, \u003Capplet> *\u002F\n",{"type":504,"tag":516,"props":1215,"children":1216},{},[1217,1222],{"type":504,"tag":520,"props":1218,"children":1219},{},[1220],{"type":510,"value":1221},"实施建议",{"type":510,"value":702},{"type":504,"tag":544,"props":1224,"children":1225},{},[1226,1239],{"type":504,"tag":548,"props":1227,"children":1228},{},[1229,1231,1237],{"type":510,"value":1230},"从一个严格的策略开始 (",{"type":504,"tag":619,"props":1232,"children":1234},{"className":1233},[],[1235],{"type":510,"value":1236},"default-src 'none'",{"type":510,"value":1238},")，然后逐步放开必要的来源。",{"type":504,"tag":548,"props":1240,"children":1241},{},[1242,1244,1250],{"type":510,"value":1243},"使用 ",{"type":504,"tag":619,"props":1245,"children":1247},{"className":1246},[],[1248],{"type":510,"value":1249},"Content-Security-Policy-Report-Only",{"type":510,"value":1251}," 头在部署前进行测试，它会报告违规行为但不会实际阻止。",{"type":504,"tag":528,"props":1253,"children":1254},{},[],{"type":504,"tag":532,"props":1256,"children":1258},{"id":1257},"_4-关联阅读",[1259],{"type":510,"value":1260},"4. 关联阅读",{"type":504,"tag":544,"props":1262,"children":1263},{},[1264,1283,1307,1323],{"type":504,"tag":548,"props":1265,"children":1266},{},[1267,1272,1274],{"type":504,"tag":520,"props":1268,"children":1269},{},[1270],{"type":510,"value":1271},"OWASP Top 10",{"type":510,"value":1273},": ",{"type":504,"tag":1275,"props":1276,"children":1280},"a",{"href":1277,"rel":1278},"https:\u002F\u002Fowasp.org\u002Fwww-project-top-ten\u002F",[1279],"nofollow",[1281],{"type":510,"value":1282},"owasp.org\u002Fwww-project-top-ten\u002F",{"type":504,"tag":548,"props":1284,"children":1285},{},[1286,1291,1292,1299,1301],{"type":504,"tag":520,"props":1287,"children":1288},{},[1289],{"type":510,"value":1290},"MDN 文档",{"type":510,"value":1273},{"type":504,"tag":1275,"props":1293,"children":1296},{"href":1294,"rel":1295},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FCSP",[1279],[1297],{"type":510,"value":1298},"Content Security Policy (CSP)",{"type":510,"value":1300},", ",{"type":504,"tag":1275,"props":1302,"children":1305},{"href":1303,"rel":1304},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FCookies#httponly_cookies",[1279],[1306],{"type":510,"value":957},{"type":504,"tag":548,"props":1308,"children":1309},{},[1310,1315,1316],{"type":504,"tag":520,"props":1311,"children":1312},{},[1313],{"type":510,"value":1314},"JWT.io",{"type":510,"value":1273},{"type":504,"tag":1275,"props":1317,"children":1320},{"href":1318,"rel":1319},"https:\u002F\u002Fjwt.io\u002Fintroduction",[1279],[1321],{"type":510,"value":1322},"Introduction to JSON Web Tokens",{"type":504,"tag":548,"props":1324,"children":1325},{},[1326,1331,1332],{"type":504,"tag":520,"props":1327,"children":1328},{},[1329],{"type":510,"value":1330},"OAuth 2.0 官网",{"type":510,"value":1273},{"type":504,"tag":1275,"props":1333,"children":1336},{"href":1334,"rel":1335},"https:\u002F\u002Foauth.net\u002F2\u002F",[1279],[1337],{"type":510,"value":1338},"oauth.net\u002F2\u002F",{"type":504,"tag":1340,"props":1341,"children":1342},"style",{},[1343],{"type":510,"value":1344},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":864,"searchDepth":1134,"depth":1134,"links":1346},[1347,1348,1352,1357],{"id":534,"depth":1134,"text":537},{"id":592,"depth":1134,"text":595,"children":1349},[1350,1351],{"id":604,"depth":1144,"text":607},{"id":712,"depth":1144,"text":715},{"id":890,"depth":1134,"text":893,"children":1353},[1354,1355,1356],{"id":896,"depth":1144,"text":899},{"id":972,"depth":1144,"text":975},{"id":1077,"depth":1144,"text":1080},{"id":1257,"depth":1134,"text":1260},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1359},"\u003Cpath fill=\"currentColor\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1361},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1363},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>",{"left":4,"top":4,"width":1365,"height":1365,"rotate":4,"vFlip":6,"hFlip":6,"body":1366},1024,"\u003Cpath fill=\"currentColor\" d=\"M768 832a128 128 0 0 1-128 128H192A128 128 0 0 1 64 832V384a128 128 0 0 1 128-128v64a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64z\"\u002F>\u003Cpath fill=\"currentColor\" d=\"M384 128a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm0-64h448a128 128 0 0 1 128 128v448a128 128 0 0 1-128 128H384a128 128 0 0 1-128-128V192A128 128 0 0 1 384 64\"\u002F>"]