目录
JDBC的简单使用
向JDBC注入攻击
防止注入攻击
自建JDBC工具类
自建工具类优化--使用配置文件
使用数据库连接池优化工具类
JDBC的简单使用
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.Driver; 5 import java.sql.DriverManager; 6 import java.sql.DriverPropertyInfo; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 import java.sql.Statement; 10 11 12 /*JDBCsun公司提供的一套标准数据库操作规范 13 * JDBC使用步骤 14 * 1 注册驱动--告诉JVM使用的是哪一个数据库 15 * 2 获得连接--使用JDBC中的类完成对MySQL数据库的连接 16 * 3 获得语句执行平台--通过连接对象获取SQL语句1的执行者对象 17 * 4 执行sql语句--使用执行者对象向数据库执行SQL语句,并获取执行后的结果 18 * 5 处理结果 19 * 6 释放资源 20 * ----------在使用之前一定要先导入jar包 21 */ 22 23 public class Main{ 24 public static void main(String[] args) throws ClassNotFoundException, SQLException { 25 //1 注册驱动,但查看源码发现这样会注册两次 26 //DriverManager.registerDriver(new Driver()); 27 //使用反射技术注册,在这里类名可能找不到因此抛出类名查不到的异常 28 Class.forName("com.mysql.jdbc.Driver"); 29 30 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名 31 String url ="jdbc:mysql://localhost:3306/mybase"; 32 String username="root";//用户名 33 String password="123";//密码 34 //连接,可能连接不到抛出SQL异常 35 Connection con =DriverManager.getConnection(url, username,password); 36 37 //3 获得语句执行平台,通过数据库连接对象获得SQL语句的执行者对象,注意导包为sql的包 38 Statement stat=con.createStatement(); 39 //查询语句 40 String sql ="Select * from titles"; 41 42 //4 调用执行者对象方法,执行SQL语句获取结果集 43 ResultSet rs=stat.executeQuery(sql); 44 //5 处理结果集 45 while(rs.next()){ 46 System.out.println(rs.getString("emp_no")+" "+rs.getString("title")); 47 } 48 49 //6 释放资源 50 rs.close(); 51 stat.close(); 52 con.close(); 53 } 54 }
向JDBC注入攻击
创建数据表
1 CREATE TABLE users( 2 username VARCHAR(20), 3 PASSWORD VARCHAR(10) 4 ); 5 6 INSERT INTO users VALUES('a','1'),('b','2');
待注入攻击的代码:
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.Driver; 5 import java.sql.DriverManager; 6 import java.sql.DriverPropertyInfo; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 import java.sql.Statement; 10 import java.util.Scanner; 11 12 13 /*MySQL注入攻击 14 * 用户登录案例 15 */ 16 17 public class Main{ 18 public static void main(String[] args) throws ClassNotFoundException, SQLException { 19 Class.forName("com.mysql.jdbc.Driver"); 20 21 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名 22 String url ="jdbc:mysql://localhost:3306/mybase"; 23 String username="root";//用户名 24 String password="123";//密码 25 Connection con =DriverManager.getConnection(url, username,password); 26 Statement stat=con.createStatement(); 27 //查询语句 28 Scanner sc=new Scanner(System.in); 29 String user=sc.next(); 30 String pass=sc.next(); 31 String sql ="Select * from users where username= '"+user+"' and password= '"+pass+"'"; 32 33 //4 调用执行者对象方法,执行SQL语句获取结果集 34 ResultSet rs=stat.executeQuery(sql); 35 System.out.println(sql); 36 //5 处理结果集 37 while(rs.next()){ 38 System.out.println(rs.getString("username")+" "+rs.getString("password")); 39 } 40 41 //6 释放资源 42 rs.close(); 43 stat.close(); 44 con.close(); 45 } 46 }
代码运行结果:
攻击的原理:
利用SQL语句:Select * from users where username= 'a' and password= '1'or'1=1',这样由于最后一个是或运算那么就会显示出来所有的数据,因此在输入时只要想办法凑成这样的形式就可以了。
输入:aa 12'or'1=1 这样便可以完成攻击,即使输入的用户名不对也可以正常登陆。
防止注入攻击
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.Driver; 5 import java.sql.DriverManager; 6 import java.sql.DriverPropertyInfo; 7 import java.sql.PreparedStatement; 8 import java.sql.ResultSet; 9 import java.sql.SQLException; 10 import java.sql.Statement; 11 import java.util.Scanner; 12 13 /*MySQL防止注入攻击--采用statement的子类preparedstatement 14 * 还可以用占位符实现增删改查等操作 15 */ 16 17 public class Main{ 18 public static void main(String[] args) throws ClassNotFoundException, SQLException { 19 Class.forName("com.mysql.jdbc.Driver"); 20 21 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名 22 String url ="jdbc:mysql://localhost:3306/mybase"; 23 String username="root";//用户名 24 String password="123";//密码 25 Connection con =DriverManager.getConnection(url, username,password); 26 27 //查询语句 28 Scanner sc=new Scanner(System.in); 29 String user=sc.next(); 30 String pass=sc.next(); 31 //用?占位符代替参数 32 String sql ="Select * from users where username=? and password= ?"; 33 PreparedStatement pds=con.prepareStatement(sql); 34 pds.setObject(1, user); 35 pds.setObject(2, pass); 36 //4 调用执行者对象方法,执行SQL语句获取结果集 37 ResultSet rs=pds.executeQuery(); 38 System.out.println(sql); 39 //5 处理结果集 40 while(rs.next()){ 41 System.out.println(rs.getString("username")+" "+rs.getString("password")); 42 } 43 44 //6 释放资源 45 rs.close(); 46 pds.close(); 47 con.close(); 48 } 49 }
自建JDBC工具类
JDBCUtils.class文件
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 9 public class JDBCUtils { 10 private JDBCUtils(){} 11 private static Connection con; 12 13 static{ 14 try { 15 Class.forName("com.mysql.jdbc.Driver"); 16 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名 17 String url ="jdbc:mysql://localhost:3306/mybase"; 18 String username="root";//用户名 19 String password="123";//密码 20 con =DriverManager.getConnection(url, username,password); 21 } catch (Exception e) { 22 throw new RuntimeException(e+"数据库连接失败!"); 23 } 24 } 25 //定义静态方法,返回数据库的连接对象 26 public static Connection getConnection(){ 27 return con; 28 } 29 30 //释放资源 31 public static void close(Connection con,Statement stat){ 32 if(stat!=null){ 33 try { 34 stat.close(); 35 } catch (SQLException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 } 40 41 if(con!=null){ 42 try { 43 con.close(); 44 } catch (SQLException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 } 49 } 50 //重载,关闭结果集 51 public static void close(Connection con,Statement stat,ResultSet rs){ 52 //注意释放的顺序 53 if(rs!=null){ 54 try { 55 rs.close(); 56 } catch (SQLException e) { 57 // TODO Auto-generated catch block 58 e.printStackTrace(); 59 } 60 } 61 62 if(stat!=null){ 63 try { 64 stat.close(); 65 } catch (SQLException e) { 66 // TODO Auto-generated catch block 67 e.printStackTrace(); 68 } 69 } 70 71 if(con!=null){ 72 try { 73 con.close(); 74 } catch (SQLException e) { 75 // TODO Auto-generated catch block 76 e.printStackTrace(); 77 } 78 } 79 } 80 }
测试代码:
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import Test.JDBCUtils; 8 9 public class JDBCTset { 10 public static void main(String[] args) throws SQLException { 11 Connection con =JDBCUtils.getConnection(); 12 PreparedStatement pst=con.prepareStatement("SELECT * FROM titles"); 13 ResultSet rs =pst.executeQuery(); 14 while(rs.next()){ 15 System.out.println(rs.getString("title")); 16 } 17 //释放资源 18 JDBCUtils.close(con, pst); 19 } 20 }
自建工具类优化--使用配置文件
优化代码
1 package Test; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 /*在前面的代码中由于数据库用户名,密码直接在静态代码块中,相当于写死了代码,不容易修改 7 * 因此采用properties配置文件,方便后期维护。配置文件建议放在src下,方便自动拷贝bin目录下 8 * 9 */ 10 11 import java.sql.Connection; 12 import java.sql.DriverManager; 13 import java.sql.ResultSet; 14 import java.sql.SQLException; 15 import java.sql.Statement; 16 import java.util.Properties; 17 18 public class JDBCUtils { 19 private JDBCUtils(){} 20 private static Connection con; 21 private static String driverClass; 22 private static String url; 23 private static String username; 24 private static String password; 25 //放到静态代码块中保证读取配置文件,获取连接只执行一次 26 static{ 27 try{ 28 readConfig(); 29 //反射 30 Class.forName(driverClass); 31 con=DriverManager.getConnection(url,username,password); 32 }catch(Exception e){ 33 throw new RuntimeException("数据库连接失败!"); 34 } 35 36 } 37 38 private static void readConfig() throws IOException{ 39 //通过字节流,使用类加载器读取配置文件的内容 40 InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("database.properties"); 41 Properties pro = new Properties(); 42 pro.load(in); 43 driverClass=pro.getProperty("driverClass"); 44 url = pro.getProperty("url"); 45 username=pro.getProperty("username"); 46 password=pro.getProperty("password"); 47 } 48 49 //定义静态方法,返回数据库的连接对象 50 public static Connection getConnection(){ 51 return con; 52 } 53 54 //释放资源 55 public static void close(Connection con,Statement stat){ 56 if(stat!=null){ 57 try { 58 stat.close(); 59 } catch (SQLException e) { 60 // TODO Auto-generated catch block 61 e.printStackTrace(); 62 } 63 } 64 65 if(con!=null){ 66 try { 67 con.close(); 68 } catch (SQLException e) { 69 // TODO Auto-generated catch block 70 e.printStackTrace(); 71 } 72 } 73 } 74 //重载,关闭结果集 75 public static void close(Connection con,Statement stat,ResultSet rs){ 76 //注意释放的顺序 77 if(rs!=null){ 78 try { 79 rs.close(); 80 } catch (SQLException e) { 81 // TODO Auto-generated catch block 82 e.printStackTrace(); 83 } 84 } 85 86 if(stat!=null){ 87 try { 88 stat.close(); 89 } catch (SQLException e) { 90 // TODO Auto-generated catch block 91 e.printStackTrace(); 92 } 93 } 94 95 if(con!=null){ 96 try { 97 con.close(); 98 } catch (SQLException e) { 99 // TODO Auto-generated catch block 100 e.printStackTrace(); 101 } 102 } 103 } 104 }
测试代码
1 package Test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import Test.JDBCUtils; 8 9 public class JDBCTset { 10 public static void main(String[] args) throws SQLException { 11 Connection con =JDBCUtils.getConnection(); 12 //当能输出数据库连接时边说用工具类正常了 13 System.out.println(con); 14 //由于是简单的测试,因此不用释放资源 15 //JDBCUtils.close(con, pst); 16 } 17 }
使用数据库连接池优化工具类
优化代码:
1 package Test; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.util.Properties; 5 6 import javax.sql.DataSource; 7 8 /* 9 * JDBC连接池工具类,使用连接池专门负责数据库的连接 10 * JDBC连接池简化了sql语句中的增删改查操作,方便代码编写 11 */ 12 import org.apache.commons.dbcp.BasicDataSource; 13 14 15 public class JDBCUtils { 16 private JDBCUtils(){} 17 private static String driverClass; 18 private static String url; 19 private static String username; 20 private static String password; 21 private static BasicDataSource datasource =new BasicDataSource(); 22 //放到静态代码块中保证读取配置文件,获取连接只执行一次 23 static{ 24 try { 25 readConfig(); 26 //数据库连接配置 27 datasource.setDriverClassName(driverClass); 28 datasource.setUrl(url); 29 datasource.setUsername(username); 30 datasource.setPassword(password); 31 //对象连接池中的数量配置,这些配置可以不用配置的 32 datasource.setInitialSize(10);//初始化的连接数 33 datasource.setMaxActive(8);//最大连接数 34 datasource.setMaxIdle(5);//最大空闲数 35 datasource.setMinIdle(1);//最小空闲数 36 } catch (IOException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 } 41 42 private static void readConfig() throws IOException{ 43 //通过字节流,使用类加载器读取配置文件的内容 44 InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("database.properties"); 45 Properties pro = new Properties(); 46 pro.load(in); 47 driverClass=pro.getProperty("driverClass"); 48 url = pro.getProperty("url"); 49 username=pro.getProperty("username"); 50 password=pro.getProperty("password"); 51 } 52 53 //定义静态方法,返回数据库的连接对象 54 public static DataSource getDataSource(){ 55 return datasource; 56 } 57 }
测试代码:
1 package Test; 2 3 import java.sql.SQLException; 4 import java.util.List; 5 6 import org.apache.commons.dbutils.QueryRunner; 7 import org.apache.commons.dbutils.handlers.ArrayHandler; 8 import org.apache.commons.dbutils.handlers.ArrayListHandler; 9 10 public class JDBCTset { 11 private static QueryRunner qr=new QueryRunner(JDBCUtils.getDataSource()); 12 13 public static void main(String[] args) throws SQLException { 14 String sql="select * from titles"; 15 //ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。这是dbutils所特有的 16 List<Object[]> list =qr.query(sql, new ArrayListHandler()); 17 for(Object[] objs:list){ 18 for(Object obj:objs) 19 System.out.print(obj+" "); 20 System.out.println(); 21 } 22 } 23 24 }
0