Skip to content

Web Frontend Security Cheat Sheet / Web前端安全速查表

Introduction / 介绍

This cheat sheet was previously named the AJAX Security Cheat Sheet.

此速查表之前被称为AJAX安全速查表。

This document will provide a starting point for AJAX security and will hopefully be updated and expanded reasonably often to provide more detailed information about specific frameworks and technologies.

本文档将为AJAX安全提供一个起点,并希望能够合理频繁地更新和扩展,以提供有关特定框架和技术的更详细信息。

For applications that compose independently deployed frontend features, see the Micro-Frontend Security Cheat Sheet for runtime isolation, cross-application messaging, and host-to-remote trust boundaries.

对于由独立部署的前端功能组成的程序,请参阅微前端安全速查表,以了解运行时隔离、跨应用消息传递和主机到远程信任边界。

Before applying any specific control, developers must adopt a fundamental security mindset: All data should be considered untrusted unless explicitly validated and safely handled. This applies to:

**在应用任何特定控制之前,开发者必须培养一种基本的安全思维模式:所有数据在未明确验证和妥善处理之前都应被视为不可信。这适用于:

  • Client-side input
    中文:客户端输入
  • API response
    中文:API响应
  • Third-party integrations
    中文:第三方集成
  • Internal services and microservices
    中文:内部服务和微服务
  • Cached responses
    中文:缓存响应
  • Browser storage (localStorage, sessionStorage)
    中文:浏览器存储(localStorage, sessionStorage)
  • Hidden form fields
    中文:隐藏表单字段

Client-Side (JavaScript) / 客户端(JavaScript)

Use innerHTML with extreme caution / 请谨慎使用innerHTML

Manipulating the Document Object Model (DOM) is common in web applications, especially in monolithic server-side rendering (e.g., PHP, ASP.NET) and AJAX-driven applications. While innerHTML seems like a convenient way to inject HTML content, it poses significant security risks on untrusted-data, particularly cross-site scripting (XSS).

在Web应用程序中,操作文档对象模型(DOM)很常见,尤其是在单体服务器端渲染(例如PHP, ASP.NET)和AJAX驱动应用程序中。虽然innerHTML看起来是一种方便注入HTML内容的方法,但它对不受信任的数据,尤其是跨站脚本(XSS)存在重大安全风险。

What is innerHTML? / 什么是innerHTML?

The innerHTML property sets or gets the HTML content of an element, including tags, which the browser parses and renders as part of the DOM. For example, setting innerHTML = "<p>Hello</p>" creates a paragraph element.

innerHTML 属性用于设置或获取元素的 HTML 内容,包括标签,浏览器将其解析并渲染为 DOM 的一部分。例如,设置 innerHTML = "<p>Hello</p>" 将创建一个段落元素。

Why does innerHTML require extreme caution? / 为什么 innerHTML 需要极端谨慎使用?

Using innerHTML with untrusted data (e.g., from API responses in AJAX) can allow malicious JavaScript to execute in the user’s browser, leading to XSS vulnerabilities. Potential risks include:

在 innerHTML 中使用不受信任的数据(例如,来自 AJAX 响应的 API 数据)可能会允许恶意 JavaScript 在用户的浏览器中执行,导致 XSS 漏洞。潜在风险包括:

  • Stealing user session cookies.
    中文:窃取用户会话 cookie。
  • Defacing the website.
    中文:篡改网站。
  • Redirecting users to malicious sites.
    中文:将用户重定向到恶意网站。
  • Performing unauthorized actions (e.g., API calls on behalf of the user).
    中文:执行未经授权的操作(例如,代表用户进行 API 调用)。
  • Keylogging user inputs.
    中文:记录用户输入。
Vulnerable Example / 易受攻击的示例
    document.getElementById('content').innerHTML = data; 
    // DANGER! The server may have returned a payload that executes scripts, for example: <img src=abc onerror=alert('xss!')>.
When is innerHTML acceptable? / 何时使用 innerHTML 是可接受的?

The fundamental security rule is to never use innerHTML with untrusted data. However, in limited cases, such as legacy monolithic applications with no viable alternatives, innerHTML may be used cautiously:

基本的安全规则是绝不应该使用 innerHTML 与不受信任的数据。然而,在有限的情况下,例如没有可行替代方案的遗留单体应用程序,可以谨慎地使用 innerHTML:

  • Static, Hardcoded HTML: For small, fixed HTML snippets that are part of your application’s source code and contain no user input:
    中文:静态、硬编码的 HTML:对于作为应用程序源代码一部分的小型、固定 HTML 片段,且不包含用户输入:
document.getElementById('footer').innerHTML = '<p>© 2025 My Company. All rights reserved.</p>';
  • Sanitized HTML: For user-generated HTML (e.g., in rich text editors), sanitize with a library like DOMPurify before using innerHTML:
    中文:清洗过的 HTML:对于用户生成的 HTML(例如,在富文本编辑器中),在使用 innerHTML 之前,使用类似 DOMPurify 的库进行清洗:
