java防sql注入 策略_java 最新sql注入原因以及预防方案(易理解)

本文详细介绍了SQL注入的原理、演示了注入案例,并重点讲解了Java中如何防止SQL注入,尤其是使用PreparedStatement的方式,包括其工作原理和源码分析。建议在前后端都进行参数校验以增强安全性。
摘要由CSDN通过智能技术生成

前沿

在现有的框架中sql防注入已经做得很好了,我们需要做的就是尽量不要使用sql拼接调用

java sql注入原因以及预防方案(易理解)

1. SQL注入

1.1 原理

SQL注入是通过客户端的输入把SQL命令注入到一个应用的数据库中,从而执行恶意的SQL语句。

1.2 演示

1.2.1 案例1

有一个登录框,需要输入用户名和密码,然后我们的密码输入 'or '123' = '123 这样的。我们在查询用户名和密码是否正确的时候,本来执行的sql语句是:select * from user where username = '' and password = ''. 这样的sql语句,现在我们输入密码是如上这样的,然后我们会通过参数进行拼接,拼接后的sql语句就是:

select * from user where username = '' and password = ' ' or '123' = '123 '; 这样的了,那么会有一个or语句,只要这两个有一个是正确的话,就条件成立,因此 123 = 123 是成立的。因此验证就会被跳过。这只是一个简单的列子,

1.2.2 案例2

密码比如是这样的:'; drop table user;, 这样的话,那么sql命令就变成了:

select * from user where username = '' and password = ''; drop table user;' , 那么这个时候我们会把user表直接删除了。

1.3 防范

1.3.1 前端前端表单进行参数格式控制;

1.3.2 后端我们可以使用预编译语句(PreparedStatement,这 样的话即使我们使用sql语句伪造成参数,到了服务端的时候,这个伪造sql语句的参数也只是简单的字符,并不能起到攻击的作用。

使用正则表达式过滤传入的参数

注意: 永远也不要把未经检查的用户输入的值直接传给数据库java中的验证字符串是否包含sql的判断package cn.javanode.thread;

import java.util.regex.Pattern;

/**

* @author xgt(小光头)

* @version 1.0

* @date 2021-1-8 11:48

*/

public class CheckSqlDemo {

/**正则表达式**/

private static String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"

+ "(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";

private static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);

private static boolean isValid(String str) {

if (sqlPattern.matcher(str).find())

{

System.out.println("未能通过过滤器:str=" + str);

return false;

}

return true;

}

public static void main(String[] args) {

System.out.println(isValid("tongji_user_add"));

}

}

补充

PreparedStatement是如何防止SQL注入的?

1. 拼接参数(sql注入)Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

PreparedStatement preparedStatement = connection.prepareStatement(sql);

String param = "'test' or 1=1";

String sql = "select file from file where name = " + param; // 拼接SQL参数

ResultSet resultSet = preparedStatement.executeQuery();

System.out.println(resultSet.next());

输出结果为true,DB中执行的SQL为-- 永真条件1=1成为了查询条件的一部分,可以返回所有数据,造成了SQL注入问题

select file from file where name = 'test' or 1=1

2. setString (防注入)Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

PreparedStatement preparedStatement = connection.prepareStatement(sql);

preparedStatement.setString(1,account);//设置参数

preparedStatement.setString(2,password);

ResultSet resultSet = preparedStatement.executeQuery();//执行查询sql,获取结果集

输出结果为false,DB中执行的SQL为select file from file where name = '\'test\' or 1=1'

我们可以看到输出的SQL是把整个参数用引号包起来,并把参数中的引号作为转义字符,从而避免了参数也作为条件的一部分

3. 源码分析

结论preparedStatement.setString 会判断当前参数的符号是否需要转义,是的话加的转义符

如果不需要,则直接加上引号

4bc5bce20add877da1b37e39abe6e70f.png//完整代码

public void setString(int parameterIndex, String x) throws SQLException {

synchronized (checkClosed().getConnectionMutex()) {

// if the passed string is null, then set this column to null

if (x == null) {

setNull(parameterIndex, Types.CHAR);

} else {

checkClosed();

int stringLength = x.length();

if (this.connection.isNoBackslashEscapesSet()) {

// Scan for any nasty chars

// 判断是否需要转义

boolean needsHexEscape = isEscapeNeededForString(x, stringLength);

if (!needsHexEscape) {

byte[] parameterAsBytes = null;

StringBuilder quotedString = new StringBuilder(x.length() + 2);

quotedString.append('\'');

quotedString.append(x);

quotedString.append('\'');

if (!this.isLoadDataQuery) {

parameterAsBytes = StringUtils.getBytes(quotedString.toString(), this.charConverter, this.charEncoding,

this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), getExceptionInterceptor());

} else {

// Send with platform character encoding

parameterAsBytes = StringUtils.getBytes(quotedString.toString());

}

setInternal(parameterIndex, parameterAsBytes);

} else {

byte[] parameterAsBytes = null;

if (!this.isLoadDataQuery) {

parameterAsBytes = StringUtils.getBytes(x, this.charConverter, this.charEncoding, this.connection.getServerCharset(),

this.connection.parserKnowsUnicode(), getExceptionInterceptor());

} else {

// Send with platform character encoding

parameterAsBytes = StringUtils.getBytes(x);

}

setBytes(parameterIndex, parameterAsBytes);

}

return;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值