技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTETC

你必须要懂的 Web 安全

所属馆藏
Other
文件格式
Markdown
原始路径
Other/05-你必须要懂的Web安全
本文目录8 个章节
  1. 一、先建立几个基础认识
  2. 二、XSS:跨站脚本攻击
  3. 三、CSRF:跨站请求伪造
  4. 四、点击劫持(Clickjacking)
  5. 五、扩展:SQL 注入、DDoS 与 SYN Flood
  6. 六、现代 Web 安全响应头和工程措施
  7. 七、安全检查清单
  8. 参考资料

你必须要懂的 Web 安全

Category(分类): Other Status: 持续更新

作为前端工程师,我们也逃不开 Web 安全问题。本文尽量保留原文关于 XSS、CSRF、点击劫持、SQL 注入和 DDoS 的介绍,同时把已经过时或容易误导的说法改成现在更准确的表述,并补充现代浏览器和服务端的防御方式。

本文中的域名、请求和代码均为教学示例。安全测试只能在自己拥有或得到明确授权的系统中进行,不要把攻击代码投放到第三方生产环境。

更多文章可戳: github.com/YvetteLau/Blog

阅读完本文,至少应该能够回答:

  1. 前端常见的攻击方式有哪些?
  2. 什么是 XSS?它有哪些类型,应该如何防范?
  3. 什么是 CSRF?为什么只改用 POST 仍然不够?
  4. 如何防御点击劫持?
  5. 如何在授权范围内检查网站的安全性?

原文还准备了一个用于本地演示的示例项目,可以参考 Security 示例目录。示例项目年代较早,运行前应检查依赖和代码,不要直接部署到线上。

一、先建立几个基础认识

1. 同源策略不是“禁止所有跨域请求”

浏览器把 协议(scheme)+ 主机名(host)+ 端口(port) 组成的三元组称为源(origin)。例如:

  • https://app.example.com:443https://api.example.com:443 不是同源;
  • http://example.comhttps://example.com 不是同源;
  • https://example.com:443https://example.com:8443 也不是同源。

同源策略主要限制一个源中的脚本读取另一个源的响应和 DOM,但并不等于“跨源请求完全不会发出”。<img><script>、表单、链接和部分简单请求仍可能跨源发送,这正是 CSRF、JSONP 和 XSSI 等问题的基础。

“同站(site)”和“同源(origin)”也不是一回事。SameSite Cookie 主要按站点判断,站点通常还会考虑可注册域名和协议;安全设计不能把“同站”简单当成“同源”。

2. 不要把安全责任放在前端

前端校验可以改善体验、减少无效请求,但用户可以修改 JavaScript、绕过表单校验并直接调用接口。认证、授权、CSRF 校验、输入约束和业务规则必须在服务端再次执行。

二、XSS:跨站脚本攻击

XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击。攻击者设法让不可信数据进入 HTML、JavaScript、CSS 或 URL 等会被浏览器解析的上下文,浏览器随后把数据当成代码执行。

XSS 不一定真的“跨站”,名称来自历史背景;它的核心是不可信数据被当成了可执行内容。成功后,攻击者可能:

  • 以受害者当前页面的权限读取页面数据、修改页面或发起请求;
  • 窃取可被 JavaScript 读取的 Cookie、localStorage、令牌或表单内容;
  • 诱导输入密码、钓鱼,或把恶意内容传播给其他用户。

如果会话 Cookie 设置了 HttpOnly,脚本不能通过 document.cookie 读取它,但 XSS 仍可能借助浏览器自动携带 Cookie 发起已登录请求。因此 HttpOnly 是降低影响面的措施,不是 XSS 的根本解决方案。

原文配图(保留)

1. XSS 的三种常见类型

按恶意数据到达页面的路径,通常分为存储型、反射型和 DOM 型。实际漏洞可能同时具有多种特征。

1.1 反射型 XSS

攻击者构造一个包含恶意参数的 URL,服务端把参数未经安全处理地反射到响应 HTML 中,用户打开链接后脚本执行。搜索页、错误页、跳转页和带查询参数的页面比较常见。

典型流程:

  1. 攻击者构造带有恶意参数的 URL;
  2. 受害者被诱导打开 URL;
  3. 服务端把参数拼进 HTML 返回;
  4. 浏览器把这段参数解析成代码并执行。

