OWASP Top 10 与注入攻击防御

共 17 题
📑 题目列表 17 题
#
★★★

1. OWASP Top 10 的 A03(Injection)的 SQL/NoSQL/LDAP/XPath 注入原理

OWASP Top 10 中 A03(Injection)所涵盖的 SQL 注入、NoSQL 注入、LDAP 注入和 XPath 注入各自的原理是什么?为什么它们被归为同一类威胁?

  • 注入攻击的共性:把不可信输入拼接进解释器/查询语法,导致语义被改写
  • SQL、NoSQL、LDAP、XPath 各自注入的语法载体与触发点
  • 注入的本质是"数据与代码(命令)未分离"

注入攻击的共性是"把用户可控的输入当作具有语义的代码/查询片段"拼接进解释器(数据库、LDAP、XPath 引擎、shell),从而改变原本的查询或命令语义。SQL 注入把输入拼进 SQL 语句,典型如 ' OR '1'='1 逃逸出字符串字面量,改写 WHERE 条件;NoSQL 注入针对 MongoDB 等,利用 $where$regex$ne$gt 等操作符,把 {"user": {"$ne": null}} 这类对象当作查询条件传入,绕过身份校验;LDAP 注入通过 (&(uid=...) 构造特殊过滤表达式,利用 *() 等元字符改变过滤逻辑;XPath 注入则把输入拼进 XPath 表达式,利用 //or| 等语法遍历或读取 XML 中不应暴露的节点。它们被归为 A03 一类,是因为根因相同:未对输入与语法做隔离,让数据流混入了可执行的语法。

理解注入要先抓住"解析边界"——任何拼了用户输入再交给解释器执行的语句都是注入面。防御的核心是参数化/预编译(把数据与语法分离),而不是靠过滤特殊字符(黑名单易被绕过)。这也解释了为什么规范化(parameterization)比转义更根本。

// 危险:拼接输入
String q = "SELECT * FROM users WHERE name='" + name + "'";
// 安全:参数化
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name=?");
ps.setString(1, name);
#
★★★

2. SQL Injection 的防御"金标准"中参数化查询(parameterized queries)与预编译语句(prepared statements)

为什么说参数化查询(parameterized queries)与预编译语句(prepared statements)是 SQL 注入防御的"金标准"?它们是如何工作的?

  • 参数化查询的原理:数据与 SQL 语法彻底分离
  • 预编译语句的两阶段(编译 + 绑定)机制
  • 为什么它比转义/过滤更可靠

参数化查询的核心是"把 SQL 结构(语法)与用户数据分离":SQL 语句先被解析/编译成固定模板,用户输入只作为"参数值"(data)绑定,而不是作为"语法片段"拼接。数据库驱动会把参数值按类型安全地编码,任何引号、单引号、运算符号都只会被当作字面值,无法改变语句语义。预编译语句(PreparedStatement)在多数数据库上先"预编译"一次(SQL 结构固定),再为每次调用绑定不同参数,既提升性能(复用执行计划)又杜绝注入。相比"转义/过滤特殊字符"的黑名单思路,参数化是结构性的白名单方案——它从根上不允许输入进入语法层,因此不存在"漏过滤某个字符"的绕过空间。这使它成为业界公认的防御金标准。

记住"数据与语法分离"是金标准的内在逻辑。只要数据永远不进入解析层,注入就无从谈起。需要说明的是:参数化查询只针对"值"(value)的位置,若需动态拼接表名、列名、ORDER BY 等结构位置,则参数化无效,只能靠白名单校验。

// 金标准:参数化查询
PreparedStatement ps = conn.prepareStatement(
    "SELECT * FROM users WHERE username=? AND password=?");
ps.setString(1, username);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
#
★★★

3. SQL Injection(SQLi)的分类中 Union、Boolean、Time-based、Error-based、Out-of-band

SQL 注入(SQLi)按数据外带方式可以分为 Union、Boolean、Time-based、Error-based、Out-of-band 等类型,它们各自的原理和适用场景是什么?

  • 每种注入类型的攻击手法与数据提取方式
  • 依赖的响应类型(联合查询、布尔差异、时间延迟、错误信息、网络通道)
  • 它们如何被用于识别与利用盲注

这些分类反映的是"如何把查询结果回传或推断给攻击者"。Union-based:通过 UNION SELECT 把查询结果合并到正常结果集中直接回显,DB 结构、列数需探测;Boolean-based:利用 AND/OR 1=1 / 1=2 构造逻辑真/假,通过页面响应差异(有数据/无数据)逐字节推断,属于盲注;Time-based:利用 SLEEP()/pg_sleep()/WAITFOR DELAY 使响应延迟,通过时间差判断条件真假,用于无回显也无布尔差异的盲注;Error-based:故意触发数据库报错(如 EXTRACTVALUEUPDATEXML、超长数字转换),把查询结果嵌入错误信息返回;Out-of-band(OOB):当数据库无法直接回显时,用 LOAD_FILE/外部请求(如 xp_cmdshell、DNS 外带)把数据泄露到攻击者控制的服务器,通过 DNS/HTTP 通道带出。实践中需根据盲注/说明注、回显方式、数据库类型选择合适的手法。

分类的关键维度是"获取数据的通道"。Union 与 Error 依赖有回显,Boolean 与 Time 面向无回显的盲注,OOB 则绕过回显限制。了解这些类型有助于在测试(渗透)时识别注入,也提醒防御者:即使无直接回显,盲注仍可能存在,须用参数化彻底封堵。

#
★★★

4. SQL Injection 的 ORM 边界中 Hibernate HQL、Sequelize ORM 的 raw query 风险

使用 ORM(如 Hibernate HQL、Sequelize ORM)时,为什么仍可能存在 SQL 注入?raw query 的风险在哪里?

  • ORM 参数绑定(setParameter / 占位符)是安全的边界
  • HQL 拼接、原生 SQL、raw query 会重新暴露注入面
  • ORM 只在"值位置"安全,结构位置仍需白名单

ORM 本身并不自动免疫注入,其安全性取决于"用什么方式传参"。Hibernate 中若用 setParameter/setString 绑定参数,HQL 与 SQL 都会被安全参数化;但若用字符串拼接 HQL(如 "from User where name='" + name + "'"),或直接执行原生 SQL(createNativeQuery),就又回到注入风险。Sequelize 中 Model.findAll({ where: { ... } }) 的查询对象会被安全参数化,但 sequelize.query("SELECT ... " + raw) 这类 raw query 若直接拼入用户输入,则存在注入。此外 ORM 参数化只保证"值"安全,表名、列名、ORDER BY 字段等结构位置的动态拼接,ORM 同样无法参数化,必须白名单校验。因此 ORM 的边界是:安全仅在得当的参数绑定路径内,绕过参数绑定(raw/拼接)即失去保护。

这条考察的是"工具安全边界意识"。经验丰富的开发者用 ORM 也会留注入口,因为注入源于"拼接",而非"框架"。理解 ORM 的参数化边界,才能避免"以为用了 ORM 就安全"的误区。

// 安全:Sequelize 参数化查询对象
User.findAll({ where: { username: req.body.username } });
// 危险:raw query 拼接
sequelize.query("SELECT * FROM users WHERE name='" + req.body.name + "'");
#
★★

5. NoSQL Injection 的 MongoDB $where、$regex、$ne 等操作符注入

MongoDB 等 NoSQL 数据库如何被注入?$where$regex$ne 等操作符在注入中扮演什么角色?

  • 操作符注入:把 $ne$gt 等对象作为查询条件传入
  • JavaScript 注入:$where 执行含有用户输入的 JS 表达式
  • 防御:类型校验、拒绝操作符、参数化查询构建

NoSQL 注入主要分两类:一类是"操作符注入",当后端把用户输入(如 JSON 对象)直接传给查询条件时,攻击者把 $ne(不等于)、$gt(大于)、$regex(正则)等操作符作为字段值传入,从而改变查询语义。典型如登录校验 login({username: input.username, password: input.password}),攻击者传 {"username": {"$ne": null}, "password": {"$ne": null}} 即可绕过校验。另一类是"JavaScript 注入",$where 操作符会把一个 JS 表达式作为选条件执行,若用户输入被拼进该表达式,则可能执行任意 JS(如 return 1; 恒真,或直接注入攻击性代码)。$regex 还可被用于正则拒绝服务(ReDoS)。防御手段包括:对输入做严格类型与结构校验(只接受标量,拒绝操作符对象)、显式白名单允许的操作符、使用驱动提供的参数化查询方法、避免把含 $ 的原始对象直接拼入查询,并对 $where 这类高风险操作符禁用或至少不拼接用户输入。

操作符注入的本质仍是"数据与查询语义未分离"。NoSQL 的 JSON 查询模型让攻击者能以内联对象形式注入语法,比传统 SQL 更隐蔽。测试时常用 $ne$gt 判断注入点,防御则靠"类型白名单 + 参数化"双管齐下。

// 危险:直接透传对象,可能被注入 $ne/$gt
db.users.findOne({ username: req.body.username, password: req.body.password });
// 缓解:校验类型为字符串,拒绝操作符对象
if (typeof req.body.username !== 'string') throw new Error('invalid');
#
★★

6. Command Injection(OS Command)的 shell 元字符注入(;、|、&、$、backticks)

命令注入(OS Command Injection)是如何发生的?shell 元字符(;|&$、反引号)在其中起到什么作用?

  • 命令注入的根因:把用户输入拼进 shell 命令
  • 元字符的作用:; 分隔、| 管道、& 后台、$() 与反引号命令替换、>/< 重定向
  • 防御:避免 shell、白名单参数、使用无 shell 的进程调用 API

命令注入发生在程序把用户输入拼接进 OS 命令字符串,再交给 shell 解释执行时。shell 元字符赋予了输入"扩展为命令"的能力:; 用于分隔多条命令,| 用于管道输出,& 把命令放后台,|/& 都可追加攻击命令;$() 和反引号 ` 做命令替换(执行其内命令并取输出),>< 重定向文件,* 通配。例如 system("ls " + dir)dir="; rm -rf /" 时,shell 会执行 ls 后执行 rm -rf /。防御的第一原则是"避免 shell":用语言提供的进程执行 API(如 Java 的 ProcessBuilder、Python 的 subprocess 参数列表形式)直接传参数组,不经 shell 解释;若必须用 shell,则对输入做白名单或严格校验,并对元字符进行明确处理。根本思路是"参数不能进入 shell 语法层"。

命令注入=用户输入前进了 shell 解释器。防御关键是"不要用 shell 去执行动态命令",或让参数以 argv 数组形式传递而绕过 shell 的元字符解析。这与 SQL 参数化思路一致:数据与命令语法分离。

// 危险:拼接后交给 shell
Runtime.getRuntime().exec("ping -c 1 " + host);
// 安全:ProcessBuilder 传参数组,不经 shell,无元字符解释
new ProcessBuilder("ping", "-c", "1", host).start();
#
★★

7. OWASP ASVS(Application Security Verification Standard)V4.0 的输入输出验证

OWASP ASVS(应用安全验证标准)V4.0 中关于输入输出验证(Input/Output Validation)有哪些核心要求?

  • ASVS 的定位:可验证的安全需求清单与测试标准
  • 输入验证:白名单、长度、格式、规范化
  • 输出编码:上下文感知编码

ASVS 是 OWASP 提供的一套"可验证的应用安全需求"标准,用于按章节(V1~V14)组织安全要求并指导测试。其输入输出验证章节(V5)核心要求包括:所有输入(包括表单、JSON、URL、文件名、请求头、cookie)都要进行验证,优先采用"白名单(allowlist)"——只接受已知合法格式,而非黑名单过滤;对输入做长度、类型、字符集、范围和格式校验;在输入验证前先做规范化(canonicalization),避免双重编码(如 %252e)绕过;同时强调"输出验证/编码"——对输出的每个上下文(HTML、属性、JS、URL、CSS)做对应编码,防止注入。ASVS 强调输入验证与输出编码是"两层防御",缺一不可,且验证应发生在信任边界(trust boundary)处。

ASVS 的价值在于把模糊的安全要求变成"可逐条验证的清单",便于安全评审与测试。输入验证用白名单、输出用上下文编码,是"纵深防御"的落地。规范化很关键,因为攻击者常用编码绕过简单校验。

#
★★

8. OWASP A03 的 Cross-site Scripting(XSS)的反射型(Reflected)

反射型 XSS(Reflected XSS)的攻击原理是什么?它与存储型 XSS 有何区别?

  • 反射型 XSS 的触发路径:输入经 URL 参数立即反射回响应
  • 一次性、非持久化、需诱导用户点击
  • 与存储型 XSS(持久化)的区别

反射型 XSS 是指用户输入的恶意脚本被服务端"反射"(原样或简单处理后)直接放进当前响应 HTML 中返回,浏览器执行该脚本。典型载体是 URL 参数、搜索框、错误提示等,攻击者把 "><script>...</script> 这类 payload 拼进 URL,诱导受害者点击,脚本在受害者浏览器中以站点上下文执行。它不持久化——只在用户访问该恶意 URL 时触发一次,因此需要"社工诱导点击",无法像存储型那样被所有访问者反复触发。但危害同样大:可窃取 cookie(配合未设 HttpOnly 的会话)、劫持会话、模拟用户操作、窃取页面数据。反射型 XSS 需要"输出编码"(在回显处按上下文编码)和"输入校验"双重防御,且常配合 URL 规范化。

反射型 XSS 的关键是"数据在响应中未编码地回显"。防御重点是输出端编码而非输入过滤(因为合法输入如搜索词也可能含特殊字符)。与存储型的关键区别是"是否持久化于服务器,是否需用户主动触发"。

#
★★

9. OWASP A03 的 XSS DOM-based(DOM 型)

DOM 型 XSS(DOM-based XSS)与反射型/存储型 XSS 在原理上有什么本质区别?它如何被触发?

  • DOM 型 XSS 不经过服务端,纯前端处理
  • 数据源(source)与流向不安全的处理器(sink)
  • 典型 sink:innerHTML、eval、document.write、location

DOM 型 XSS 的本质特征是"攻击载荷只在浏览器端被处理,且不经过服务端反射"——恶意数据来自 URL 参数、location.hash、cookie、window.name 等浏览器端数据源(source),被前端 JavaScript 读取后流向一个不安全的"汇"(sink),如 innerHTMLdocument.writeevallocation.hrefsetTimeout 的字符串参数等,从而执行恶意脚本。服务端可能完全正常,甚至响应中根本没有恶意字符串,因此服务端 WAF 和输出编码通常无法拦截。防御重点在前端:对 DOM 写入操作使用安全 API(如 textContent 替代 innerHTML)、对 hash/location 等 source 做严格校验与编码、避免使用 eval 等危险 sink、使用 CSP 限制脚本执行。

DOM 型 XSS 强调"数据流"分析:source → sink 的路径。它很难被服务端检测,因为漏洞在客户端 JS 里。前端安全编码(用安全 DOM API、避免 eval)与 CSP 是主要防线。

// 危险:把 URL 参数直接拼进 innerHTML,形成 DOM XSS
document.getElementById('out').innerHTML = location.search.split('q=')[1];
// 安全:用 textContent 只设文本
document.getElementById('out').textContent = location.search.split('q=')[1];
#
★★

10. OWASP A03 的 XSS 存储型(Stored)

存储型 XSS(Stored XSS)的攻击原理是什么?为什么它被认为危害最大?

  • 恶意脚本被持久化存储(数据库),之后每次被读取时执行
  • 触发面广、无需社工、可波及所有用户
  • 典型场景:评论、论坛、用户资料、富文本

存储型 XSS 是指攻击者把恶意脚本提交到服务器并被持久化(如存入数据库的用户评论、帖子、资料、文件名等),之后任何用户访问包含该内容的页面时,脚本都会被加载并执行。由于内容被"存储",攻击是一次注入、长期有效,且无需像反射型那样依赖用户点击恶意链接——所有浏览该内容的用户都会中招,还可能形成"存储型蠕虫"(脚本自动传播)。它的危害最大,因为触发面广、可窃取管理员会话、篡改页面、批量钓鱼。防御重点在"输出端上下文编码":在渲染存储内容的位置按 HTML/属性/JS 上下文正确编码,同时对富文本做白名单标签与属性清洗(sanitize),配合 CSP。

存储型 XSS 的关键是"持久化 + 广泛触发"。防御核心是"输出编码"(存储内容在回显时必须编码),因为存储内容是用户可控的,输入过滤不可靠。它比反射型更危险正因"一次注入、人人中招"。

#
★★

11. 注入攻击的类型中 SQL/命令/模板注入的防御?

SQL 注入、命令注入与模板注入(Template Injection)作为三类不同的注入攻击,它们的防御策略有何异同?

  • 三类注入的共同根因:数据与语法未分离
  • SQL 用参数化、命令用避免 shell、模板用沙箱/不拼接模板语法
  • 防御的通用原则:数据只作为数据传递

三类注入的共同根因都是"把用户可控输入当作有语义的代码/查询片段处理"。防御策略的共性在于"让数据永远只作为数据,不进入语法层"。SQL 注入的防御金标准是参数化查询/预编译语句,把 SQL 结构固定、仅绑定参数值;命令注入的防御最重要的是"避免 shell"——用 ProcessBuilder/subprocess 的 argv 参数数组形式调用,使输入不经 shell 元字符解释;模板注入(SSTI,如 Jinja2、EJS、Velocity)则是把用户输入拼进模板表达式,攻击者可用模板语法执行任意代码(如 {{config}}{{7*7}}),防御关键是"不把用户输入作为模板语法解析",对用户可控的模板名/表达式做白名单,尽量用数据渲染而非模板解析,并避免在模板中暴露危险对象。共同原则:白名单化、参数化、最小权限、把输入当成"数据"而非"代码"。

三类注入本质相同、载体不同。防御都是"数据/语法分离"。答这题要高屋建瓴地指出共性,再分别给出各注入类型的针对性手段,体现系统化理解。

#

12. XSS 的 CSP(Content Security Policy)的纵深防御

内容安全策略(CSP)如何作为 XSS 的纵深防御手段?它有哪些关键指令?

  • CSP 的作用:限制浏览器加载和执行的内容来源
  • 关键指令:default-src、script-src、object-src、style-src、connect-src
  • 与输出编码配合形成纵深防御

CSP 是一种 HTTP 响应头(或 <meta>),告诉浏览器"允许加载和执行哪些来源的内容",从而在 XSS 注入发生时代码无法从非白名单来源执行。关键指令包括:default-src(兜底默认来源)、script-src(允许的脚本来源)、object-src(插件外链)、style-src(样式来源)、connect-src(可连接的网络端点)、img-srcframe-ancestors(防点击劫持)等。严格模式常配合 'nonce-xxx'(为合法内联脚本加随机 nonce)或 'strict-dynamic'。CSP 是"纵深防御":即使 XSS 漏洞存在(输出编码被绕过),CSP 也能阻止恶意脚本执行或从外部加载 payload,显著降低危害。但 CSP 不是万能——它不能完全替代输出编码,且配置不当(如 unsafe-inlineunsafe-eval)会削弱防护。

CSP 是"倒霉时的最后防线":它假设 XSS 可能发生,通过限制脚本来源阻止其执行。应与输出编码配合使用,二者是纵深防御的互补。配置上要避免 unsafe-inline/unsafe-eval 等放行项。

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; object-src 'none'; style-src 'self'
#

13. XSS 的防御中 Context-aware escaping(HTML、Attribute、JavaScript、CSS、URL)

什么是上下文感知的转义(Context-aware escaping)?为什么 XSS 防御必须分上下文?

  • 不同上下文(HTML 元素、属性、JS、CSS、URL)的编码规则不同
  • 编码要与渲染上下文匹配,否则无效
  • 框架自动转义(Vue/React/Thymeleaf)的默认值

上下文感知转义是指根据内容将要被渲染的"上下文"选择对应的编码规则,因为不同上下文对特殊字符的解析方式不同。在 HTML 元素内容中,需编码 <>&;在 HTML 属性中,需额外编码引号;在 JavaScript 字符串中,需编码 '"</script> 等;在 CSS 中要编码 ;url() 等;在 URL 中要编码 :/?# 等。若编码与上下文不匹配(如在属性中只做了 HTML 编码,未处理引号),攻击者仍可闭合属性逃逸。因此安全的做法是"按输出上下文选择编码器"。现代框架(React 的 JSX、Vue 的插值 {{ }}、Thymeleaf 的 th:text)默认对文本做 HTML 编码,但需注意 v-html/dangerouslySetInnerHTML/th:utext 会绕过默认转义,使用它们必须自行确保内容安全。

这是"输出编码"的进阶:编码不是一刀切,而是"上下文相关"。记忆点:HTML/Attr/JS/CSS/URL 五种上下文各有转义规则。框架默认转义是首道防线,避免使用绕过转义的 API 即可。

#

14. XSS 的防御中输出编码与 CSP?

输出编码与 CSP 在 XSS 防御中分别扮演什么角色?为什么说两者是互补而非替代?

  • 输出编码:从源头消除(渲染时转义)
  • CSP:注入发生后限制脚本执行
  • 纵深防御:两者配合

输出编码是"源头防御":在把数据渲染到 HTML 时,按上下文正确转义,让恶意脚本以纯文本形式显示而非执行,从而消除 XSS 漏洞。CSP 是"兜底防御":假定 XSS 仍可能发生(如编码被绕过、第三方程库漏洞),通过限制脚本来源与执行,让注入的脚本无法执行或无法从外部加载 payload。两者互补是因为输出编码"治本"(消除漏洞),CSP"治标"(限制危害),且 CSP 无法覆盖所有编码场景(如某些 DOM 操作、富文本),输出编码也无法完全抵御所有高级绕过。正确做法是"输出编码为主、CSP 为辅",形成纵深防御,同时配合输入校验、HttpOnly cookie、WAF 等。

输出编码解决"能不能注入",CSP 解决"注入了还能不能执行"。防线叠加才能应对多种绕过手段。答题要强调"主次配合",而非二选一。

#

15. 不安全的反序列化中风险与缓解?

不安全的反序列化(Insecure Deserialization)有哪些风险?如何缓解?

  • 反序列化攻击原理:构造恶意数据触发代码执行
  • 风险:RCE、重放、DoS
  • 缓解:不信任数据、签名验证、白名单类、替代格式

不安全的反序列化是指应用程序反序列化来自不可信来源的数据,而攻击者可通过构造恶意的序列化数据,在反序列化过程中触发任意对象构造、属性设置甚至远程代码执行(RCE)。风险包括:RCE(如 Java 的 Commons Collections Gadget、PHP 的 unserialize 魔术方法)、重放攻击(篡改或重放序列化后的对象)、拒绝服务(构造超大或深嵌套对象导致内存耗尽)。缓解措施包括:不对不可信数据使用反序列化;对序列化数据做完整性校验(HMAC 签名)并验证来源;使用反序列化类白名单限制可实例化的类;选用更安全的替换格式(JSON)并配合强类型校验;在沙箱/隔离环境运行;升级依赖以避免已知 gadget 链。

反序列化风险源于"把数据当代码执行"。缓解核心是"不信任输入 + 限制可反序列化的范围 + 用安全格式替代"。Java/PHP 等语言是重点,JSON 等无类型格式天然更安全。

#

16. 安全头配置中 CSP、HSTS 与 X-Frame-Options?

常见的安全响应头配置有哪些?CSP、HSTS 与 X-Frame-Options 各自防御什么?

  • CSP:限制脚本来源,防 XSS
  • HSTS:强制 HTTPS,防协议降级/中间人
  • X-Frame-Options / frame-ancestors:防点击劫持

常见的 Web 安全响应头包括:CSP(Content-Security-Policy)通过限制脚本与内容来源防御 XSS 和内容注入;HSTS(Strict-Transport-Security)指示浏览器必须使用 HTTPS 访问该域,防止协议降级攻击和中间人会话劫持,通常配合 preload;X-Frame-Options(DENY/SAMEORIGIN)防止页面被嵌入第三方 iframe,防御点击劫持(clickjacking),现代替代是 CSP 的 frame-ancestors 指令;此外还有 X-Content-Type-Options: nosniff(防止 MIME 嗅探)、Referrer-Policy(控制 Referer 泄露)、Permissions-Policy(限制浏览器 API)。这些头是"纵深防御"的组成部分,配置成本低、收益高。

安全头是"低成本高收益"的加固。答题时把每个头与其防御目标对应起来:CSP→XSS、HSTS→协议降级、X-Frame-Options→点击劫持。可用工具(如安全头检查器)扫描验证配置。

#

17. 输入校验与白名单中纵深防御?

为什么说"输入校验 + 白名单"是纵深防御的基础?白名单校验比黑名单有哪些优势?

  • 白名单校验:只接受已知合法输入
  • 黑名单的缺陷:无法穷举攻击模式
  • 输入校验作为纵深防御的第一层

输入校验(Input Validation)是纵深防御的第一层防线:在信任边界处,对进入系统的数据做格式、类型、长度、范围和字符集校验,只接受符合预期的数据。白名单(allowlist)校验是首选策略——它"只接受已知合法值",凡是预期之外的输入一律拒绝;而黑名单(denylist)尝试列出所有恶意模式,存在"无法穷举"和"禁用绕过"的根本缺陷(如大小写、编码、Unicode 变体、嵌套语法)。因此白名单更可靠、更易维护。但要注意:输入校验不能替代输出编码(因为部分合法输入在特定输出上下文仍可能危险),且输入校验是纵深防御的一层,需与输出编码、CSP、参数化等配合,形成多层防线。

白名单的优势是"默认拒绝、可维护、无绕过"。输入校验是纵深防御的第一层,但不是唯一一层——它要与输出编码、CSP 等互补。答题强调"白名单优于黑名单 + 纵深防御体系"。