Web 安全基础

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

1. CSRF 原理与防御(CSRF Token/双重提交 Cookie/SameSite 协同)

请详细说明 CSRF(跨站请求伪造)攻击的原理,以及 CSRF Token、双重提交 Cookie(Double Submit Cookie)与 SameSite 三种防御手段各自的机制与协同关系?

  • CSRF 攻击的原理(利用浏览器自动携带 Cookie 的机制)
  • CSRF Token 的相互校验流程
  • 双重提交 Cookie 与 SameSite 的适用场景

CSRF 攻击利用的是"浏览器会自动把目标站点的 Cookie 随请求一起发送"这一特性,攻击者诱导已登录用户在不知情的情况下向目标站点发起伪造请求(如转账、改密、发帖),因为请求携带了有效会话 Cookie,服务端无法区分是用户主动操作还是攻击者伪造。核心防御手段:一是 CSRF Token,服务端在表单或请求中下发随机 Token,并存储在 Session 中,请求提交时服务端比对表单 Token 与会话 Token 是否一致,攻击者无法读取目标站点的 Token 因而无法伪造;二是双重提交 Cookie,服务端把 Token 同时写入一个 Cookie 和请求参数/头,校验两者是否一致,因为 CSRF 攻击无法跨域写入目标站点的 Cookie,这种方式无状态、无需 Session 存储;三是 SameSite 属性,设置 Cookie 的 SameSite=Strict 或 Lax 后,浏览器在跨站请求时不再携带该 Cookie,从源头阻断。工程上三者协同:SameSite 作为第一道防线,CSRF Token 作为纵深防御,双重提交 Cookie 适用于无状态/分布式场景。注意 SameSite=None 需要 Secure,且老浏览器兼容性需考虑。

本题考察对 CSRF 本质(浏览器自动携带 Cookie)和三类防御机制的理解。关键要回答"为什么 Token 能防 CSRF"(攻击者读不到目标站点的 Token)与"SameSite 为何能防"(跨站不携带 Cookie)。协同关系体现纵深防御思想。

#
★★★

2. OWASP Top 10 风险的工程理解

请从工程实践角度阐述 OWASP Top 10 中几类核心风险(注入、认证失效、访问控制失效、敏感数据泄露、XSS、不安全反序列化、安全配置错误、日志与监控不足等)如何在 Java 应用中体现,以及对应的防御手段?

  • OWASP Top 10 各风险的名称与本质
  • 各类风险在 Java 应用中的具体表现
  • 对应防御策略

OWASP Top 10 是 Web 应用最严重安全风险的权威清单。工程上需逐项对照:注入类(SQL/命令/LDAP/模板注入)——本质是"数据与代码未分离",Java 中应使用 PreparedStatement 预编译、参数化查询,禁止拼接 SQL;认证失效——弱口令、会话可预测、密码明文存储,应使用强哈希(BCrypt/Argon2)加盐、会话固定防护;访问控制失效——IDOR 水平越权、垂直越权,应做对象级授权与方法级权限校验;敏感数据泄露——数据加密、传输用 TLS、日志脱敏;XSS——输出编码、CSP、HttpOnly;不安全反序列化——限制反序列化类白名单、用 ObjectInputFilter;安全配置错误——关闭默认弱配置、错误信息不泄露内部细节;日志与监控不足——记录审计日志、异常告警、入侵检测。工程实践的核心是"纵深防御":把安全嵌入开发流程(安全编码规范、SAST/DAST 扫描、依赖漏洞扫描、安全评审),并持续监控。

本题考察对 OWASP Top 10 的整体认知与落实到 Java 工程的能力。回答应体现"风险是什么 + 在 Java 中如何表现 + 如何防御"三段式,并点出纵深防御思想。

#
★★★

3. SQL 注入的预编译(PreparedStatement)

请说明 SQL 注入攻击的原理,以及使用 PreparedStatement 预编译为什么能有效防止 SQL 注入,MyBatis 中 ${} 与 #{} 的区别是什么?

  • SQL 注入的原理(拼接用户输入改变 SQL 语义)
  • PreparedStatement 预编译的参数化机制
  • MyBatis ${} 与 #{} 的区别

SQL 注入攻击的本质是:开发者把用户输入直接拼接进 SQL 字符串,导致用户输入被当作 SQL 代码执行,从而绕过认证、读取或篡改数据。PreparedStatement 之所以能防注入,是因为它采用"预编译 + 参数化":SQL 骨架先被数据库编译,用户输入通过 setString 等作为参数绑定,参数值在数据库端被当作纯数据(字面量)处理,而不是 SQL 代码,因此即使输入包含 ' OR 1=1 也不会改变 SQL 语义。规范写法是 PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE name = ?"); ps.setString(1, name);。MyBatis 中,#{} 会生成占位符 ? 走预编译,安全;${} 是直接字符串拼接,存在注入风险,仅用于动态表名/列名等少数场景,且必须对输入做白名单校验。此外,ORM 框架(JPA/Hibernate/MyBatis Mapper)底层多走预编译,但动态 SQL 的 ${} 或原生 SQL 拼接仍需警惕。