POST 数据也可能触发反射型 XSS,只是通常需要构造表单并诱导用户提交,因此比 URL 传播的场景少见。

**防范重点是根据输出上下文进行编码,而不是简单地“过滤几个字符”。**例如,下面的查询参数编码只适用于 URL 的一个参数值:

const url = `/search?q=${encodeURIComponent(keyword)}`

如果变量最终要放到 HTML 文本中,encodeURIComponent 并不等价于 HTML 编码;如果变量放在 JavaScript、CSS、HTML 属性或 URL 中,也各自需要不同的处理方式。

服务端模板应使用默认转义:

app.get('/welcome', (req, res) => {
  const type = typeof req.query.type === 'string' ? req.query.type : ''

  // 使用会自动进行 HTML 转义的模板输出 type
  res.render('welcome', { type })
})

不要把用户输入直接拼到 HTML、事件属性或内联脚本中。过去常说的“Chrome 和 Safari 会自动拦截 XSS、Firefox 不会”已经不能作为安全依据;浏览器过滤器会变化,而且不能替代应用自身的防御。

1.2 DOM 型 XSS

DOM 型 XSS 的恶意数据可能只存在于浏览器端,例如来自 location、URL hash、document.referrerpostMessage、Web Storage 或接口响应。服务端不一定能看到这段数据,前端 JavaScript 将它写入危险 DOM 接收器后即可触发。

常见来源(source)包括:

  • location.hreflocation.searchlocation.hash
  • document.referrerwindow.namepostMessage 消息;
  • localStoragesessionStorage、接口返回值和用户可编辑的表单。

常见危险接收器(sink)包括:

  • innerHTMLouterHTMLinsertAdjacentHTMLdocument.write()
  • eval()new Function()、字符串形式的 setTimeout() / setInterval()
  • 事件属性(如 onclickonerror)和未经校验的 hrefsrc
  • 把不可信字符串交给会解析 HTML 或脚本的第三方组件。

只需要显示文本时,优先使用 textContent、表单的 valuecreateTextNode 或框架的默认插值:

const keyword = new URL(location.href).searchParams.get('q') ?? ''
document.querySelector('#result').textContent = keyword

setAttribute() 只有在属性名固定且属性本身安全时才适合作为安全接收器,例如 setAttribute('title', value)。不要让用户控制属性名,也不要把不可信内容写入 on* 事件属性。

如果业务确实需要用户提交富文本,不能简单删除 <script> 标签,因为事件属性、危险 URL 和 SVG 等也可能执行代码。应使用经过维护的 HTML Sanitizer(例如 DOMPurify),配置允许的标签和属性,并在清洗后不要再次拼接或修改成不安全的 HTML:

const cleanHtml = DOMPurify.sanitize(untrustedHtml)
container.innerHTML = cleanHtml

hrefsrc 等 URL 还应先解析并限制协议,至少拒绝 javascript: 等脚本协议。URL 编码本身不能把一个危险协议变成安全 URL。

Vue、React、Angular 等框架通常会自动转义文本,但 v-htmldangerouslySetInnerHTMLbypassSecurityTrust... 等逃生口会绕过默认保护,使用前必须完成可靠的清洗和审查。

1.3 存储型 XSS

恶意内容被保存到数据库、缓存或其他持久化存储中,之后在评论、帖子、私信、昵称、后台工单等页面展示给其他用户。因为一次提交可能影响很多人,存储型 XSS 的影响通常比反射型更大。

典型流程:

  1. 攻击者提交包含恶意内容的数据;
  2. 服务端把数据保存到数据库;
  3. 页面读取数据并输出到 HTML;
  4. 访问页面的用户执行了恶意内容。

正确的防御链路是:

  1. 输入校验:对长度、类型、格式和业务范围使用白名单,减少垃圾数据;
  2. 安全存储:不要因为“看起来像 HTML”就把输入当作可信代码;
  3. 按输出上下文编码:普通文本在 HTML 文本节点输出时使用 HTML 转义;
  4. 富文本单独清洗:只在明确需要 HTML 时使用白名单 Sanitizer;
  5. 服务端负责最终防御:前端过滤不能防止抓包或直接构造请求。

“在入库前统一过滤所有内容”不是万能方案:它可能破坏原始数据,也无法知道数据未来会被放入什么输出上下文。输入校验、输出编码和必要的 HTML 清洗应各司其职。

