XSS、SYN Flood 与 Socket 校招面试题|计算机网络安全
XSS、SYN Flood 与 Socket 校招面试题|计算机网络安全
本章面向计算机专业学生、应届生和校招求职者,聚焦 XSS 攻击与防护、SYN Flood 和半连接队列,并介绍 Socket 通信的执行过程。
1. 什么是 XSS 攻击?
面试题剖析
本题考察不可信数据进入浏览器可执行上下文的原因、类型和影响。回答需要区分反射型、存储型与 DOM 型,说明攻击代码在受信任站点上下文中运行,而不只是“插入一段 HTML”。
面试题解答
XSS(跨站脚本)是应用将不可信内容当成代码或可执行页面结构处理,使浏览器以受影响站点的权限执行非预期脚本的漏洞。关键是数据与代码的边界被破坏。

图:分类视角可能交叉,DOM 型强调客户端中的不安全数据流。
- 反射型
不可信输入来自本次请求,服务端未经合适处理就拼入响应。例如搜索页面将查询词直接拼成 HTML,访问特制链接时可能触发。攻击内容不需要先长期存入数据库。
- 存储型
不可信内容先保存在评论、资料或其他存储中,其他用户浏览页面时被作为可执行内容展示。由于会被多次访问,影响可能扩散到很多读者。
- DOM 型
前端代码把 URL、消息等不可信来源的数据传给危险 DOM 接口或执行接口,形成客户端注入。服务器返回的初始 HTML 不一定直接包含攻击代码。反射/存储描述来源和持久性,DOM 型描述客户端处理路径,因此不是永远互斥的三只盒子。
一个纯本地、无外传的教学例子
下面用占位符示意“未经转义直接拼接 HTML”。双花括号只是伪代码,不表示所有模板引擎都不转义;启用默认自动转义的模板通常会把输入作为文本输出。只有绕过编码、直接插入原始内容时,输入才可能被当作标记解析:
<!-- Unsafe server-side interpolation for demonstration only. -->
<div class="comment">{{ raw_user_input }}</div>
例如把简单的本地 alert('demo') 脚本作为原始输入直接写入初始文档,浏览器可能执行它;安全模板应将其转义为可见文本。实际注入还可以发生于属性、URL 等上下文,不能只搜索 <script> 就认定没有漏洞。不同 DOM 接口对插入脚本的执行行为也不相同。
危害与边界
XSS 可以改写页面、读取脚本可访问的数据、以用户身份发送请求。HttpOnly 降低 Cookie 被直接读取的风险,但不能阻止已执行脚本代用户操作。HTTPS 保护传输,不能阻止应用自己把不可信数据执行。XSS 与 CSRF 不同:前者是站点内执行非预期代码,后者通常是诱导浏览器携带身份跨站发请求。
面试时可以总结为:XSS 的根源是把外部数据送进可执行上下文。分析时沿“来源 → 处理过程 → 危险输出点”追踪,防御则要保证数据按正确上下文处理。
可能追问的问题
反射型、存储型与 DOM 型 XSS 有什么区别?
没有 script 标签就一定没有 XSS 吗?
HttpOnly 和 HTTPS 为什么不能彻底解决 XSS?
XSS 与 CSRF 的根本区别是什么?
2. 如何解决 XSS 攻击?
面试题剖析
本题应给出按数据流与输出上下文选择的防御方案,而不是把所有输入统一替换几个字符。重点是安全输出、富文本净化、危险接口控制与纵深防御各自的作用。
面试题解答
防御 XSS 的核心是让不可信数据始终被当作数据,避免进入可执行上下文。输入校验有帮助,但必须结合输出位置采用正确的编码或净化方式。

图:纯文本、富文本和链接应走不同处理路径,CSP 与 HttpOnly 提供额外保护。
- 纯文本优先使用安全接口
用模板自动转义或 textContent 写入文本,避免直接拼接 innerHTML:
// Treat the value as text, not markup.
function showComment(node, user_input) {
node.textContent = user_input;
}
HTML 文本、HTML 属性、JavaScript、CSS 和 URL 的上下文规则不同,不能认为 HTML 转义能保护所有位置。尽量避免把不可信内容直接放入脚本、事件属性和样式代码。
- 必须支持富文本时使用净化器
富文本需要保留允许的 HTML,应使用维护良好的净化库和允许列表策略,移除危险元素、属性与 URL。不要依赖正则或自行维护一个简单的 script 黑名单,净化后也不要再拼入不可信代码使保护失效。
- 校验链接与危险执行入口
链接需校验允许的协议和必要的目标范围,避免把 javascript: 等可执行协议当普通 URL。避免不可信内容进入 eval、new Function 或类似执行入口。框架默认转义只有在正常绑定路径上有效,手动原始 HTML 插入等接口可能绕过它。
- 纵深防御
CSP 使用合适的 nonce/hash 与来源策略限制脚本执行,条件允许时结合 Trusted Types 约束危险 DOM 写入。它们不能代替修复根本的数据流问题。HttpOnly、Secure 和 SameSite 分别保护 Cookie 的读取、传输和部分跨站携带行为,也不是通用 XSS 修复方法。
输入长度和业务格式限制用于控制数据质量与资源,但攻击片段可能很短,长度限制不是核心防护。具体上下文规则可参考 OWASP XSS 防御指南。
面试时可以总结为:纯文本用安全输出接口,富文本用专业净化器,URL 校验协议,避免危险执行入口,并用 CSP 与 Cookie 属性降低残余风险。必须按上下文防护,不能只过滤某个标签。
可能追问的问题
为什么不能用一种 HTML 转义覆盖所有输出位置?
富文本为什么需要净化而不是全部转义?
框架自动转义在哪些用法下会被绕过?
CSP 和 HttpOnly 分别能缓解什么、不能解决什么?
3. 半连接队列和 SYN Flood 攻击的关系
面试题剖析
本题把攻击原理落实到服务端状态与排障。与前面的攻击概念题相比,应重点说明哪个队列受压、SYN Cookie 改变了哪一步,以及为什么只增大队列不能解决所有问题。
面试题解答
SYN Flood 与半连接队列的关系在于:正常握手路径会为待确认请求保留状态,大量未完成请求可占满这部分容量,影响正常连接建立。