本题核心是"预编译把用户输入当作数据而非代码"这一机制。回答应点出 PreparedStatement 的 ? 占位符本质,以及 MyBatis 的 #{}(安全)与 ${}(风险)的区别,体现数据与代码分离原则。

// 安全:预编译 + 参数绑定
String sql = "SELECT * FROM user WHERE name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userName); // 注入字符被当作数据
ResultSet rs = ps.executeQuery();
#
★★★

4. Spring Security 的 BCryptPasswordEncoder(自适应哈希)在密码存储的工程价值

请说明 Spring Security 中 BCryptPasswordEncoder 作为自适应哈希算法在密码存储中的工程价值,为什么不能用简单的 MD5/SHA-256 直接存储密码?

  • BCrypt 自适应哈希的特性(内置盐、可调代价因子)
  • 慢哈希对抗暴力破解/彩虹表
  • 与 MD5/SHA-256 直接哈希的差异

BCryptPasswordEncoder 实现的是 BCrypt 算法,其工程价值在于三点:一是内置随机盐,每次加密结果不同,能抵御彩虹表攻击;二是"自适应"(adaptive)——算法带 cost factor 代价因子,可随硬件提升而调高,使单次哈希刻意变慢,从而大幅提高暴力破解成本;三是输出格式自包含(含算法版本、代价因子、盐、哈希),实现与验证分离。相反,MD5/SHA-256 是"快速、无盐"的哈希,攻击者可用 GPU 每秒计算数十亿次,且相同的密码得到相同哈希,配合彩虹表极易被破解。工程上应使用 BCrypt 或 Argon2 这类慢哈希加盐的算法。使用方式:PasswordEncoder encoder = new BCryptPasswordEncoder(); encoder.encode(rawPassword); encoder.matches(rawPassword, encodedPassword);。注意 BCrypt 输入长度限制(72 字节),且需配合 DelegatingPasswordEncoder 支持未来升级。

本题考察"为什么密码存储需要慢哈希 + 盐"。核心是 BCrypt 的盐与自适应代价因子,以及它对比 MD5/SHA 在暴力破解成本上的数量级差异。回答应点出"慢"是特性而非缺陷。

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12); // cost factor 12
}
// 使用
String encoded = encoder.encode("plainPassword");
boolean ok = encoder.matches("plainPassword", encoded);
#
★★★

5. XSS 的防御(CSP/HttpOnly Cookie/输出编码)

请说明 XSS(跨站脚本)攻击的防御措施,包括 CSP(内容安全策略)、HttpOnly Cookie、输出编码各自的机制与适用场景?

  • XSS 的三种类型(存储/反射/DOM)
  • CSP 的指令与作用
  • HttpOnly 与输出编码的作用

XSS 攻击是攻击者把恶意脚本注入到网页中,当其他用户访问时在浏览器执行,从而窃取 Cookie、篡改页面或发起攻击。防御分多层:一是输出编码(Output Encoding),在渲染不可信数据时对 HTML 实体、属性、JS 上下文进行正确的转义,是防止反射型/存储型 XSS 的基础;二是 CSP(Content-Security-Policy),通过 HTTP 响应头声明允许加载脚本的来源白名单,如 default-src 'self'; script-src 'self',即使脚本被注入,浏览器也会阻止其执行,是纵深防御的关键;三是 HttpOnly Cookie,在 Set-Cookie 中加 HttpOnly 标志,使 JS 无法通过 document.cookie 读取会话 Cookie,从而降低 XSS 窃取会话的风险;四是输入校验/消毒,对富文本等按白名单过滤。三层协同:输出编码治本、CSP 兜底、HttpOnly 保护会话数据。注意 CSP 不能完全替代输出编码,DOM 型 XSS 需在 JS 层面正确处理。

本题考察 XSS 防御的分层思路。核心是"输出编码是第一道防线、CSP 是纵深防御、HttpOnly 保护 Cookie"。回答应点出各层防御的机制与局限,体现纵深防御。

#
★★★

6. XSS(Cross-Site Scripting)

请详细说明 XSS(跨站脚本)攻击的定义、类型(反射型、存储型、DOM 型)各自的攻击路径与危害?

  • XSS 三种类型的攻击路径
  • XSS 的危害(会话窃取、钓鱼、篡改)
  • 与 CSRF 的关联

XSS 是攻击者注入恶意脚本到网页,在受害者浏览器中执行的一类攻击。三种类型:反射型 XSS——恶意脚本作为 URL 参数随请求提交,服务端未经转义直接回显到页面,一次点击触发,如搜索框结果回显;存储型 XSS——恶意脚本被持久化到数据库(如评论、留言板、昵称),所有浏览该页面的用户都中招,危害最大;DOM 型 XSS——恶意代码不经过服务端,直接在浏览器端的 DOM 操作(如 innerHTMLdocument.write)中执行,通过修改 URL fragment 或 DOM 触发。危害包括:窃取会话 Cookie(配合绕过 HttpOnly 时)、以用户身份执行操作、记录键盘输入、植入钓鱼页面、发起 CSRF 请求等。防御核心是"输出编码 + 输入消毒 + CSP + HttpOnly",并区分注入上下文(HTML/属性/JS/URL/CSS)选择正确的编码方式。

