一、为什么要做RESTful API的安全检测
现在不管是APP、小程序还是网站后台,几乎都靠RESTful API传数据——比如你点进个人中心看订单、改收货地址,本质都是APP给后台发了个带参数的请求,后台处理后返回数据。但很多开发做API时,只想着“功能能不能跑通”,忘了加安全防护,结果就出大问题。 比如有人能直接改请求里的参数,看别人的订单;或者把普通用户的权限改成管理员,删别人的数据。这种漏洞叫“越权”和“参数篡改”,要是没提前查出来,上线后要么用户数据泄露,要么平台被搞乱,最后都是开发背锅。 做安全检测不用等上线,开发阶段就能做,用工具自动化测,比人工快太多,也能覆盖到人工容易漏的地方。
二、核心工具:Burp Suite的基础用法
做API安全检测的工具很多,Burp Suite是最常用的,它能抓API请求、改参数、自动测漏洞,适合新手也适合老手。用之前先搞懂两个核心功能:
2.1 抓包:截获API请求
正常你用APP或网页操作时,请求直接发给后台,你看不到也改不了。Burp的抓包功能就是当“中间人”,把请求先截下来,让你能改参数再发出去。
比如你改个人资料时,发的请求是/api/user/123/update,后台会检查你是不是123号用户,要是你把123改成456,再发请求,后台没拦的话,你就能改别人的资料。
2.2 重放:重复发请求
抓包后可以把请求存下来,反复发,不用再操作APP或网页,适合测漏洞时重复验证。
三、实战1:用Burp测越权漏洞
越权漏洞分两种:垂直越权(普通用户变管理员)、水平越权(普通用户看别人的个人数据),先测水平越权,这个最常见。
3.1 准备工作:搭建测试环境
先搭一个简单的测试后台,用Node.js+Express,代码很简单,只有两个接口:登录和获取订单。 技术栈:Node.js 18 + Express 4 + JSON Web Token(JWT)
// 安装依赖:npm install express jsonwebtoken cors
const express = require('express');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const app = express();
// 中间件:解析JSON、允许跨域
app.use(express.json());
app.use(cors());
// 测试用户数据:用户ID=1的订单,用户ID=2的订单
const users = [
{ id: 1, username: 'user1', password: '123456', orders: [{ orderId: 101, goods: '手机' }] },
{ id: 2, username: 'user2', password: '123456', orders: [{ orderId: 102, goods: '电脑' }] }
];
const JWT_SECRET = 'test-secret-key'; // JWT密钥,实际项目要存环境变量
// 登录接口:返回JWT令牌
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (!user) return res.status(401).json({ code: 401, msg: '账号密码错误' });
// 生成JWT,存用户ID,过期时间1小时
const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '1h' });
res.json({ code: 200, msg: '登录成功', token });
});
// 获取订单接口:根据userId参数查订单(漏洞点:没验证当前登录用户的userId)
app.get('/api/getOrders', (req, res) => {
const { userId } = req.query; // 从请求参数拿userId
const user = users.find(u => u.id === Number(userId));
if (!user) return res.status(404).json({ code: 404, msg: '用户不存在' });
res.json({ code: 200, data: user.orders });
});
// 启动服务,监听3000端口
app.listen(3000, () => console.log('服务启动,地址:http://localhost:3000'));
这个后台的漏洞很明显:获取订单时,只看参数里的userId,没检查当前登录的用户是不是这个userId的主人。比如你登录user1(userId=1),把参数改成userId=2,就能拿到user2的订单。
3.2 测试步骤
第一步:配置Burp抓包 打开Burp,切换到Proxy(代理)标签页,点Options(选项),找到Intercept Client Requests(拦截客户端请求),把端口改成8080,勾选Intercept(拦截)。然后把浏览器的代理改成127.0.0.1:8080,这样浏览器发的请求会先到Burp。 第二步:登录拿令牌 用浏览器访问http://localhost:3000,发登录请求:
{
"username": "user1",
"password": "123456"
}
Burp会截到这个请求,点Forward(转发),后台返回token,把这个token记下来,后面要用到。
第三步:抓获取订单的请求
发获取订单的请求,参数是userId=1,Burp截到后,切换到Repeater(重放)标签页,这个请求会自动存到Repeater里。
第四步:改参数测越权
把参数里的userId改成2,点Send(发送),看返回结果:如果返回了user2的订单,说明有水平越权漏洞。
3.3 漏洞修复
修复的核心是:不能相信参数里的userId,要从JWT里拿当前登录的用户ID,和参数里的userId对比。修改获取订单接口的代码:
// 修复后的获取订单接口
app.get('/api/getOrders', (req, res) => {
const { userId } = req.query;
const token = req.headers.authorization?.split(' ')[1]; // 从请求头拿JWT
if (!token) return res.status(401).json({ code: 401, msg: '未登录' });
try {
// 验证JWT,拿到当前登录的userId
const decoded = jwt.verify(token, JWT_SECRET);
const currentUserId = decoded.userId;
// 对比:参数里的userId必须等于当前登录的userId
if (Number(userId) !== currentUserId) {
return res.status(403).json({ code: 403, msg: '无权限查看该用户的订单' });
}
const user = users.find(u => u.id === Number(userId));
if (!user) return res.status(404).json({ code: 404, msg: '用户不存在' });
res.json({ code: 200, data: user.orders });
} catch (err) {
return res.status(401).json({ code: 401, msg: '令牌无效' });
}
});
修复后再测,改userId=2发请求,会返回无权限,漏洞就堵上了。
四、实战2:用Burp测参数篡改漏洞
参数篡改是指攻击者改请求里的参数值,比如把商品价格从100改成1,把订单状态从“待支付”改成“已完成”。
4.1 准备工作:新增测试接口
在原来的Node.js后台里加一个更新订单状态的接口,漏洞点是:没验证参数的合法性,比如订单状态的取值范围。
// 新增:更新订单状态接口(漏洞点:没验证status参数的取值)
app.post('/api/updateOrderStatus', (req, res) => {
const { orderId, status } = req.body; // 从请求体拿参数
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ code: 401, msg: '未登录' });
try {
const decoded = jwt.verify(token, JWT_SECRET);
const currentUserId = decoded.userId;
// 先找当前用户的订单
const user = users.find(u => u.id === currentUserId);
const order = user.orders.find(o => o.orderId === Number(orderId));
if (!order) return res.status(404).json({ code: 404, msg: '订单不存在' });
// 漏洞:直接把参数里的status赋值给订单
order.status = status;
res.json({ code: 200, msg: '更新成功', data: order });
} catch (err) {
return res.status(401).json({ code: 401, msg: '令牌无效' });
}
});
正常情况下,订单状态应该只有“待支付”“已支付”“已完成”,但这个接口没限制,攻击者可以传任何值,比如“已发货”“已退款”。
4.2 测试步骤
第一步:抓更新订单的请求 用user1登录,发更新订单的请求,内容是:
{
"orderId": 101,
"status": "已支付"
}
Burp截到后,转到Repeater。 第二步:改参数测篡改 把status改成“已退款”,点Send,看返回结果:如果返回更新成功,说明有参数篡改漏洞。
4.3 漏洞修复
修复的核心是:对参数做合法性校验,比如限制status的取值范围。修改接口代码:
// 修复后的更新订单状态接口
app.post('/api/updateOrderStatus', (req, res) => {
const { orderId, status } = req.body;
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ code: 401, msg: '未登录' });
try {
const decoded = jwt.verify(token, JWT_SECRET);
const currentUserId = decoded.userId;
const user = users.find(u => u.id === currentUserId);
const order = user.orders.find(o => o.orderId === Number(orderId));
if (!order) return res.status(404).json({ code: 404, msg: '订单不存在' });
// 修复:校验status的取值范围,只有这三个值才合法
const allowedStatus = ['待支付', '已支付', '已完成'];
if (!allowedStatus.includes(status)) {
return res.status(400).json({ code: 400, msg: '无效的订单状态' });
}
order.status = status;
res.json({ code: 200, msg: '更新成功', data: order });
} catch (err) {
return res.status(401).json({ code: 401, msg: '令牌无效' });
}
});
修复后再测,传“已退款”会返回无效状态,漏洞堵上。
五、实战3:用Burp自动化测试所有漏洞
前面的测试是手动改参数,要是接口多、参数多,手动测太慢,Burp有个功能叫Intruder(入侵),能自动改参数,批量测漏洞。
5.1 用Intruder测水平越权
比如要测多个userId的情况,不用手动改,让Burp自动生成不同的userId参数: 第一步:把Repeater里的获取订单请求转到Intruder,切换到Positions(位置)标签页,找到参数里的userId=1,点Add(添加),把这个位置标记为测试点。 第二步:切换到Payloads(载荷)标签页,在Payload Type(载荷类型)里选Numbers(数字),然后设置范围:从1到100,步长1。这样Burp会自动生成1、2、3…100的userId参数。 第三步:点Start Attack(开始攻击),Burp会批量发请求,每个请求用不同的userId。 第四步:看结果:要是某个请求的返回码是200,并且返回了订单数据,说明这个userId的订单能被当前用户访问,存在越权漏洞。
5.2 用Intruder测参数篡改
比如要测status参数的所有可能值,不用手动改,让Burp自动传不同的status: 第一步:把更新订单的请求转到Intruder,标记status参数的位置。 第二步:Payload Type选List(列表),然后把所有可能的恶意值填进去,比如“已退款”“已发货”“已取消”。 第三步:开始攻击,看结果:要是某个恶意值的请求返回200,说明存在参数篡改漏洞。
六、应用场景、优缺点、注意事项
6.1 应用场景
这种安全检测适合所有用RESTful API的项目,比如电商平台(防止用户看别人订单、改价格)、社交APP(防止用户改别人的个人资料)、企业后台(防止普通员工改管理员数据)。开发阶段测,能提前发现漏洞,避免上线后出问题;上线后定期测,能防止新接口加了没做防护。
6.2 技术优缺点
优点:用Burp自动化测,速度快,能覆盖人工容易漏的参数,不用写复杂的测试代码,适合不同基础的开发。缺点:Burp的免费版功能有限,比如Intruder的攻击速度慢;要是接口需要复杂的参数(比如加密的请求),需要手动处理;测试结果需要人工分析,不能自动判断漏洞的严重程度。
6.3 注意事项
第一:测试环境要和生产环境一致,比如JWT密钥、数据库数据,不然测试结果不准。第二:不能用生产环境测,不然会影响真实用户的数据。第三:测试前要备份测试环境的数据,防止测试时把数据改乱。第四:除了Burp,还要结合代码检查,比如用代码扫描工具查有没有没做权限校验的接口。
七、文章总结
RESTful API的安全检测,核心是测“越权”和“参数篡改”,用Burp Suite能快速上手,不管是手动改参数还是自动化批量测,都能覆盖常见的攻击面。开发时要记住两个核心原则:一是不能相信参数里的身份信息(比如userId),要从令牌里拿真实的身份;二是所有参数都要做合法性校验,限制取值范围。提前做安全检测,不仅能避免上线后的风险,还能让项目更稳定,也能提升自己的安全意识。
评论
围绕“RESTful API安全检测实战,利用Burp Suite自动化测试越权与参数篡改漏洞,覆盖常见攻击面”参与讨论