30人参与 • 2025-09-25 • MsSqlserver
在日常开发中,数据库操作几乎是绕不开的环节。很多同学写查询语句的时候,习惯直接用字符串拼接,比如:
string sql = "select * from users where username = '" + username + "' and password = '" + password + "'";
乍一看挺正常,但一旦碰上心怀不轨的攻击者,后果就可能非常严重。这就是我们常说的 sql 注入 问题。
sql 注入的本质就是:
用户的输入被直接拼接到 sql 语句中,没有做任何防护,导致数据库把攻击者的输入当成真正的 sql 指令去执行。
举个最经典的例子:
如果登录接口这样写:
string username = "admin"; string password = "' or '1'='1"; // 攻击者输入的内容 string sql = "select * from users where username='" + username + "' and password='" + password + "'"; system.out.println(sql);
拼接后的 sql 就变成了:
select * from users where username='admin' and password='' or '1'='1'
这一句 or '1'='1' 永远成立,所以攻击者轻轻松松绕过了密码验证,直接登录成功。
别以为这只是理论,现实中因为 sql 注入出问题的案例太多了。常见危害包括:
drop table users; 直接把表删掉。所以在企业开发里,sql 注入算是基础中的基础,必须提前预防。
那我们该怎么防范呢?有几种常见的方式:
preparedstatement 是 jdbc 提供的预编译语句对象。它会先把 sql 模板交给数据库编译好,然后再传入参数。这样参数和 sql 逻辑严格分离,用户输入就不会被当成 sql 指令执行。
demo 代码:
import java.sql.*;
public class safelogindemo {
public static void main(string[] args) throws exception {
string url = "jdbc:mysql://localhost:3306/testdb";
string user = "root";
string pass = "123456";
string inputuser = "admin";
string inputpass = "' or '1'='1";
connection conn = drivermanager.getconnection(url, user, pass);
string sql = "select * from users where username = ? and password = ?";
preparedstatement stmt = conn.preparestatement(sql);
stmt.setstring(1, inputuser);
stmt.setstring(2, inputpass);
resultset rs = stmt.executequery();
if (rs.next()) {
system.out.println("登录成功: " + rs.getstring("username"));
} else {
system.out.println("用户名或密码错误");
}
rs.close();
stmt.close();
conn.close();
}
}
这里无论用户输入什么奇怪的密码,数据库都会把它当成一个普通的字符串参数处理,而不是 sql 逻辑。
在 mybatis 中,有两个写法经常被混淆:${} 和 #{}。
${}:直接拼接字符串,可能导致 sql 注入。#{}:安全的参数绑定,底层会帮你用 preparedstatement。错误写法(容易被注入):
<select id="getuserbyname" resulttype="user">
select * from users where username = '${username}'
</select>
正确写法(推荐使用):
<select id="getuserbyname" resulttype="user">
select * from users where username = #{username}
</select>
这样就算有人传了 ' or '1'='1 这样的输入,也只会作为字符串参数传入,不会破坏 sql 逻辑。
像 hibernate、jpa 这类 orm 框架,通常都已经封装了参数绑定逻辑,默认情况下就能避免注入风险。
比如用 spring data jpa:
public interface userrepository extends jparepository<user, long> {
user findbyusernameandpassword(string username, string password);
}
spring data jpa 底层会自动生成类似 preparedstatement 的语句,所以基本不需要担心 sql 注入问题。
回过头来看,sql 注入的核心原因是 “把用户输入当成 sql 语句的一部分”。
解决的思路就是 “参数化查询”,让 sql 和用户输入严格分离。
落地建议:
preparedstatement。#{} 而不是 ${}。到此这篇关于sql注入的风险与解决方案实战解析的文章就介绍到这了,更多相关sql注入内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论