本题考察 XSS 的本质与分类。应能区分反射/存储/DOM 三种类型的触发路径,并点出危害与防御。DOM 型 XSS 尤其容易被忽略,因为它不经过服务端。

#
★★★

7. CORS(跨域资源共享)的 Spring CorsConfiguration 与 allowedOriginPatterns 的安全边界

请说明 Spring 中 CorsConfiguration 与 allowedOriginPatterns 的配置方式,以及 CORS 配置的安全边界(为什么不能随意使用通配来源)?

  • CORS 的预检请求与响应头机制
  • allowedOriginPatterns 与 allowedOrigins 的区别
  • 通配来源与凭证(allowCredentials)的冲突

CORS 是浏览器的一种跨域访问控制机制,通过服务端返回 Access-Control-Allow-Origin 等响应头,决定浏览器是否允许跨域读取响应。Spring 中可用 CorsConfiguration 配置,allowedOrigins 用精确来源列表,allowedOriginPatterns 支持通配符模式(如 https://*.example.com),且允许与 allowCredentials(true) 同时使用(Spring 会把匹配到的具体 Origin 回显到响应头,而不是返回 *)。安全边界在于:一旦开启 allowCredentials(true)(允许携带 Cookie),Access-Control-Allow-Origin 就不能是 *,因为携带凭证时浏览器会拒绝通配来源,且 * 意味着任何网站都能发起带凭证的跨域请求,导致 CSRF 风险与 Cookie 泄露。因此生产环境应精确列出信任的 Origin 白名单,避免使用 *allowedOriginPatterns 也应限定到可信域名模式。另外注意 CORS 是浏览器侧策略,服务端接口本身仍应做认证与授权,不能依赖 CORS 作为唯一防线。

本题考察 CORS 配置的安全边界。核心是"允许凭证时不能用通配来源"以及 allowedOriginPatterns 与 allowedOrigins 的区别。应点出 CORS 只是浏览器限制,服务端仍需独立鉴权。

CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("https://*.example.com"));
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE"));
config.setAllowCredentials(true); // 携带凭证时不允许通配 *
config.addAllowedHeader("*");
#
★★★

8. Java 反序列化漏洞(readObject 利用链、Fastjson/Jackson 多态历史漏洞)与安全配置

请说明 Java 反序列化漏洞的原理(readObject 利用链),以及 Fastjson/Jackson 多态反序列化的历史漏洞与安全配置?

  • Java 原生反序列化 readObject 的利用链机制
  • Fastjson/Jackson 多态反序列化的风险
  • 安全配置(白名单、ObjectInputFilter、关闭多态)

Java 反序列化漏洞源于 ObjectInputStream.readObject() 会实例化对象并调用其 readObject 方法,攻击者构造恶意序列化字节流,使其在反序列化过程中通过 gadget 链(如 Apache Commons Collections 的 InvokerTransformer)触发任意代码执行。防御原生反序列化的关键是:只反序列化可信数据、使用 ObjectInputFilter 白名单过滤类、或改用 JSON 等安全格式。Fastjson 与 Jackson 的多态反序列化源于其支持在 JSON 中通过 @type 字段指定具体类,攻击者可指定危险类(如 JdbcRowSetImplTemplatesImpl)触发 JNDI 注入或代码执行。Fastjson 曾多次出现 autoType 绕过漏洞,防御建议:升级到修复版本、关闭 autoType 或使用白名单、依赖 @JsonTypeInfo@JsonSubTypes 限制可反序列化的类型。Jackson 默认不启用多态,启用时也需用 @JsonTypeIdResolver 白名单。核心原则:永远不要反序列化不可信数据,并尽量收窄类型范围。

本题考察反序列化攻击的机制与防御。核心是"readObject 触发链"与"类型多态导致可指定任意类"。防御重点在于类型白名单与关闭多态,体现了"最小化可反序列化类型面"。

#
★★

9. Cross-Origin-Opener-Policy/Embedder-Policy 的边界

请说明 Cross-Origin-Opener-Policy(COOP)与 Cross-Origin-Embedder-Policy(COEP)两个安全响应头的作用与边界?

  • COOP 隔离窗口上下文、防止跨源窗口攻击
  • COEP 限制跨源资源加载
  • 与跨源隔离(Cross-Origin Isolation)的关系

