目录

XSS、SQL 注入、CSRF、DDoS 到底怎么防?

做 Web 开发,安全这道坎绕不过去。

下面把四类最常见的攻击讲清楚:XSS、SQL 注入、CSRF、DDoS。

每类都说原理、危害和防御,顺手纠正几个流传很广的错误说法。

内容综合公开资料整理,部分细节做了核对,但安全这块更新快,遇到拿不准的地方还是以 OWASP 等官方文档为准。

四类攻击先看个总览

赶时间的话,这张表就够用了。

Web 攻击 一句话概述 核心防御
XSS 注入 JavaScript 脚本,攻击用户浏览器 / DOM 输入校验 + 输出编码,配合浏览器安全策略
SQL 注入 参数伪造 SQL 语句,攻击数据库 参数化查询(GORM 已封装)
DDoS 海量无效请求,把服务器打到 503 不可用 云厂商高防服务 + IP 限流
CSRF 盗用登录态,冒名跟网站交互 CSRF 令牌 + SameSite Cookie

下面逐个展开。

XSS 全称跨站脚本攻击(Cross-Site Scripting)。

为了不和层叠样式表 CSS(Cascading Style Sheets)搞混,才缩写成 XSS。

它的本质是:攻击者把恶意代码植入到提供给别人使用的页面里,等其他用户打开,脚本就在受害者浏览器里跑起来了。

跟大多数攻击不同,XSS 牵扯三方,攻击者、客户端、Web 应用。

攻击目标通常是盗取存储在客户端的 Cookie 或其他身份敏感信息。

一旦拿到合法用户的信息,攻击者就能假冒这个用户跟网站交互。

XSS 的三种类型

很多教程只讲两种,其实有三种,DOM 型经常被漏掉。

分类 描述
存储型 XSS 恶意脚本被存进目标网站的数据库。别的用户访问到这个页面时,脚本被动态加载执行。留言、评论、个人资料这类地方最常见
反射型 XSS 脚本作为参数拼在 URL 里。用户点了带毒链接,网站把参数值原样反射回响应,脚本就在浏览器里执行了。一次性,发给谁谁中招
DOM 型 XSS 全程不经过服务器,问题出在前端 JavaScript 直接操作 DOM。比如把 location.hash 塞进 innerHTML。纯前端漏洞,服务端过滤拦不住

举个存储型的例子。

有人发了篇文章,正文写着 <script>alert(document.cookie)</script>。

如果服务端没处理就直接入库,那别的用户读这篇文章时,浏览器执行了脚本,Cookie 就弹出来了。

XSS 怎么防?

现在的浏览器本身做了不少安全措施,能降低 XSS 风险,但不能全指望它。

老教程爱说"过滤所有特殊字符就行了",这话不全对——光过滤输入远远不够,关键在输出时按场景做编码。

几个真正有效的手段:

措施 描述
输入验证和过滤 对表单、URL 参数、Cookie 等所有用户输入,校验类型、长度、格式,拒掉可疑或恶意输入
输出编码 把 < > & " ' 转成 HTML 实体,让浏览器当文本显示而不是当代码执行。这是最核心的一招
内容安全策略(CSP) 通过 Content-Security-Policy 头限制脚本只能从指定来源加载,禁止内联脚本,能挡掉一大批注入
HttpOnly Cookie 给 Cookie 加 HttpOnly 标记,JavaScript 就读不到它,偷不走

顺带一提:现在主流的 React、Vue 默认对插值做转义。只要别用 dangerouslySetInnerHTML 或 v-html 直接塞用户数据,就少踩很多坑。

SQL 注入:一个引号怎么就绕过了登录?

SQL 注入的根子在于:程序把用户输入直接拼进了 SQL 语句。

攻击者提交一段精心构造的输入,程序错把它当成查询逻辑的一部分执行,原本的查询意图就被改了。

最经典的例子是 ' OR '1'='1。

假设登录时用户名填 admin,密码填 ' OR '1'='1。