图:先确定压力发生在握手等待阶段,还是应用取连接阶段。
普通路径与攻击压力
收到 SYN → 记录待确认状态 → 回复 SYN+ACK → 等第三次 ACK。请求在确认或超时后离开等待状态,但持续涌入会使清理速度赶不上创建速度。伪造源地址是可能手段,真实源也能制造压力。
如果大量请求完成握手却迟迟没有被应用 accept,则压力更多体现在全连接队列。二者可能同时出现,但不能把所有队列积压都叫半连接攻击。
SYN Cookie 改变状态分配时机
它把必要的可验证信息编码到服务端初始序列号中,等 ACK 返回后再验证和恢复状态,减少每个初始 SYN 的常规状态占用。验证对象涉及 ACK 的确认号及连接信息,不是 HTTP Cookie,也不是客户端新发送一个专门 Cookie 字段。
SYN Proxy 改变验证位置
代理先验证客户端能够完成握手,再向后端建连,减少后端直接承受不完整握手的机会。代理仍有资源和带宽上限,已有连接洪泛、应用层耗时请求等也需要另外处理。
排查应比较 SYN 速率、握手完成率、半连接数量、队列溢出、应用 accept 速度和入口带宽。增大 backlog 可缓冲短时突发,却无法补足持续不足的 CPU、带宽或应用处理能力。
面试时可以总结为:半连接队列是 SYN Flood 常见的受压点,Cookie 将状态保存推迟到验证之后,Proxy 将握手验证前移。先定位握手队列还是 accept 队列,再选择容量、应用或网络侧措施。
可能追问的问题
全连接队列满与半连接队列满分别有哪些常见原因?
SYN Cookie 是否还需要处理每个到达的 SYN?
SYN Proxy 与 SYN Cookie 的部署位置和作用有什么区别?
为什么增大 backlog 无法解决持续过载?
4. Socket 的执行过程
面试题剖析
本题考察 Socket API、内核协议处理和事件循环的关系。应画清监听与已连接 Socket,并明确 connect 触发建连,accept 取出完成连接,I/O 多路复用也可以监听监听 Socket。
面试题解答
Socket 是应用访问网络通信能力的一组抽象与接口。在 Unix/Linux 中常由文件描述符引用内核对象,可以用读写或专用收发接口操作,但不是磁盘上的普通文件,也不保证所有操作语义与普通文件相同。

图:监听 Socket 保持监听,accept 返回新的已连接 Socket;握手由内核协议栈处理。
- 服务端流程
socket → bind → listen → accept → recv/send → close。
socket 创建对象;bind 绑定本地地址与端口;listen 开始被动接收连接。连接握手完成后进入等待 accept 的状态,accept 返回一个新文件描述符。原监听描述符继续负责新连接,新描述符处理这个客户端的数据。
- 客户端流程
socket → connect → send/recv → close。
connect 通常触发 TCP 握手。阻塞调用等待成功或错误;非阻塞调用可能返回正在进行,随后需等待相应事件并读取 SO_ERROR 确认结果,不能只看到“可写”就断言成功。客户端可以不显式 bind,由系统选择本地地址和临时端口。
- accept 与握手的关系
服务端内核在应用调用 accept 之前就可以完成握手。accept 不是三次握手中的一条消息,也不是让服务端去调用客户端 connect。应用暂时不取走连接时,已完成连接可能在队列中等待,直到容量或其他限制介入。
- I/O 多路复用的位置
事件循环可以同时监视监听 Socket 与已连接 Socket。监听描述符可读通常意味着有连接可 accept;已连接描述符可读可能意味着数据、EOF 或错误;可写意味着当前有相应写入空间或连接事件,仍需按操作结果处理。
Linux 常用 epoll,macOS 常用 kqueue,也有 select、poll。边缘触发等模式通常需要非阻塞并循环处理到暂时无数据/空间,具体以接口规则为准。不能说多路复用只发生在 accept 之后。
- 读写与容量边界
send 可能只接受部分数据,recv 也不保证得到完整业务消息。大于零的读取长度下,TCP recv 返回 0 表示对端有序结束发送且已有数据读完;错误与暂时不可读应另行处理。close 释放引用,是否立即发送 FIN 还与共享引用、缓冲数据和选项有关。
一个服务端端口能对应很多四元组,但实际连接数受文件描述符、内存、CPU、队列、临时端口和网络设备状态等限制。不能把地址位数相乘当作可达到的机器容量。
面试时可以总结为:Socket API 把应用操作交给内核网络栈。connect 发起建连,listen 接受被动连接,accept 交付已建立连接,事件循环管理新连接与数据就绪,应用仍负责部分读写、分帧和错误恢复。
可能追问的问题
accept 返回前,三次握手可以已经完成吗?
监听 Socket 和已连接 Socket 的职责及端口有什么不同?
非阻塞 connect 可写后为什么还要检查 SO_ERROR?
recv 返回 0 和暂时不可读分别代表什么?
为什么服务器最大连接数不能简单用 IP 数乘端口数计算?
继续阅读
阅读导航