Cross-Origin-Opener-Policy(COOP)限制页面能否通过 window.opener 与跨源窗口相互引用,取值为 same-origin(同源页面可交互)、same-origin-allow-popupsunsafe-none。设置 COOP 后,跨源页面无法通过 window.opener 操纵当前页面,能防御跨源窗口信息泄露(如点击劫持、跨源 opener 攻击)。Cross-Origin-Embedder-Policy(COEP)取值为 require-corp(要求所有跨源资源带上 CORP 头或 CORS 头)或 credentialless,它限制页面能嵌入哪些跨源资源,防止通过跨源资源泄露数据。二者配合设置可启用浏览器的"跨源隔离"(Cross-Origin Isolation)能力,从而解锁 SharedArrayBuffer 等高级 API。其边界在于:COOP/COEP 是浏览器侧的隔离策略,只作用于当前文档的浏览上下文,不能替代服务端鉴权;且 COEP 的 require-corp 会要求所有第三方资源(如 CDN、图片)配合声明 CORP,实践中可能造成跨源资源加载失败,需要评估兼容性。

本题考察两个较新的安全响应头。核心是 COOP 管"窗口引用关系"、COEP 管"资源嵌入",两者协作形成跨源隔离。回答应点出边界与兼容性代价。

#
★★

10. HTTPS 与 HSTS(HTTP Strict Transport Security)

请说明 HTTPS 与 HSTS(HTTP 严格传输安全)的作用,以及 HSTS 的配置参数与边界?

  • HTTPS 的加密与认证原理
  • HSTS 强制浏览器使用 HTTPS
  • max-age/includeSubDomains/preload 参数

HTTPS 通过 TLS 对传输内容加密,并利用证书体系验证服务器身份,防止窃听、篡改与中间人攻击。但用户首次访问时若输入的是 http:// 或访问被重定向到 HTTP,仍存在被劫持的窗口。HSTS(HTTP Strict Transport Security)通过响应头 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload 告知浏览器:在 max-age 时间内,该域名必须使用 HTTPS 访问,浏览器会自动把 HTTP 请求升级为 HTTPS,杜绝降级攻击。参数:max-age 为有效期秒数;includeSubDomains 覆盖子域名;preload 申请加入浏览器内置预加载列表(需同时满足 HSTS 规则)。HSTS 的边界在于:它只在浏览器已收到过 HSTS 响应头后生效(首次访问仍有风险,故配 preload 缓解);max-age 过短可能无法覆盖所有会话;且 HSTS 只对域名生效,不适用于 IP 直连。服务端还需在 HTTP 层做重定向到 HTTPS 的兜底。

本题考察 HTTPS 与 HSTS 的关系。核心是 HSTS 解决"首次访问降级"问题,强制浏览器走 HTTPS。回答应点出 max-age、includeSubDomains、preload 参数及首次访问的边界。

#
★★

11. Permissions-Policy 的权限控制

请说明 Permissions-Policy(原 Feature-Policy)响应头的作用,以及如何通过它控制浏览器功能权限?

  • Permissions-Policy 的作用范围
  • 权限指令(摄像头、麦克风、定位等)
  • 与 CSP 的区分

Permissions-Policy 是一类 HTTP 响应头(旧称 Feature-Policy),用于控制当前页面及其 iframe 中可用的浏览器功能权限,如摄像头(camera)、麦克风(microphone)、地理位置(geolocation)、自动播放(autoplay)、支付(payment)等。配置示例:Permissions-Policy: geolocation=(self), camera=()() 表示完全禁用,(self) 表示仅当前源可用,也可指定其他源。它通过限制页面能访问的敏感能力,降低被攻击者利用的潜在风险面(如第三方 iframe 里滥用摄像头/定位)。与 CSP 的区别:CSP 控制"资源加载与脚本执行",Permissions-Policy 控制"浏览器功能权限",两者互补。其边界在于:Permissions-Policy 只对浏览器功能生效,不能替代 CSP 或服务端鉴权;且需在支持的浏览器中才生效。

本题考察 Permissions-Policy 的作用。核心是"限制浏览器敏感功能权限",与 CSP(管资源加载)区分。回答应点出 (self)() 的语法。

#
★★

12. Referrer-Policy 与跨域引用

请说明 Referrer-Policy 响应头的作用,以及它如何控制跨域请求中 Referer 头信息的泄露?

  • Referrer-Policy 的取值
  • 控制 Referer 携带的信息量
  • 防止 URL 中敏感参数泄露

Referrer-Policy 控制浏览器在发送请求时携带 Referer(或 Referrer) 头的内容范围,从而避免把源页面 URL 中的敏感信息(如 token、查询参数)泄露给第三方站点。常用取值:no-referrer(完全不发送)、no-referrer-when-downgrade(默认,HTTPS→HTTP 降级时不发送)、origin(只发送源)、strict-origin-when-cross-origin(同源发完整 URL,跨源只发源,HTTPS→HTTP 不发送)、same-origin(仅同源发送)。工程上推荐 strict-origin-when-cross-origin,兼顾功能与隐私。其边界在于:Referrer-Policy 只影响浏览器发送的 Referer 头,无法约束其他代理或服务端主动携带的信息;且 URL 中的敏感参数本就不应放入 URL(应放在 POST body 或 Header),否则仍有泄露风险。可结合 Referrer-Policy 响应头与 <meta name="referrer">rel="noreferrer" 链接属性使用。