import DOMPurify from 'dompurify';
const userInput = '<img src=abc onerror=alert("xss")>';
document.getElementById('content').innerHTML = DOMPurify.sanitize(userInput); // Safe, removes malicious code
Alternatives / 替代方案
  • Use Templating Engines (with auto-escaping) for reusable, structured HTML snippets.
    中文:使用模板引擎(具有自动转义功能)来处理可重用的、结构化的 HTML 片段。
  • Use framework text bindings, which generally escape text rather than sanitize arbitrary markup; Vue documents this distinction. Raw-HTML APIs such as React's dangerouslySetInnerHTML require trusted, sanitized HTML. URL and style bindings need controls appropriate to their context; see Framework Security.
    中文:使用框架文本绑定,这通常意味着转义文本而不是清理任意标记;Vue 文档说明了这种区别。原始 HTML API,如 React 的 dangerouslySetInnerHTML,需要信任且经过清理的 HTML。URL 和样式绑定需要适合其上下文的有效控制;参见 框架安全。

Use of textContent or innerText for DOM updates (for text-only content) / 使用 textContent 或 innerText 进行 DOM 更新(仅用于纯文本内容)

In AJAX and monolithic server-side rendering applications (e.g., PHP, ASP.NET), dynamic Document Object Model (DOM) updates are common for rendering text-only content from APIs or user inputs.

在 AJAX 和单体服务器端渲染应用(例如 PHP、ASP.NET)中,动态文档对象模型(DOM)更新是常见的,用于从 API 或用户输入中渲染纯文本内容。

What is textContent? / 什么是 textContent?

The textContent property sets or gets the plain text content of an element. It treats inserted HTML tags as literal text and does not parse them. It is ideal for most text-only updates, such as displaying user comments, etc.

textContent 属性用于设置或获取元素的纯文本内容。它将插入的 HTML 标签视为文本,而不对其进行解析。它非常适合大多数纯文本更新,例如显示用户评论等。

const userInput = '<script>alert("OWASP")</script>';
document.getElementById('content').textContent = userInput; // Displays plain text
What is innerText? / 什么是 innerText?

The innerText property sets or gets the visible text content of an element, respecting CSS styling (e.g., ignoring text in display: none elements). It also reflects rendered text formatting, such as line breaks or spacing.

innerText 属性用于设置或获取元素的可见文本内容,并尊重 CSS 样式(例如,忽略 display: none 元素中的文本)。它还反映了渲染文本的格式,如换行或间距。

const userInput = 'OWASP'; 
document.getElementById('content').innerText = userInput;
When to Use textContent vs. innerText / 何时使用 textContent 与 innerText
  • Use textContent: Use textContent in monolithic applications to safely insert plain text content returned from APIs.
    中文:使用 textContent:在单体应用中使用 textContent 来安全地插入从 API 返回的纯文本内容。
  • Use innerText: Only when CSS visibility or rendered text formatting (e.g. ignoring text in display: none elements) is required.
    中文:使用 innerText:仅当需要 CSS 可见性或渲染文本格式(例如,忽略 display: none 元素中的文本)时。

Note: textContent is slightly faster and more predictable; use it unless you need to respect rendered text formatting (innerText).

中文:注意:textContent 运行速度略快且更可预测;除非需要尊重渲染文本格式(innerText),否则请使用它。

Note
  • While textContent and innerText are safe for inserting plain text into the DOM, they do not protect against XSS in other contexts such as HTML attributes, JavaScript event handlers, or URLs. Always validate and sanitize untrusted input.
    中文:虽然 textContent 和 innerText 在将纯文本插入 DOM 时是安全的,但它们不能防止在其他上下文中的 XSS,例如 HTML 属性、JavaScript 事件处理器或 URL。始终验证和清理不受信任的输入。
  • Modern Frameworks like React, Vue, Angular, or Svelte automatically update text-only content so there is no need to manually use textContent or innerText.
    中文:现代框架如 React、Vue、Angular 或 Svelte 会自动更新纯文本内容,因此无需手动使用 textContent 或 innerText。

Don't use eval(), new Function() or other code evaluation tools / 不要使用 eval()、new Function() 或其他代码评估工具

eval() function is dangerous, never use it. Needing to use eval() usually indicates a problem in your design.

eval() 函数是危险的,永远不要使用。需要使用 eval() 通常表明你的设计存在问题。

Note: Using eval() or new Function() opens doors to remote code execution and XSS. Avoid it entirely.

中文:注意:使用 eval() 或 new Function() 会打开远程代码执行和 XSS 的通道。请完全避免使用。

Encode Data Before Use in an Output Context / 在输出上下文中使用数据之前进行编码

When using data to build HTML, script, CSS, XML, JSON, etc., make sure you take into account how that data must be presented in a literal sense to keep its logical meaning.

当使用数据构建 HTML、脚本、CSS、XML、JSON 等,确保考虑到数据在字面意义上的呈现方式,以保持其逻辑意义。

