JavaScript and TypeScript Security Cheat Sheet / JavaScript和TypeScript安全速查表¶
Introduction / 介绍¶
This cheat sheet lists secure development practices for JavaScript and TypeScript that apply everywhere the language runs: browsers, hybrid apps, server-side Node.js, and any other runtime that implements the language (MDN JavaScript). It covers language-level pitfalls (dynamic code execution, prototype pollution, regular expressions), client-side sinks, and TypeScript-specific false confidence. Rules that are equally valid on the client and the server are stated once here; backend and runtime hardening stays in the Node.js Security Cheat Sheet, which this sheet links to instead of duplicating.
此速查表列出了适用于JavaScript和TypeScript的 secure development practices,这些实践适用于语言运行的所有环境:浏览器、混合应用、服务器端Node.js以及任何实现该语言的运行时(MDN JavaScript)。它涵盖了语言级别的陷阱(动态代码执行、原型污染、正则表达式)、客户端接收点和TypeScript特定的错误信心。在此处一次声明在客户端和服务器上同样有效的规则;后端和运行时加固保留在Node.js安全速查表,此速查表通过链接而不是重复来引用它。
Related Cheat Sheets (Top-Level Links) / 相关速查表(顶级链接)¶
- Node.js Security Cheat Sheet (Node.js安全速查表) - backend and runtime guidance.
- Cross Site Scripting Prevention Cheat Sheet (跨站脚本攻击预防技巧清单) - output encoding rules per context.
- DOM based XSS Prevention Cheat Sheet (基于DOM的XSS防护技巧清单) - client-side XSS sinks and sources.
- Third Party JavaScript Management Cheat Sheet (第三方JavaScript管理速查表) - managing external scripts.
- Transport Layer Security Cheat Sheet (传输层安全性速查表) - TLS configuration.
- OWASP Cheat Sheet Series index) (OWASP速查表系列索引) - start here for the full catalog.
Dangerous Language Surface / 危险语言表面¶
eval, Function, and with / eval, Function, 和 with¶
Never build code from strings. See MDN's eval guidance. eval and new Function execute arbitrary code with the current runtime's privileges, so any attacker-influenced input reaching them is code injection (CWE-94). In browsers, setTimeout and setInterval with a string argument compile it the same way through implied eval.
切勿从字符串构建代码。请参阅MDN的eval指南。eval和new Function会以当前运行时的权限执行任意代码,因此任何攻击者影响的输入到达它们时都是代码注入(CWE-94)。在浏览器中,带有字符串参数的setTimeout和setInterval会通过隐含的eval以相同的方式编译。
- Parse data with
JSON.parse, nevereval.
中文:使用JSON.parse解析数据,切勿使用eval。 - Replace dynamic dispatch with static maps of functions instead of constructing calls from names.
中文:用函数的静态映射代替动态分发,而不是从名称构造调用。 - Do not use the
withstatement. It makes scope unpredictable, is forbidden in strict mode, and blocks engine optimizations.
中文:不要使用with语句。它使作用域不可预测,在严格模式下被禁止,并阻止引擎优化。 - Enforce this statically with the
no-eval,no-implied-eval, andno-new-funclint rules.
中文:通过no-eval、no-implied-eval和no-new-func代码检查规则静态地强制执行此规则。 - In browsers, block string compilation with an enforced Content Security Policy whose
script-srcdirective, ordefault-srcfallback, omits both'unsafe-eval'and'trusted-types-eval'. A report-only policy does not block execution (CSPEnsureCSPDoesNotBlockStringCompilation).
中文:在浏览器中,使用强制性的内容安全策略(Content Security Policy)阻止字符串编译,其中script-src指令或default-src回退省略了'unsafe-eval'和'trusted-types-eval'。仅报告策略不会阻止执行(CSPEnsureCSPDoesNotBlockStringCompilation)。 - CSP is a browser-side control and does not apply to server-side runtimes, so the lint rules remain the primary enforcement everywhere.
中文:CSP是浏览器端控制,不适用于服务器端运行时,因此代码检查规则仍然是所有地方的强制执行主要手段。
Evil Regex (ReDoS) / 恶意正则表达式(ReDoS)¶
Nested quantifiers such as (a+)+, and repeated ambiguous alternatives such as ^(a|aa)*$, can make matching take exponential time on crafted input, consuming CPU and potentially blocking the executing thread or event loop (CWE-1333). Whether a pattern is actually exploitable depends on the surrounding expression and the failing input, not just the quantified group.
嵌套量词,如 (a+)+,以及重复的歧义性选择,如 ^(a|aa)*$,可能导致在精心设计的输入上匹配时间呈指数级增长,消耗 CPU 资源,并可能阻塞执行线程或事件循环(CWE-1333)。一个模式是否真正可利用取决于周围的表达式和失败的输入,而不仅仅是量词组本身。
- Prefer well-tested validators over hand-written patterns for emails, URLs, and similar inputs.
中文:对于电子邮件、URL 和类似输入,优先使用经过良好测试的验证器而不是手写的模式。 - Keep patterns linear: avoid nested quantifiers and ambiguous alternation over the same characters.
中文:保持模式线性:避免嵌套量词和相同字符上的歧义性选择。 - Cap untrusted input length before matching, and reject rather than sanitize when input does not match.
中文:在匹配之前限制不受信任的输入长度,当输入不匹配时拒绝而不是净化。 - For the attack mechanics and detection tooling, see the OWASP ReDoS guidance; use linear-time patterns as the primary control and input-length caps as defense in depth.
中文:关于攻击机制和检测工具,请参阅OWASP ReDoS指南;使用线性时间模式作为主要控制,并将输入长度上限作为深度防御。
Strict Mode / 严格模式¶
Ship ES modules (strict by default) or declare 'use strict', as described in MDN's strict mode documentation. Strict mode turns silent mistakes into errors: assignment to undeclared variables throws, this stays undefined in plain functions instead of becoming the global object, and with is rejected. It does not fix injection, XSS, or prototype pollution; treat it as hygiene, not a security boundary.
分发 ES 模块(默认为严格模式)或声明 'use strict',如 MDN 严格模式文档 中所述。严格模式将静默错误转换为错误:未声明的变量赋值会抛出异常,this 在普通函数中保持 undefined 而不是成为全局对象,并且 with 被拒绝。它不会修复注入、XSS 或原型污染;将其视为卫生习惯,而不是安全边界。
Object and Property Safety (Including Prototype Pollution) / 对象和属性安全性(包括原型污染)¶
Prototype pollution (CWE-1321) occurs when attacker-controlled keys such as __proto__, constructor, or prototype reach a recursive merge or path setter and modify an object's prototype. This can alter the behavior of objects that inherit from that prototype. These are the JavaScript-specific essentials only; the full protection guidance lives in the dedicated Prototype Pollution Prevention Cheat Sheet.
原型污染(CWE-1321)发生在攻击者控制的键,如 __proto__、constructor 或 prototype 达到递归合并或路径设置器并修改对象的原型时。这可能会改变继承自该原型的对象的行为。这些只是 JavaScript 特定的基本要点;完整的保护指南可以在专门的 原型污染预防备忘单 中找到。
- Never pass untrusted input to a recursive merge or
set-by-pathhelper, and reject the key segments__proto__,constructor, andprototypebefore writing.
中文:切勿将不受信任的输入传递给递归合并或set-by-path辅助函数,并在写入之前拒绝__proto__、constructor和prototype等键段。 - Use a
Mapwithset,get, andhasfor untrusted dictionary keys, keeping entries separate from object properties (MDN prototype pollution defenses). If an object is required, create it withObject.create(null)so it has no prototype.
中文:对于不受信任的字典键,使用带有set、get和has的Map,将条目与对象属性分开(MDN原型污染防御)。如果需要对象,使用Object.create(null)创建它,使其没有原型。 - Validate parsed or copied untrusted data against a schema before use, and drop
__proto__keys first:Object.assignapplies them through the prototype setter and mutates the target's prototype, while spread creates a silent own property.
中文:在使用之前,请根据模式验证解析或复制的不可信数据,并首先删除__proto__键:Object.assign通过原型设置器应用它们并修改目标的原型,而展开则创建静默的自身属性。
DOM Sinks and Output Context / DOM 溢出点和输出上下文¶
Injecting attacker-controlled strings into HTML, script, or URL contexts is cross-site scripting (CWE-79). Follow the Cross Site Scripting Prevention Cheat Sheet for per-context encoding and the DOM based XSS Prevention Cheat Sheet for client-side sources and sinks.
将攻击者控制的字符串注入到 HTML、脚本或 URL 上下文中是跨站脚本 (CWE-79)。遵循 跨站脚本预防备忘单 进行上下文编码,以及 基于 DOM 的 XSS 预防备忘单 进行客户端源和汇。
- Build DOM with
textContentandcreateElementinstead ofinnerHTMLorinsertAdjacentHTML.
中文:使用textContent和createElement而不是innerHTML或insertAdjacentHTML构建 DOM。 - When HTML must be rendered, sanitize with a maintained allowlist sanitizer and enforce Trusted Types with no permissive default policy.
中文:当必须渲染HTML时,使用维护的允许列表清理器进行清理,并使用没有宽容默认策略的Trusted Types强制执行。 - Framework auto-escaping has explicit bypasses that must never receive untrusted input: React
dangerouslySetInnerHTML, Vuev-html, and AngularbypassSecurityTrustHtmland its siblings.
中文:框架自动转义具有显式绕过机制,绝不能接收不受信任的输入:ReactdangerouslySetInnerHTML、Vuev-html和 AngularbypassSecurityTrustHtml及其兄弟。
Async Error Handling, Messaging, and Origin Checks / 异步错误处理、消息传递和来源检查¶
Not every promise failure is a defect. An expected failure is part of a function's contract, such as a lookup that returns null for a missing key or a parse that throws on malformed input; handle it where the caller decides what to do, with a try/catch around await or a .catch on the terminal link of the chain, and return a typed result or a documented error. An unhandled rejection is a promise that rejects with no handler attached, so the failure propagates past the call site and is usually a bug: browsers report it in the console and fire an unhandledrejection event, while Node.js behavior depends on its unhandled-rejection mode and may terminate the process (MDN promise rejection events). Keep promise chains flat with a terminal error handler so genuinely unexpected rejections stay visible, and do not silence them with an empty catch. Server-side specifics live in the Node.js Security Cheat Sheet and are not repeated here.
并非每个承诺失败都是缺陷。一个 预期的 失败是函数合约的一部分,例如返回 null 的查找或对格式错误的输入抛出的解析;在调用者决定如何处理的地方处理它,使用 await 或链末端的 .catch 附近的 try/catch,并返回一个类型化的结果或文档化的错误。一个 未处理的 拒绝是一个没有附加处理器的承诺,因此失败会传播到调用点,通常是一个错误:浏览器在控制台中报告它并触发一个 unhandledrejection 事件,而 Node.js 的行为取决于其未处理的拒绝模式,并且可能会终止进程 (MDN 承诺拒绝事件)。通过终端错误处理器保持承诺链平坦,以便真正意外的拒绝仍然可见,并且不要通过空的 catch 来静默它们。服务器端的具体内容位于 Node.js 安全备忘单 中,此处不再重复。
For postMessage, the receiver must verify event.origin against an explicit allowlist, check event.source when a conversation partner is expected, and validate event.data against the expected schema before acting on it. The sender must pass an exact targetOrigin, never "*" for sensitive data (MDN postMessage). Prefer narrow MessageChannel ports over broadcast messaging where the design allows it.
对于 postMessage,接收方必须将 event.origin 与显式的允许列表进行验证,当预期有会话伙伴时检查 event.source,并在采取行动之前对 event.data 进行与预期模式的有效性验证。发送方必须传递确切的 targetOrigin,对于敏感数据绝不能使用 "*"(MDN postMessage) 。当设计允许时,优先使用窄 MessageChannel 端口而不是广播消息。
TypeScript-Specific Caveats / TypeScript 特殊注意事项¶
Types are erased at runtime, so TypeScript alone enforces nothing against a malicious or malformed caller.
类型在运行时被擦除,因此 TypeScript 本身无法防止恶意或格式错误的调用者。
- Treat
anyas a hole in every check.unknownis the safe default for values of unknown type, because it forces you to narrow before use, whereasanydisables type checking for that value (TypeScript Handbook:unknown).
中文:将any视为每个检查中的漏洞。unknown是未知类型值的默认安全选择,因为它强制你在使用之前进行缩小,而any则禁用了该值的类型检查(TypeScript手册:unknown)。 - Type assertions (
as) and non-null assertions (!) silence the compiler without changing runtime values; do not use them on untrusted data.
中文:类型断言(as)和非空断言(!)会关闭编译器而不改变运行时值;不要在不受信任的数据上使用它们。 - Enable
strictintsconfig.json(plusnoUncheckedIndexedAccesswhere affordable) to catch accidental unsafety in your own code. It is a code-quality control, not a trust boundary.
中文:在tsconfig.json中启用strict(以及当可行时加上noUncheckedIndexedAccess)以捕获自己代码中的意外不安全性。这是一个代码质量控制,而不是信任边界。 - Validate at every trust boundary (network responses,
postMessagepayloads, storage reads) with a runtime schema validator. The validated type should flow from the schema, not from a parallel hand-written interface.
中文:在每一个信任边界(网络响应、postMessage负载、存储读取)处使用运行时模式验证器进行验证。验证过的类型应从模式中流动,而不是从并行手写的接口中流动。
Linting and Dependency Tooling / 代码审查和依赖工具¶
- Lint with
typescript-eslintrecommended sets plusno-eval,no-implied-eval, andno-new-func. Keep dependencies updated so new rules apply.
中文:使用typescript-eslint推荐的集合进行代码检查,包括no-eval、no-implied-eval和no-new-func。保持依赖项更新,以便应用新规则。 - Pin versions with a lockfile, review dependency changes, and monitor advisories. Frontend dependency-review specifics overlap with the Node.js Security Cheat Sheet.
中文:使用锁文件固定版本,审查依赖变更,并监控安全通告。前端依赖审查的具体内容与 Node.js 安全备忘录 相重叠。 - For third-party scripts loaded from a CDN, pin a Subresource Integrity hash with
crossoriginhandling per the Third Party JavaScript Management Cheat Sheet.
中文:对于从CDN加载的第三方脚本,根据第三方JavaScript管理作弊表中的说明,使用crossorigin处理来固定子资源完整性哈希。
References / 参考¶
- MDN: Window.postMessage
- TypeScript Handbook: unknown) (TypeScript手册: 未知)
- W3C Trusted Types) (W3C可信类型)