【2025】web安全 - SQL注入漏洞,从零基础到精通,收藏这篇就够了! - 实践
.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
SQL注入漏洞是Web层面最高危的漏洞之一。
SQL注入原理
下图是一个登录表单,输入正确的账号和密码后,页面会跳转到详情页;否则,提示账号或密码错误。
现在我们使用一个比较特殊的用户“’ or 1=1 – ”,密码随意设置,发现也是可以正常登录的,如下图所示。
为什么随意输入密码也可以进入详情页?进入数据库中查找,也没有“’ or 1=1 – ”这个用户。难道是程序出现BUG了吗?下面我们来详细分析程序,看看问题出现在哪里?
经过分析发现,登录请求到达服务器之后,会调用下述的方法处理:
async function login(ctx, next) {
const {
username, password,
} = ctx.request.body
const sql = `select count(*) from users where username='${username}' and password='${password}'`
const exists = await db.query(sql)
.then((results) => {
return results[0] && results[0]['count(*)']
})
ctx.status = exists ? 200 : 401
ctx.body = {
message: exists ? 'Login successful' : 'Invalid username or password',
}
return next()
}
我们第8
行代码处插入断点,重新使用账号“’ or 1=1 – ”登录并跟踪SQL语句,发现最后执行SQL语句为:
select count(*) from users where username='' or 1=1 -- ' and password='111111'
此时的password
已经被注释了,而且username='' or 1=1
永远为真。很显然,返回的数据条目大于0
,所以可以顺利通过认证,登录成功。
这就是一次简单的SQL注入过程,如果不加以防范,可能会对系统造成巨大的危害。比如,在账号处输入:
“’ or 1=1; drop table users – ”
如果此时开启了多语句执行功能,这里会直接删除users
表。
由此可知,SQL注入漏洞的形成原因就是:用户输入的数据被SQL解析器执行。
防止SQL注入
SQL注入攻击问题最终归于用户非法输入被“准确地”送达后端,并被SQL解释器“准确地”执行。所以,要有效的防护SQL注入,我们需要从代码上入手,避免直接拼接SQL查询语句。
输入数据校验
对用户输入的数据进行校验。比如:
- 限制账号只能用字母、数字、下划线组成。
- 对数据类型进行严格校验
特殊字符转义(不推荐)
使用\
对特殊字符进行转义,防止恶意字符(如'
)对SQL语句造成破坏。例如,用户输入账号为“’ or 1=1 – ”,转义后SQL语句如下:
SELECT count(*) from users where username='\' or 1=1 -- ' and password=111111
这样,转义后的输入不会干扰SQL查询的结构,避免了 SQL 注入的直接执行。但是,转义并不能解决二次注入的问题。
所谓的二次注入,即攻击者在一个查询中注入恶意代码,并将其存储在数据库中。这个数据本身可能是无害的,但在系统的后续查询中,它被再次使用,从而导致恶意代码执行。
假设有一个注册表单,系统对账号进行转义。当用户输入“aric’ or 1=1 – ”时,即使对输入数据做了转义处理(“aric\’ or 1=1 – ”),但这仍是个恶意数据,可能在后续的查询中被利用。例如,在用户登录时,系统执行了下述查询:
SELECT * FROM users WHERE username = 'aric' or 1=1 -- ' AND password = ''
;
它依然会被执行,从而能够绕过身份认证。
参数化查询 / 预处理语句
是防止 SQL 注入的最有效方法。它不仅自动处理输入的转义,还能确保每个输入都是作为数据传递给数据库,而不是作为查询的一部分。
例如,在mysql2
中使用:
const login = async (ctx, next) => {
const {
username, password,
} = ctx.request.body
const sql = `select count(*) from users where username=? and password=?`
const exists = await db.query(sql, [username, password])
.then((results) => {
return results[0] && results[0]['count(*)']
})
more...
}
使用ORM
许多现代框架和库提供 ORM(对象关系映射)功能,它们通过封装 SQL 查询和数据库操作,自动处理 SQL 注入的防护工作。ORM 提供了更高层次的抽象,减少了手动拼接 SQL 查询的机会。
例如,Node.js的一个ORM库Sequelize
。
使用存储过程
存储过程可以将SQL查询封装在数据库内部,减少外部对 SQL 查询的直接操作。使用存储过程时,用户输入的内容不会直接插入到SQL语句中,从而减少了SQL注入的风险。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享
1.成长路线图&学习规划
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享
2.视频教程
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享
3.SRC&黑客文籍
大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录
SRC技术文籍:
黑客资料由于是敏感资源,这里不能直接展示哦!
4.护网行动资料
其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!
5.黑客必读书单
**
**
6.面试题合集
当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
更多内容为防止和谐,可以扫描获取~
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取