SQL注入攻击的实现和防止

什么是SQL攻击?

在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL语句片段和我们DAO中的SQL语句组合成一个完整的SQL语句。就会出现一些意想不到的结果。

演示SQL注入攻击:

CREATE TABLE tab_user(
	userid VARCHAR(10) PRIMARY KEY,
	username VARCHAR(20) NOT NULL,
	PASSWORD VARCHAR(20) NOT NULL
);
插入四条数据
INSERT INTO tab_user(userid,username,PASSWORD) VALUES('1','德玛','123');
INSERT INTO tab_user(userid,username,PASSWORD) VALUES('2','信爷','123');
INSERT INTO tab_user(userid,username,PASSWORD) VALUES('3','皇子','123');
INSERT INTO tab_user(userid,username,PASSWORD) VALUES('4','拉克丝','123');
下面通过Java代码来模拟登陆:
public boolean login(String uname, String upwd) {
		Connection conn = null;
		Statement state = null;
		ResultSet set = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/mydb";
			String user = "root";
			String password = "root";
			conn = DriverManager.getConnection(url, user, password);
			state = conn.createStatement();
			String sql = "select * from tab_user where username='"+uname+"' and password='"+upwd+"'";
			set = state.executeQuery(sql);
			System.out.println(sql);
			return set.next();
		} catch (Exception e) {
			throw new RuntimeException("查询错误:"+e);
		}
		finally {
			try {
				if(set!=null)
					set.close();
				if(state!=null)
					state.close();
				if(conn!=null)
					conn.close();
			} catch (Exception e) {
				throw new RuntimeException("关闭错误:"+e);
			}
		}
	}
测试方法:
	@Test
	public void fun3() {
		System.out.println(login("德玛", "123"));
	}
输出结果是:
select * from tab_user where username='德玛' and password='123'
1,德玛,123。说明这样能取到记录,可以登录。
那如果这样写呢?
	@Test
	public void fun3() {
		login("a' or 'a'='a", "a' or 'a'='a");
	}
输入结果是:
select * from tab_user where username='a' or 'a'='a' and password='a' or 'a'='a'
1,德玛,123
2,信爷,123
3,皇子,123
4,拉克丝,123
四条记录全部取到,如果是登陆的话是不是很可怕。
原因就是输入了一些sql的语句符合和现在Java代码中写的sql语句的符号组合了,形成了一条新的并且作用效果并不是预期的语句。

解决方法是:

只要阻止输入[or ']这类字符就行。(这个方法可以在页面和代码中实现)
还有就是分步校验。下面演示:
public void login2(String uname,String upwd){
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			Class.forName("com.mysql.jdbc.Driver");
			String url="jdbc:mysql://localhost:3306/mydb";
			String user = "root";
			String password = "root";
			conn = DriverManager.getConnection(url,user,password);
			stmt = conn.createStatement();
			String sql = "select password from tab_user where username='"+ uname+"'";
			rs = stmt.executeQuery(sql);
			if(rs.next()){
				if(upwd.equals(rs.getString(1))){
					System.out.println("登陆成功");
				}else{
					System.out.println("登陆失败");
				}
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			try{
				if(rs!=null) rs.close();
				if(stmt!=null) stmt.close();
				if(conn!=null) conn.close();
			}catch(Exception e){
				throw new RuntimeException(e);
			}
		}
	}
先测试正确的
	@Test
	public void fun3() {
		login2("拉克丝","123");
	}
输出结果:登陆成功
在测试使用违法的
	@Test
	public void fun3() {
		login2("a' or 'a'='a", "a' or 'a'='a");
	}
输出结果:登陆失败。SQL注入失败。可以

还有一种方法是使用PreparedStatement也能实现,但它不仅能防止SQL注入。它主要作用是提高了代码的可读性和可维护性。最主要是提高了运行效率。下面示范:
public void login3(String uname,String upwd){
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/mydb";
			String user = "root";
			String password = "root";
			conn = DriverManager.getConnection(url,user,password);
			String sql = "select * from tab_user where username=? and password=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, uname);//设置第一个问号的值
			pstmt.setString(2, upwd);//设置第二个问号的值
			rs= pstmt.executeQuery();//注意这里是无参的方法
			if(!rs.next()){//如果没有满足条件的记录
				System.out.println("登陆失败");
			}else{
				rs.beforeFirst();
				while(rs.next()){
					System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3));
				}
			}
			
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			try{
				if(rs!=null) rs.close();
				if(pstmt!=null) pstmt.close();
				if(conn!=null) conn.close();
			}catch(Exception e){
				throw new RuntimeException(e);
			}
		}
		
	}


演示测试结果:

	@Test
	public void fun3() {
		login3("a' or 'a'='a", "a' or 'a'='a");
	}
登陆失败
	@Test
	public void fun3() {
		login3("信爷","123");
	}
2,信爷,123。
可以防止

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值