Web 安全是每个后端开发者和运维人员都无法绕开的必修课。一个看似不起眼的输入框,可能成为攻击者撬动整个数据库的支点。本文围绕 Web 安全中最经典的三类漏洞——SQL 注入、XSS 和 CSRF,梳理它们的攻击原理、常见变体以及对应的防御策略,帮助你建立一套完整的攻防认知框架。
一、SQL 注入:当用户输入变成数据库指令
SQL 注入(SQL Injection)是 Web 安全领域最古老、也最具破坏力的漏洞之一。它的核心问题在于:应用程序将用户输入直接拼接进 SQL 语句,导致攻击者可以篡改查询逻辑。
攻击原理
假设登录接口的查询语句是这样拼接的:
SELECT * FROM users WHERE username = '$username' AND password = '$password';
如果攻击者在用户名输入 ' OR '1'='1' --,语句就变成:
SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = '...';
OR '1'='1' 使条件恒真,-- 注释掉后续内容,攻击者无需密码即可登录。更进一步,攻击者可以通过 UNION SELECT 读取其他表的数据,甚至利用数据库函数执行系统命令。
常见变体
- 联合查询注入:利用
UNION SELECT将额外数据拼接到正常结果集中。 - 盲注:页面不回显数据时,通过布尔条件或时间延迟逐字符推断信息。
- 堆叠注入:利用分号执行多条语句,直接修改或删除数据。
防御策略
参数化查询是根本解法。 使用预编译语句将 SQL 结构与数据分离,让数据库引擎明确区分“代码”和“值”:
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
此外,还应做到:最小权限原则(Web 应用连接数据库的账号不应有 DROP、FILE 等权限)、对输入进行类型校验和长度限制、关闭生产环境的详细错误回显。
二、XSS:在别人的浏览器里执行我的代码
跨站脚本攻击(Cross-Site Scripting,XSS)的本质是:攻击者将恶意脚本注入到网页中,当其他用户浏览该页面时,脚本在其浏览器中执行,从而窃取 Cookie、会话令牌或进行钓鱼操作。
三种类型
存储型 XSS 是最危险的一种。恶意脚本被永久存储在服务器上(如评论区、用户昵称),所有访问该页面的用户都会中招。
反射型 XSS 中,恶意脚本作为请求参数发送给服务器,服务器将其原样“反射”回响应页面。攻击者通常通过钓鱼链接诱导用户点击。
DOM 型 XSS 不经过服务器,完全由前端 JavaScript 处理不当引起。例如:
document.getElementById('output').innerHTML = location.hash.slice(1);
攻击者在 URL 的 hash 中构造 <img src=x onerror=alert(document.cookie)>,脚本便会在受害者浏览器中执行。
防御策略
输出编码是第一道防线。 根据输出位置(HTML 正文、属性、JavaScript、URL)使用对应的编码方式,将 <、>、"、' 等字符转义。
内容安全策略(CSP)是纵深防御的关键。 通过 HTTP 响应头限制脚本来源:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
这能有效阻止内联脚本和未授权外部脚本的执行。此外,对 Cookie 设置 HttpOnly 标志,可以防止 JavaScript 读取会话 Cookie。
三、CSRF:借用户之手完成恶意操作
跨站请求伪造(Cross-Site Request Forgery,CSRF)与 XSS 不同,它不需要注入脚本,而是利用浏览器自动携带 Cookie 的机制,诱导已登录用户在不知情的情况下发出请求。
攻击场景
假设银行转账接口为 POST /transfer,参数为 to 和 amount。攻击者构造一个自动提交的隐藏表单,放在自己的页面上:
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>
当已登录银行账户的用户访问该页面时,浏览器会自动带上银行的会话 Cookie 发出请求,服务器误以为是用户本人操作。
防御策略
CSRF Token 是最常用的防御手段。 服务器在表单中嵌入一个随机生成的、与用户会话绑定的令牌,提交时验证令牌是否匹配。攻击者无法预测该令牌,因此伪造的请求会被拒绝。
SameSite Cookie 属性是现代浏览器的另一道屏障。将会话 Cookie 设置为 SameSite=Lax 或 SameSite=Strict,可以限制跨站请求携带 Cookie:
Set-Cookie: sessionid=abc123; SameSite=Lax; Secure; HttpOnly
此外,对于敏感操作,应验证 Origin 或 Referer 请求头,并避免使用 GET 请求执行状态变更操作。
四、安全加固清单
将以上防御措施整合为一份可落地的检查清单:
- 所有数据库查询使用参数化语句,禁止字符串拼接 SQL。
- 所有用户可控输出进行上下文相关的编码,配合 CSP 头限制脚本执行。
- 所有状态变更请求携带 CSRF Token,Cookie 设置
SameSite、HttpOnly、Secure。 - 输入验证采用白名单策略,只允许预期格式的数据通过。
- 错误信息不暴露堆栈和数据库细节,统一返回友好提示。
- 依赖库定期更新,关注 CVE 漏洞公告。
- 部署 WAF 作为辅助,但不能替代代码层面的修复。
结语
SQL 注入、XSS 和 CSRF 之所以长期占据 OWASP Top 10,不是因为防御手段有多复杂,而是因为开发者往往在功能实现后才想起安全。将参数化查询、输出编码、CSRF Token 和 SameSite Cookie 作为编码习惯而非事后补丁,才能真正把这三类漏洞挡在门外。安全不是一次性的审计,而是贯穿开发全流程的思维方式。
未经允许不得转载:任鹏个人博客 » Web 安全入门:从 SQL 注入到 XSS、CSRF 的完整攻防图谱


朋友圈点赞图在线生成源码