本题考察 Referrer-Policy 控制 Referer 泄露。核心是"减少跨域请求携带的 URL 信息量"。回答应点出推荐取值与敏感参数不应放 URL 的原则。

#
★★

13. SSRF 原理、利用链与 URL 校验/出网白名单防御(协议限制/DNS rebinding 防护)

请说明 SSRF(服务端请求伪造)攻击的原理、利用链,以及 URL 校验、出网白名单、协议限制与 DNS rebinding 防护等防御手段?

  • SSRF 的原理(服务端发起请求)
  • URL 校验与解析不一致问题
  • DNS rebinding 防护与出网白名单

SSRF(Server-Side Request Forgery)攻击是攻击者利用服务端发起请求的功能(如远程图片 URL、webhook、代理),让服务端向内部网络、云元数据服务(如 169.254.169.254)或本机端口发起请求,从而探测内网、读取敏感数据或发起攻击。利用链常为:输入 URL → 服务端 fetch → 访问内网 IP/云元数据 → 盗取凭证。防御手段:一是 URL 校验,解析并校验 scheme(仅允许 http/https)、主机名、端口,禁止解析结果指向内网 IP/保留地址;二是出网白名单,限制服务端可访问的域名/IP 白名单;三是协议限制,禁止 file、gopher、dict 等危险协议;四是 DNS rebinding 防护——攻击者让域名在首次解析时指向公网合法 IP(通过校验),实际请求时再解析到内网 IP,从而绕过校验,防御需在"校验后、实际请求前"重新解析并校验,或用固定 IP 解析、禁止重定向、限制重定向次数。此外,应禁止跟随重定向到内网,并对响应做隔离。

本题考察 SSRF 的机制与防御。核心是"服务端发起请求导致内网访问",防御要点是"校验与实际请求的一致性"与"出网白名单"。DNS rebinding 是高级考点,体现校验时序问题。

#
★★

14. SameSite 三种取值(Strict/Lax/None)的差异

请说明 Cookie 的 SameSite 属性三种取值(Strict、Lax、None)的差异与适用场景?

  • Strict/Lax/None 各自的携带规则
  • Lax 的默认行为(GET 顶导)
  • 与跨站请求的关系

SameSite 属性控制 Cookie 在跨站请求中是否被携带,与 CSRF 防御直接相关。Strict:跨站请求完全不携带 Cookie,最严格,但用户体验差(从外部站点的链接进入时,首次请求不携带会话);Lax:跨站请求中,仅"顶层导航 + GET 方法"(如点击链接、<a> 跳转)携带 Cookie,而 POST/iframe/脚本发起的跨站请求不携带,是浏览器默认值,兼顾安全与可用性;None:跨站请求都携带 Cookie,必须配合 Secure(仅 HTTPS)才能设置,用于需要跨站共享会话的场景(如 SSO 回调、第三方登录)。默认情况下 Chrome 已将 SameSite 默认为 Lax。工程上,会话 Cookie 通常用 Lax 或 Strict,第三方场景才用 None+Secure。注意 SameSite 是浏览器侧策略,与 CSRF Token 属不同层,可协同使用。

本题考察 SameSite 三种取值。核心是 Lax 允许"GET 顶导"、Strict 完全禁止、None 需 Secure。回答应点出默认值 Lax 与 CSRF 的关联。

#
★★

15. Strict-Transport-Security(HSTS)的工程价值

请说明 Strict-Transport-Security(HSTS)响应头的工程价值,以及部署时需要注意的要点?

  • HSTS 强制 HTTPS 的机制
  • 部署注意点(max-age、preload、一次配置生效)
  • 降级攻击防护

HSTS 的工程价值在于:通过 Strict-Transport-Security 响应头告知浏览器"该域名在指定时间内只能通过 HTTPS 访问",浏览器收到后会自动把 HTTP 请求升级为 HTTPS,从而杜绝 SSL 剥离/降级攻击(中间人把 HTTPS 请求降级为 HTTP 窃取数据)。部署要点:max-age 应足够长(如 31536000 即一年),否则过期后浏览器又会尝试 HTTP;includeSubDomains 可覆盖所有子域名;preload 可申请加入浏览器内置 HSTS 预加载列表,解决"首次访问仍是 HTTP"的窗口问题(但加入后域名需长期保持 HTTPS,否则会导致浏览器拒连)。注意:HSTS 只在域名下生效,对 IP 无效;且需所有子域都支持 HTTPS 才能安全开启 includeSubDomains。工程上常在 CDN/网关层统一注入 HSTS 头。

本题考察 HSTS 的工程价值。核心是"强制 HTTPS、杜绝降级"。回答应点出 max-age、includeSubDomains、preload 及首次访问窗口与兼容性考量。