后端本来要执行的是:

SELECT * FROM user WHERE username='' AND password=''

参数拼进去之后变成:

SELECT * FROM user WHERE username='admin' AND password='' OR '1'='1'

'1'='1' 永远成立,验证就这么被跳过了。

/img/common-web-attacks/0001.png
SQL注入通过OR1=1绕过登录验证的语句拼接示意

再狠一点,密码填 '; DROP TABLE user; --,拼出来的语句会把 user 表直接删掉。

末尾的 -- 是注释,把原语句剩下的部分注释掉,让伪造的语句合法执行。

SQL 注入怎么防?

核心就一条:用参数化查询,别手动拼字符串。

拿 Go 的 GORM 举个对比,一眼就能看出差别。

// ❌ 危险写法:字符串拼接
name := "admin' --"
query := fmt.Sprintf("SELECT * FROM users WHERE username = '%s' AND password = '%s'", name, pwd)
db.Raw(query).Scan(&user)
// 实际执行:SELECT * FROM users WHERE username = 'admin' --' AND password = 'xxx'
// 后面的 -- 把密码判断注释掉了,直接绕过登录

// ✅ 安全写法:参数化查询
db.Where("username = ? AND password = ?", username, password).First(&user)
// 实际执行:username = 'admin\' --' AND password = 'xxx'
// 特殊字符被自动转义,输入只会被当成普通字符串值

GORM 用占位符 ? 时会自动转义,注入参数起不到攻击作用。

但要注意:GORM 不是万能护身符。

像上面的 Raw、Exec 里手动拼接照样能注入,别因为用了 ORM 就放松警惕。

其他几条配套手段:

  • 数据库账号别用 root,按最小权限授权,就算被注入了也删不掉表。
  • 关掉详细报错,别把字段名、表结构、SQL 片段直接吐给前端。
  • 上线前用 sqlmap 这类工具自查一遍,提前发现明显注入点。

DDoS:服务器被请求"群殴"瘫痪了

DDoS 是分布式拒绝服务攻击(Distributed Denial of Service)。

说白了就是发海量无效请求,把服务器资源耗尽,让正常用户访问不了,直接打到 503。

它是 DoS 的升级版。

DoS 是单挑,一台机器打你;DDoS 是群殴,攻击者控制一大批"肉鸡"一起上。

DDoS 能打在网络协议的各层,常见手法有 TCP 类的 SYN Flood、ACK Flood,UDP 类的 Fraggle、Trinoo,还有 DNS Query Flood、ICMP Flood、Slowloris 等等。

实战里往往是混合打,控制好节奏,成本最低、最难防。

SYN Flood 攻击

拿 TCP 的 SYN 攻击举例。

三次握手时,服务器发出 SYN-ACK 后、收到客户端 ACK 前的连接叫半连接,此时服务器处于 SYN_RCVD 状态。

收到 ACK 后才会转入 ESTABLISHED。

攻击者短时间内伪造大量不存在的 IP,疯狂发 SYN 包。

服务器回了确认包就傻等对方的 ACK,可源 IP 是假的,等不到,只能不断重发直到超时。

这些半连接长时间占着未连接队列,把队列塞满,正常的 SYN 请求被丢弃,服务就慢甚至瘫了。

DDoS 怎么防?

DDoS 防起来确实难,因为很难区分到底是正常请求还是攻击请求。

没法靠几行代码根治,主要靠这几招:

  • 云厂商高防服务:现在各大云都提供专业的 DDoS 防护,靠带宽和清洗集群硬扛,普通业务直接接入最省事。
  • IP 限流:对单 IP 的请求频率设上限,能挡掉一部分粗暴攻击。
  • 检测 + 清洗:这是防护产品的核心。检测判断是否正在被攻击,清洗过滤异常流量。检测的关键在于对业务足够了解——正常流量长啥样心里有数,才分得清异常。

CSRF:你的登录状态被人偷偷利用了

CSRF 全称跨站请求伪造(Cross-Site Request Forgery)。