Data should be properly encoded before being used in this manner to prevent injection style issues, and to make sure the logical meaning is preserved.

在使用这种方式之前,数据应该被正确编码,以防止注入式问题,并确保逻辑意义得到保留。

Check out the OWASP Java Encoder Project.) (查看OWASP Java编码器项目。)

Don't rely on client logic for security / 不要依赖于客户端逻辑进行安全防护

Don't forget that the user controls the client-side logic. A number of browser plugins are available to set breakpoints, skip code, change values, etc. Never rely on client logic for security.

不要忘记用户控制客户端逻辑。有许多浏览器插件可用于设置断点、跳过代码、更改值等。永远不要依赖于客户端逻辑进行安全防护。

Don't rely on client business logic / 不要依赖于客户端业务逻辑

As with security logic, make sure any important business rules are duplicated on the server side so a user cannot bypass them, which could lead to unexpected or costly behavior.

与安全逻辑一样,确保任何重要的业务规则在服务器端都有副本,这样用户就不能绕过它们,这可能导致意外或昂贵的操作。

Avoid writing serialization code / 避免编写序列化代码

This is hard and even a small mistake can cause large security issues. There are already a lot of frameworks to provide this functionality.

这很困难,即使是小小的错误也可能导致重大的安全问题。已经有许多框架提供这项功能。

Refer to the JSON page for more info.

请参阅JSON页面获取更多信息。

Avoid building XML or JSON dynamically / 避免动态构建XML或JSON

Just like building HTML or SQL you may cause XML injection bugs, so stay away from this or at least use an encoding library or safe JSON or XML library to make attributes and element data safe.

就像构建HTML或SQL一样,你可能会引入XML注入漏洞,因此请远离这种行为,或者至少使用编码库或安全的JSON或XML库来确保属性和元素数据安全。

Never transmit secrets to the client / 永远不要向客户端传输秘密

Anything sent to the client can be read or modified by the user, so keep all that secret stuff on the server please.

发送给客户端的任何内容都可以被用户读取或修改,所以请将所有秘密内容保留在服务器上。

Choose encryption for the threat model / 为威胁模型选择加密

Use TLS for transport. Client-side encryption can also be appropriate for end-to-end protection or encryption before upload, as described in the Web Cryptography use cases. Use reviewed protocols and implementations rather than designing a cryptographic protocol yourself. Browser cryptography does not protect plaintext or keys from malicious code running in the application; account for XSS and key management as described in the Web Cryptography security considerations.

使用TLS进行传输。客户端加密也可以用于端到端保护或在上传前加密,如Web Cryptography用例中所述。使用经过审查的协议和实现,而不是自己设计加密协议。浏览器加密不能保护明文或密钥免受应用程序中恶意代码的影响;考虑XSS和密钥管理,如Web Cryptography安全考虑中所述。

Don't perform security impacting logic on client-side / 不要在客户端执行影响安全的逻辑

This principle serves as a fail-safe—if a security decision is ambiguous, perform it on the server.

此原则作为安全措施的保险丝——如果安全决策不明确,则在服务器上执行。

Server-Side / 服务器端

Use CSRF Protection / 使用CSRF保护

Take a look at the Cross-Site Request Forgery (CSRF) Prevention cheat sheet.

查看跨站请求伪造(CSRF)预防速查表。

Protect against JSON hijacking for older browsers / 保护旧浏览器免受JSON劫持

Review AngularJS JSON hijacking defense mechanism / 审查AngularJS JSON劫持防御机制

See the JSON Vulnerability Protection section of the AngularJS documentation.

参见AngularJS文档中的JSON漏洞保护部分。

Always return JSON with an object on the outside / 始终在外部返回包含对象的 JSON

Always have the outside primitive be an object for JSON strings:

JSON 字符串的外部始终为对象类型:

Exploitable:

可利用:

[{"object": "inside an array"}]

Not exploitable:

不可利用:

{"object": "not inside an array"}

Also not exploitable:

同样不可利用:

{"result": [{"object": "inside an array"}]}

Avoid writing serialization code server-side / 避免在服务器端编写序列化代码

Remember reference vs. value types; use a reviewed library.

记住引用类型与值类型;使用经过审查的库。

Services can be called directly by users / 服务可以直接被用户调用

Even though you only expect your AJAX client-side code to call those services, a malicious user can also call them directly.

即使你只期望你的 AJAX 客户端代码调用这些服务,恶意用户也可以直接调用它们。

Validate inputs and treat them as if they are under user control.

验证输入并将它们视为受用户控制的数据。

Avoid building XML or JSON by hand, use the framework / 避免手动构建 XML 或 JSON,使用框架

Use the framework to serialize data; building payloads by hand can introduce security issues.

使用框架序列化数据;手动构建有效载荷可能会引入安全问题。

Use JSON and XML schema for web services / 使用 JSON 和 XML 架构进行 Web 服务

Use a third-party library to validate web service inputs.

使用第三方库验证 Web 服务输入。

References / 参考