#
★★

16. X-Content-Type-Options: nosniff 的工程价值

请说明 X-Content-Type-Options: nosniff 响应头的工程价值,以及它防御的攻击类型?

  • nosniff 的作用机制
  • MIME 类型嗅探攻击
  • 与上传/下载场景的关系

X-Content-Type-Options: nosniff 响应头禁止浏览器对响应内容进行 MIME 类型嗅探(MIME sniffing),即浏览器必须严格按照响应头声明的 Content-Type 来解析内容,不能猜测。其工程价值在于:防止攻击者通过"错标 Content-Type"诱导浏览器把响应内容当作可执行类型(如 HTML/JS)解析,从而触发 XSS 或脚本执行。典型场景:用户上传了一个文本文件,服务端返回 Content-Type: text/plain,若攻击者把内容做成 HTML 且服务端未严格设置 Content-Type,浏览器可能嗅探为 HTML 并执行其中脚本;设置 nosniff 后浏览器按声明类型解析,杜绝此类绕过。同时 nosniff 还要求 script 元素的 Content-Type 必须是 JavaScript 类型,否则拒绝执行。工程上应在所有响应中统一注入该头,与 CSP、X-Frame-Options 等组成安全响应头基线。

本题考察 nosniff 的作用。核心是"禁止 MIME 嗅探,强制按声明类型解析"。回答应点出它防御的是"类型混淆导致的脚本执行",并说明它常与上传场景的风险相关。

#
★★

17. XXE 与 XML 解析器安全配置(禁用 DTD/外部实体)

请说明 XXE(XML 外部实体)攻击的原理,以及 Java 中 XML 解析器的安全配置(禁用 DTD/外部实体)?

  • XXE 攻击原理(外部实体读取文件/内网)
  • Java XML 解析器的安全配置
  • 禁用 DTD 与外部实体的方法