2. XSS 的纵深防御

2.1 使用正确的输出编码和安全接收器

编码必须匹配上下文:

输出位置优先做法
HTML 文本节点使用框架默认转义或 HTML 实体编码
普通 HTML 属性使用引号包裹属性值并进行属性编码,属性名使用固定白名单
URL 参数使用 URL 百分号编码;完整 URL 还要校验协议和主机
JavaScript 字符串尽量不要拼接进脚本;必须使用经过验证的 JavaScript 编码器
CSS不要拼接不可信选择器或样式代码,优先修改固定 CSS 属性
富文本 HTML使用成熟 Sanitizer,不能只做字符串替换

不要把同一种编码“全局套用”到所有地方,也不要依赖一个拦截器把所有请求统一编码。请求拦截器通常不知道变量最终会进入 HTML、JavaScript 还是 URL,容易造成漏防或双重编码。

2.2 Content Security Policy(CSP)

CSP 是浏览器的额外限制层,可以限制脚本、样式、图片、连接和页面被嵌入的来源。一个严格策略的示意如下:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-<BASE64_NONCE>'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

实际部署时应根据应用资源逐项配置,并使用每次响应独立的随机 nonce 或哈希;示例中的 <BASE64_NONCE> 只是占位符,必须由服务端替换成密码学安全的随机 Base64 值,不能原样复制。尽量不要使用 'unsafe-inline''unsafe-eval'。可以先使用 Content-Security-Policy-Report-Only 观察报告,再逐步执行策略。CSP 的 frame-ancestors、报告等功能应通过 HTTP 响应头配置;把 CSP 放进 <meta> 不能替代所有响应头能力。

CSP 是纵深防御,不是输出编码的替代品。旧浏览器、不正确的白名单以及被允许加载的第三方脚本都可能削弱它。

Chromium 系浏览器还可以评估 Trusted Types,例如在确认兼容性后使用:

Content-Security-Policy: require-trusted-types-for 'script'; trusted-types default

它可以约束 innerHTML 等 DOM XSS 接收器必须通过经过审查的策略创建内容,但目前不能当作所有浏览器的通用替代方案。

敏感会话 Cookie 至少应考虑:

Set-Cookie: __Host-session=随机会话值; Path=/; Secure; HttpOnly; SameSite=Lax
  • Secure:只通过 HTTPS 发送;
  • HttpOnly:禁止 JavaScript 读取,降低 XSS 窃取 Cookie 的影响;
  • SameSite:减少跨站请求自动携带 Cookie 的机会,主要用于 CSRF 防御;
  • __Host-:要求 HTTPS、Path=/ 且不能设置 Domain,把 Cookie 限制在当前主机。

Cookie 属性不能阻止恶意脚本执行,也不能阻止 XSS 代表用户发起请求。不要把长期会话令牌、密码等敏感信息放进 localStorage;一旦发生 XSS,Web Storage 通常可以被直接读取。

2.4 长度、格式和速率限制

对用户名、评论、文件名、URL 等字段设置合理长度和格式限制,可以减少攻击面和资源消耗;但它们只能是辅助措施,不能替代上下文编码、清洗和 CSP。验证码适合转账、改密等高风险操作的二次确认,不是 XSS 的通用修复方案。

3. 如何检测 XSS

只能在授权范围内进行检测,建议结合代码审查、自动化扫描和人工验证:

  1. 盘点来源和接收器,重点检查 URL、消息、存储和接口数据的流向;
  2. 在本地或测试环境使用无害的唯一标记验证是否被当成 HTML,而不是直接使用会执行脚本的字符串;
  3. 使用浏览器开发者工具查看 DOM、响应头和 CSP 报告;
  4. 使用 OWASP Web Security Testing Guide 设计测试用例;
  5. 使用 OWASP ZAP 或商业扫描器进行辅助扫描,人工复核结果。

原文中的“通用 XSS 攻击字符串”来自较早的过滤器绕过测试,长度很大、容易造成误报或破坏页面,不能当成所有浏览器和所有上下文都有效的检测方法,更不能直接投放生产环境。

原文配图(保留)

Arachni、w3af 等工具可以作为历史资料或特定环境的补充,但使用前应确认项目维护状态和运行环境。Mozilla HTTP Observatory 主要检查 HTTP 安全响应头,不能替代 XSS、SQL 注入等应用漏洞测试。