它的玩法是:攻击者盗用你的身份(比如登录后的 Cookie),以你的名义发恶意请求。

能干的坏事不少:以你的名义发邮件、发消息、盗号,甚至买东西、转账虚拟货币。

危害直指隐私泄露和财产安全。

CSRF 的原理

/img/common-web-attacks/0002.png
CSRF攻击流程示意:用户带着A站登录态访问恶意B站被冒名操作

整个过程就四步:

  1. 用户登录了受信任的 A 网站,本地生成登录信息。
  2. 用户从 A 网站被诱导跳到恶意 B 网站。
  3. B 网站借机发起指向 A 的请求,浏览器自动带上 A 的 Cookie。
  4. A 网站以为是本人操作,B 就这么冒名把事办了。

关键点在于:浏览器向 A 发请求时会自动附加 A 的 Cookie,不管这个请求是从哪个页面发出去的。

很多人觉得"我不同时满足登录 A、又访问 B 不就行了"。

可现实是,登录一个网站后谁能保证不开新标签逛别的站?关掉浏览器 Cookie 也不一定立刻过期。

CSRF 怎么防?

原文档提了几招,按可靠程度排一下:

措施 描述
CSRF 令牌 服务端生成随机 token,藏在表单或请求头里,提交时带回来校验。重点在于浏览器会自动带 Cookie,但不会自动带 token——token 得手动加到请求里,而恶意网站拿不到受害者的 token,伪造请求就过不了校验
SameSite Cookie 把 Cookie 设成 SameSite=Strict 或 Lax,限制它只在同站请求里发送,跨站请求不带,能挡掉很大一部分 CSRF
不点不可信网站 理论上有用,但靠用户自觉这事可能性太低,只能当辅助

实际项目里,CSRF 令牌 + SameSite Cookie 配合用,基本就稳了。

转账、改密码这类敏感操作,再加一道二次确认(重输密码或验证码)更保险。

常见问题

Q1. XSS 和 CSRF 到底有啥区别?

一句话:XSS 是往你的浏览器里注入并执行恶意脚本,CSRF 是冒用你已有的登录状态发请求。

XSS 利用的是网站对用户输入的信任,CSRF 利用的是网站对用户浏览器(Cookie)的信任。

而且 XSS 往往是 CSRF 的帮凶——拿到脚本执行权限后,绕过 CSRF 令牌也不难了。

Q2. 用了 GORM 这类 ORM,是不是就不用担心 SQL 注入了?

不是。

GORM 默认的参数化查询确实安全,但只要你用了 Raw、Exec 手动拼接 SQL,注入风险照样存在。

安全与否取决于有没有用参数化,而不是用没用 ORM。

Q3. 设置了 HttpOnly,XSS 是不是就没威胁了?

没那么乐观。

HttpOnly 只是让脚本读不到 Cookie,挡住了偷 Cookie 这一种危害。

但脚本还能在页面上为所欲为:伪造点击、篡改内容、发起请求、记录键盘输入。

HttpOnly 是必备项,不是 XSS 的唯一防线。

Q4. 小网站也会被 DDoS 吗?需要专门防吗?

会,而且小网站更脆。

大站有冗余带宽和成熟防护,小站可能几 G 流量就被打垮。

不过普通小网站没必要自建防护,套一层云厂商的基础 DDoS 防护或 CDN,性价比最高。

小结

这四类攻击的防御思路其实有共性:不信任任何外部输入,该校验的校验,该编码的编码,该隔离的隔离。

参数化查询、输出编码、CSRF 令牌、SameSite、最小权限,这几样配齐,能挡住绝大多数常规攻击。

安全是个持续的活儿,新漏洞天天有,框架和依赖也得跟着更新。

如果你对某类攻击的细节还有疑问,或者踩过别的安全坑,欢迎在评论区交流~~~

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/common-web-attacks/

备用原文链接: https://blog.fiveyoboy.com/articles/common-web-attacks/