XXE(XML External Entity)攻击发生在应用解析 XML 时,XML 中可通过 DTD 定义外部实体(<!ENTITY xxe SYSTEM "file:///etc/passwd">),解析器若允许加载外部实体,攻击者即可利用它读取本地文件、发起 SSRF、DoS(Billion Laughs)。Java 中多个 XML 解析器(DocumentBuilderFactory、SAXParserFactory、TransformerFactory 等)默认行为在不同版本不同,必须显式关闭危险特性。安全配置要点:设置 setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) 完全禁用 DTD;若必须支持 DTD,则禁用外部通用实体与参数实体(http://xml.org/sax/features/external-general-entities 与 external-parameter-entities 设为 false);并禁用外部 schema 加载(setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true))。最稳妥的做法是:如果业务不需要 DTD,直接 disallow-doctype-decl=true 从源头禁用。若使用 JSON 替代 XML 可彻底规避。

本题考察 XXE 原理与 Java 解析器安全配置。核心是"DTD 外部实体导致文件/内网访问"。回答应点出具体 feature 配置与"优先禁用 DTD"的建议。

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
#
★★

18. 会话劫持(Session Hijacking)的防护

请说明会话劫持(Session Hijacking)攻击的原理与防护手段?

  • 会话劫持的途径(窃取 Cookie、XSS、网络嗅探)
  • 防护手段(HttpOnly、Secure、定期轮换、绑定指纹)
  • 检测与响应

会话劫持是攻击者窃取用户的有效会话标识(Session ID/Cookie)后,以用户身份访问系统的攻击。主要途径:通过 XSS 读取 Cookie(若未设 HttpOnly)、网络嗅探 HTTP 明文流量、中间人攻击、会话固定、或从日志/Referer 中泄露。防护手段:一是 Cookie 加 HttpOnly(防 XSS 读取)、Secure(仅 HTTPS 传输)、SameSite(防跨站携带);二是全程使用 HTTPS,杜绝明文嗅探;三是会话 ID 使用足够随机的值(SecureRandom),并在登录、权限变更等高敏感操作后轮换 Session ID;四是绑定会话指纹(如 IP、User-Agent、设备指纹),检测异常变化时中止会话;五是设置合理超时与空闲过期;六是配合异常检测(地点/设备突变)触发重新认证。检测方面,可记录会话的异常跳变(IP 变化、异地登录)并主动失效。

本题考察会话劫持的防护。核心是"从窃取途径入手":HttpOnly 防 XSS 读取、Secure 防嗅探、HTTPS 防中间人、轮换与指纹绑定缩小攻击面。回答应系统列出多条防线。

#
★★

19. 会话固定(Session Fixation)的攻击路径

请说明会话固定(Session Fixation)攻击的攻击路径与防御方法?

  • 会话固定的攻击路径(预先设置会话 ID)
  • 认证成功后轮换会话 ID
  • 与 Session 失效的关联

会话固定攻击是攻击者预先向受害者提供一个已知的会话 ID(如通过链接 /login?sessionid=xxx 或设置 Cookie),受害者用它登录后,由于服务端未更换 Session ID,攻击者仍持有同一会话 ID,从而直接以受害者身份登录。攻击路径:攻击者获取/构造一个会话 ID → 诱导受害者携带该 ID 访问站点并完成登录 → 服务端继续使用该 ID → 攻击者用该 ID 直接访问。防御核心是"认证成功后更换 Session ID"(登录成功时必须调用 request.changeSessionId() 或执行 session 失效并新建),使攻击者持有的旧 ID 作废。同时应:不接受客户端提交的任意会话 ID(尽量由服务端生成)、对会话 ID 做随机性校验、设置会话超时。Spring Security 默认在登录成功后自动迁移会话(sessionManagement().sessionFixation().migrateSession()newSession()),即更换 Session ID 并迁移属性。

本题考察会话固定的攻击路径。核心是"攻击者预置会话 ID,登录后未更换导致劫持"。防御关键是"认证成功后轮换会话 ID"。回答应点出 changeSessionId 与 Spring Security 的 sessionFixation 配置。

#
★★

20. 密码安全(bcrypt/argon2)的工程实现

请说明在 Java 工程中正确实现密码安全存储(bcrypt/argon2)的要点?

  • 加盐慢哈希算法选择
  • BCrypt 与 Argon2 的差异
  • 编码、校验与升级

密码安全存储的工程实现核心是"加盐 + 慢哈希"。推荐 BCrypt 或 Argon2(Argon2 是密码哈希竞赛获奖算法,支持内存与并行度参数,抗 GPU 攻击更强)。BCrypt 内置 22 位随机盐,带 cost 参数控制哈希成本;Argon2 有 memoryiterationsparallelism 参数,可显式控制内存占用。Spring Security 中可用 BCryptPasswordEncoder 或引入 spring-security-crypto 的 Argon2 实现,也可用 BouncyCastle 提供的 Argon2。实现要点:盐由算法自动生成并随哈希存储,无需手工管理;用 matches/verify 方法做校验,且用常量时间比较避免时序攻击;密码哈希的唯一用途是校验,不能用于加解密返回明文;对输入长度做限制(BCrypt 72 字节)并配合预处理。升级策略:用 DelegatingPasswordEncoder 支持多种算法并存,登录时检测旧哈希并升级。另注意密码哈希与业务数据加密(需要还原)是不同需求,不能混用。

本题考察密码哈希的工程实现。核心是"加盐慢哈希 + 正确校验 + 可升级"。回答应点出 BCrypt/Argon2 的选择、参数、常量时间比较与 DelegatingPasswordEncoder。

// Spring Security
PasswordEncoder encoder = new BCryptPasswordEncoder(11);
String hash = encoder.encode("myPassword");
boolean match = encoder.matches("myPassword", hash);
// 兼容多种算法并支持升级
PasswordEncoder delegating = new DelegatingPasswordEncoder("bcrypt",
    Map.of("bcrypt", new BCryptPasswordEncoder(), "argon2", new Argon2PasswordEncoder()));
#

21. 开放重定向(Open Redirect)的边界

请说明开放重定向(Open Redirect)漏洞的产生原因与防御边界?

  • 开放重定向的原理
  • 重定向目标校验的边界
  • 防御策略

开放重定向漏洞是应用根据用户可控参数(如 redirectnextreturnUrl)进行跳转,但未校验目标 URL,导致攻击者诱导用户从可信站点跳转到恶意站点(钓鱼)。攻击者构造 https://trusted.com/login?redirect=https://evil.com,用户以为在可信站点,实则被引导到钓鱼站。防御要点:重定向目标必须是白名单内的相对路径或可信域名,校验 URL 是否以 http:///https:// 开头且 host 在允许列表内;禁止使用 //(协议相对 URL)或 \\ 等绕过;推荐使用相对路径跳转(如 /dashboard)而非完整 URL。安全边界在于:单纯校验"开头是否以内部域名开头"不充分,因为 https://trusted.com.evil.com 也是以 trusted.com 开头,需精确解析 host;且 @ 符号、编码(%2f)等都可能绕过,应使用 URI 解析后的 host 比较。Spring Security 中可用 DefaultRedirectStrategy 并自定义校验,或手动校验后再跳转。

本题考察开放重定向的边界。核心是"校验重定向目标需精确解析 host 并做白名单,不能简单前缀匹配"。回答应点出编码与 @ 绕过等细节。

#

22. 文件上传安全(类型嗅探、存储隔离、路径穿越)与 MultipartFile 的安全校验

请说明文件上传的安全风险(类型嗅探、存储隔离、路径穿越)以及 Spring 中 MultipartFile 的安全校验方法?

  • 文件上传的类型校验(扩展名 vs 内容)
  • 存储隔离与路径穿越
  • MultipartFile 的校验与防毒

文件上传是常见攻击面,风险包括:上传恶意可执行文件(如 WebShell、含脚本的 HTML)导致 RCE/XSS;类型嗅探绕过(伪造扩展名但内容是脚本);路径穿越(文件名含 ../ 覆盖服务器文件);以及超大文件导致 DoS。安全校验要点:一是文件类型校验应同时检查扩展名(白名单)与文件内容(MIME 魔术字节、真正解析内容),不能只信扩展名或 Content-Type;二是存储隔离——上传文件应存到 Web 根目录之外、独立目录或对象存储,不可直接从 Web 访问执行路径,并重命名为随机名(不保留用户原始文件名);三是严格校验文件名,过滤 ../..\、空字节、以 / 开头的路径,防止路径穿越;四是限制文件大小与类型(Spring 配置 spring.servlet.multipart.max-file-size)。Spring 中 MultipartFile 提供 getOriginalFilename()(需校验)、getContentType()(不可信)、getSize()getInputStream(),可读取内容做魔数校验。图片类建议重编码(绘制后重新生成)以去除恶意载荷。

本题考察文件上传的安全校验。核心是"类型双校验(扩展名+内容)、存储隔离、防路径穿越、限大小"。回答应点出文件名重命名与图片重编码等实践。

public void upload(MultipartFile file) throws IOException {
    String original = file.getOriginalFilename();
    String ext = StringUtils.getFilenameExtension(original);
    if (!ALLOWED_EXTENSIONS.contains(ext.toLowerCase())) throw new IllegalArgumentException("非法类型");
    if (file.getSize() > MAX_SIZE) throw new IllegalArgumentException("文件过大");
    // 校验内容魔数
    byte[] bytes = file.getBytes();
    if (!isAllowedMagic(bytes)) throw new IllegalArgumentException("内容不匹配");
    // 存储到 Web 目录外,改用随机文件名,避免路径穿越
    String storedName = UUID.randomUUID().toString() + "." + ext;
    file.transferTo(Path.of(UPLOAD_DIR, storedName));
}
#

23. 水平越权与垂直越权(IDOR)及数据权限控制(行级/列级权限)

请说明水平越权(IDOR)与垂直越权的区别,以及数据权限控制(行级/列级权限)的实现方式?

  • 水平越权(IDOR)与垂直越权的区别
  • 对象级授权
  • 行级/列级权限控制

水平越权(IDOR)指普通用户访问同等级别其他用户的资源(如通过修改 id 参数查看他人订单),本质是"对象级授权缺失";垂直越权指低权限用户访问高权限功能(如普通用户调用管理员接口),本质是"功能级授权缺失"。二者的共同根因是"服务端只验证了登录,未验证请求者对该资源/操作是否有权限"。防御:垂直越权用方法级/URL 级授权(Spring Security 的 @PreAuthorize、过滤器链);水平越权用对象级授权——在查询/更新时把"资源所属者"与"当前用户"绑定校验,如 SELECT ... WHERE id=? AND owner_id=?,或先查询资源再校验归属。数据权限控制分行级(记录级,控制能访问哪些行——用数据权限注解附加 owner 条件)与列级(字段级,控制能看哪些列——脱敏、投影)。实现可用 Spring Security 的授权对象、@PreAuthorize("#id == @auth.currentUserId()")、或专门的权限框架(如 Hilldata、Sa-Token 的数据权限)。原则是"服务端必须对每个资源做归属校验,不能依赖前端传参或隐藏字段"。

本题考察越权与对象级授权。核心是"水平越权=对象级缺失、垂直越权=功能级缺失"。回答应点出"查询时绑定 owner"这一关键实践。

#

24. 点击劫持(Clickjacking)与 X-Frame-Options

请说明点击劫持(Clickjacking)攻击的原理,以及 X-Frame-Options 的防御机制?

  • 点击劫持的原理(iframe 透明覆盖)
  • X-Frame-Options 的取值
  • CSP frame-ancestors 的补充

点击劫持(Clickjacking)是攻击者把目标页面用 iframe 透明地覆盖在恶意页面上,诱导用户点击看似无害的按钮,实际点击的是被覆盖的目标页面上的功能(如转账、点赞、授权),从而实现"用户不知情地执行操作"。防御核心是禁止页面被第三方 iframe 嵌入。X-Frame-Options 响应头取值:DENY(完全禁止嵌入)、SAMEORIGIN(仅允许同源页面嵌入)、ALLOW-FROM uri(已废弃,仅允许指定源)。现代推荐用 CSP 的 frame-ancestors 指令(如 frame-ancestors 'self'),它比 X-Frame-Options 更灵活,支持多源,且优先于 X-Frame-Options。注意:frame-ancestors 不适用于通过 sendBeacon 等非导航请求;且应同时考虑 Content-Security-Policy 的兼容性(老浏览器只认 X-Frame-Options)。业务上,若确实需要被 iframe 嵌入(如第三方嵌入),需仔细评估风险并配合 frame-ancestors 白名单。

本题考察点击劫持与防御。核心是"禁止 iframe 嵌入"。回答应点出 X-Frame-Options 的 DENY/SAMEORIGIN 与 CSP frame-ancestors 的补充关系。