三、CSRF:跨站请求伪造

CSRF(Cross-Site Request Forgery,跨站请求伪造)是指攻击者诱导用户访问第三方页面,由用户的浏览器向目标站点发起请求。浏览器可能自动带上目标站点的 Cookie 或其他隐式凭证,目标站点如果只验证“凭证有效”,就可能把伪造请求当成用户主动操作。

CSRF 通常不能让攻击者直接读取目标站点的 Cookie;攻击者也不一定需要读取响应,只需要让目标站点执行一个改变状态的操作即可。可能的后果包括修改邮箱、改密码、下单、转账或提升权限,具体取决于用户权限和接口能力。

CSRF 攻击流程示意

1. 典型流程和常见误区

  1. 用户登录受信任的站点 A,浏览器保存了会话 Cookie;
  2. 用户没有退出 A,又访问了攻击者控制的站点 B;
  3. B 通过图片、表单、链接或其他方式向 A 发起请求;
  4. 如果 Cookie 满足浏览器的发送条件,浏览器会自动带上它;
  5. A 只检查 Cookie 便执行了操作。

过去常见的错误接口是用 GET 完成转账:

GET https://bank.example/transfer?to=attacker&amount=1000

攻击者可以把它放进图片或链接中。把接口改成 POST 仍然不等于解决 CSRF,因为第三方页面可以通过隐藏表单提交 POST:

<form action="https://bank.example/transfer" method="post">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="1000">
</form>

因此,所有改变状态的接口都不应使用 GET,且必须有额外的请求真实性校验。CORS 也不是 CSRF 防御:CORS 主要控制脚本能否读取响应,简单表单请求仍可能发送到服务端。

原文 CSRF 示意图

2. CSRF 防御

2.1 优先使用框架内置方案

先检查后端框架是否已经提供 CSRF 中间件和 Token 校验。内置方案通常包含 Token 生成、比较、失效和错误处理,优于每个项目自行发明一套实现。

2.2 不使用 GET 改变状态

GET、HEAD、OPTIONS 应保持安全和幂等语义;删除、修改、转账等操作使用 POST、PUT、PATCH 或 DELETE,并继续执行 Token、Origin 等校验。只改 HTTP 方法不能单独防御 CSRF。

2.3 Synchronizer Token(同步 Token)

有服务端会话的应用可以为会话生成一个高熵、不可预测且保密的 Token,放入 HTML 或接口响应,再由表单隐藏字段或 AJAX 自定义请求头带回:

<form action="/profile/email" method="post">
  <input type="hidden" name="csrf_token" value="服务端生成的随机值">
  <input name="email" type="email">
  <button type="submit">保存</button>
</form>

服务端必须比较请求中的 Token 与当前会话中的 Token,不存在或不匹配就拒绝请求。Token 不应放到 URL 中,因为 URL 可能进入浏览器历史、代理日志、服务器日志和 Referer。每次请求都更换 Token 并非绝对必要;按请求更新可能导致用户打开多个页面或使用后退按钮时产生误报,应根据业务和框架取舍。

对于 AJAX/API,可以把 Token 放在自定义请求头中,例如 X-CSRF-Token。跨源页面不能随意设置这类请求头,浏览器通常会先发 CORS 预检;不过服务端仍应对所有接受的简单请求做好 CSRF 防护。

无服务端会话时,可以使用 Double Submit Cookie:浏览器保存一个 CSRF Cookie,同时在请求头或请求体中显式提交同一个值,服务端比较二者。

仅仅比较两个相同字符串的“朴素方案”可能受到 Cookie 注入或子域名控制影响。新系统更适合使用与会话绑定、由服务端密钥 HMAC 签名的 Double Submit Cookie,并使用安全的 Cookie 范围。CSRF Cookie 本身通常不能设置为 HttpOnly,否则前端无法读取它;真正的会话 Cookie 仍应使用 HttpOnly

2.5 校验 Origin 和 Referer

对改变状态的请求,优先严格校验 Origin;必要时把 Referer 作为兼容性回退。比较时使用完整的协议、主机和端口白名单,不能只查找字符串,例如不能把 https://qq.com.attacker.example 当成 https://qq.com

受隐私策略、书签、代理或浏览器行为影响,Referer 可能缺失或只包含源,因此它适合做纵深防御或监控,不应成为唯一防线。Origin: null 也必须按业务明确处理,不能无条件放行。

SameSite 能减少跨站请求携带 Cookie 的机会,但应当与 Token 和来源校验组合使用:

属性主要行为注意事项
Strict跨站场景基本不发送 Cookie防护更强,但可能影响从外部链接进入网站的体验
Lax允许同站请求,以及部分跨站顶级安全导航(如 GET)跨站图片、脚本、iframe 等子资源通常不带 Cookie;不能代替 Token
None允许跨站发送 Cookie必须同时设置 Secure,通常意味着需要额外 CSRF 防御

现代浏览器对未显式声明的 Cookie 通常采用接近 Lax 的默认策略,但兼容性、最近创建 Cookie 的宽松例外和第三方 Cookie 政策仍可能不同。不要把浏览器默认行为当成应用的唯一安全边界。

2.7 Fetch Metadata

现代浏览器可能发送 Sec-Fetch-SiteSec-Fetch-ModeSec-Fetch-Dest 等 Fetch Metadata 请求头。服务端可以把 Sec-Fetch-Site: cross-site 的非安全方法作为明显的跨站请求拒绝,并对缺失请求头的旧客户端使用 Token 或 Origin/Referer 回退。它适合做额外防线,不应替代已有的 CSRF 方案。

2.8 验证码和用户交互

验证码、重新输入密码、二次确认或 WebAuthn 等用户交互适合保护转账、改密、删除账号等高风险操作。若每个普通请求都要求验证码,体验会很差,也不能代替基础 Token 校验。

XSS 可以在目标站点的同源上下文中读取 Token 并发起请求,因此 XSS 能绕过 CSRF 防护。CSRF 与 XSS 必须分别修复。

原文配图(保留)

四、点击劫持(Clickjacking)

点击劫持也叫 UI Redress Attack。攻击者把目标页面放在透明或伪装的 iframe 中,再把按钮、图片等诱导内容放在上面,让用户以为自己点击的是假页面,实际上点击了目标页面中的操作。

1. 首选:CSP frame-ancestors

如果页面不需要被嵌入,建议通过 HTTP 响应头禁止所有祖先页面嵌入:

Content-Security-Policy: frame-ancestors 'none'

只允许同源页面嵌入:

Content-Security-Policy: frame-ancestors 'self'

如果必须允许合作方嵌入,应列出精确的来源:

Content-Security-Policy: frame-ancestors 'self' https://partner.example

frame-ancestors 必须通过响应头配置,写成 <meta http-equiv> 不可靠且不能替代响应头。

2. X-Frame-Options 兼容防线

X-Frame-Options 仍可作为旧浏览器的兼容防线:

X-Frame-Options: DENY

或:

X-Frame-Options: SAMEORIGIN

ALLOW-FROM 已过时,现代浏览器通常会忽略它;需要允许多个来源时应使用 CSP frame-ancestorsX-Frame-Options 也必须是 HTTP 响应头,放在 HTML 的 <meta> 中没有效果。

3. Frame busting 只能作为遗留浏览器的补充

过去常见的代码是:

if (top.location !== window.location) {
  top.location = window.location
}

它可能被 iframe sandbox、多层嵌套、浏览器导航策略等方式绕过,不能替代服务端响应头。对于必须兼容非常老的浏览器,可以把它作为额外措施;现代应用应以 CSP 和 X-Frame-Options 为主。

SameSite Cookie 也能降低已登录页面在 iframe 中被利用的机会,但未登录页面、旧浏览器或不依赖 Cookie 的攻击仍可能存在,所以不能单独依赖它。

五、扩展:SQL 注入、DDoS 与 SYN Flood

这几类问题主要属于后端和基础设施安全,不是前端代码单独能够解决的。原文为了完整性进行了介绍,这里保留核心概念并修正防护方式。

1. SQL 注入

SQL 注入是把不可信输入拼接进 SQL 语句,使数据库把输入当成 SQL 代码执行。下面这种字符串拼接是不安全的:

const sql = `SELECT * FROM users WHERE name = '${name}'`

正确做法是使用参数化查询、预编译语句或 ORM 的绑定参数:

const result = await db.query(
  'SELECT * FROM users WHERE name = ?',
  [name]
)

不同数据库的占位符写法可能不同,应使用对应驱动提供的参数绑定。表名、列名、排序方向通常不能直接作为绑定参数,应从代码内置的白名单映射得到,而不是把用户输入直接拼接进去。

其他纵深防御包括:

  • 为每个应用使用权限最小的数据库账号,禁止直接使用 DBA/管理员账号;
  • 限制数据库和应用服务器的网络暴露面;
  • 不把密码“加密后保存”当作密码存储方案,密码应使用 Argon2id、scrypt、bcrypt 或 PBKDF2 等专用慢哈希算法,并为每个密码使用唯一盐;
  • 统一记录异常、限制查询结果规模并妥善处理错误信息。

“把单引号、双引号替换掉”或“把所有输入转义后再拼 SQL”都不是可靠的主防线;参数化查询才是首选。

2. DoS 与 DDoS

DoS(拒绝服务)是让服务无法正常响应,DDoS(分布式拒绝服务)则由大量分布式节点共同消耗目标的带宽、连接、CPU、内存或应用资源。攻击可能发生在:

  1. 网络带宽层,发送大量流量;
  2. 协议层,消耗连接和设备状态;
  3. 应用层,发送看似正常但成本很高的请求;
  4. 针对特定服务或用户制造不可用。

防护通常需要上游网络、CDN/Anycast、云清洗、WAF、限速、连接数限制、缓存、队列和监控配合。单靠前端加验证码不能解决大规模 DDoS;也不能把所有高流量都简单判定为攻击,需要结合基线、来源、请求特征和业务指标分析。

3. SYN Flood

TCP 三次握手中,服务器发送 SYN-ACK 后等待客户端 ACK 的阶段会占用半连接状态。攻击者可以制造大量未完成握手,使监听队列或连接状态资源被耗尽,正常连接因此受到影响。

只看到大量 SYN_RECV 或随机源 IP 不能单独证明遭受攻击,还应结合连接速率、完成率、带宽和上游设备指标判断。常见缓解手段包括:

  • 启用并正确配置 SYN cookies;
  • 合理调整监听队列、连接超时和防火墙连接限制;
  • 在负载均衡器、云网络或运营商侧进行清洗和限速;
  • 保持系统、内核和网络设备配置与实际流量模型匹配。

缩短超时或盲目增大半连接数可能只是暂时缓解,甚至引起新的资源消耗,不能作为通用答案。

六、现代 Web 安全响应头和工程措施

响应头不能修复业务漏洞,但成本低、适合做纵深防御。常见起点包括:

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
  • HSTS 只应在确认整个站点及子域都能稳定使用 HTTPS 后逐步开启;
  • nosniff 减少 MIME 类型猜测,服务端仍必须设置正确的 Content-Type
  • Referrer-Policy 减少 URL 中敏感信息泄露;
  • Permissions-Policy 关闭应用不需要的摄像头、麦克风、定位等能力;
  • 对密码重置、个人信息和其他敏感响应使用合适的 Cache-Control,必要时使用 no-store

X-XSS-Protection、HPKP(Public-Key-Pins)和 X-Frame-Options: ALLOW-FROM 都属于过时方案,不应作为新项目的主防线。CSP、正确编码、Cookie 属性、依赖升级、日志告警和最小权限应共同工作。

七、安全检查清单

上线前至少检查:

  • 所有用户可控数据都经过了与输出上下文匹配的编码或清洗;
  • 没有把不可信内容直接交给 innerHTMLeval、事件属性或危险 URL;
  • 使用了 CSP,并通过 Report-Only 逐步收敛策略;
  • 会话 Cookie 使用 SecureHttpOnly、合适的 SameSite,并尽量采用 host-only 范围;
  • 所有改变状态的接口禁用 GET,并有 Token、Origin/Referer 或 Fetch Metadata 等 CSRF 防护;
  • 页面通过 frame-ancestors 和兼容性的 X-Frame-Options 防止不必要的嵌入;
  • CORS 只允许明确的来源,带凭证时不使用 *,并正确设置 Vary: Origin
  • SQL 使用参数化查询,应用数据库账号遵循最小权限;
  • 依赖、构建产物、第三方脚本和上传文件都有安全审查;
  • 使用 OWASP WSTG、ZAP 等在授权测试环境中验证,并人工复核扫描结果;
  • 有日志、告警、备份、补丁和漏洞修复流程。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS