一、今日工作内容
1、知识点回顾
-
java
操作数据库的原生方式:JDBC注意:我们需要在使用完connection连接后,需要关闭连接释放资源
-
java
中使用MyBatis框架操作数据库1.学会使用xml配置方式进行数据库开发 2.学会使用注解配置方式进行数据库开发 提示:对于第三方配置或者类,我们尽量使用注解xml配置方式进行开发
2、新知识点学习
-
硬编码和软编码
硬编码: 硬编码就是直接将数据写入到代码中进行编译开发。在java开发中,如果我们没有使用MyBatis框架或者其它ORM框架前,我们使用原始的JDBC操作数据库时候,我们直接将sql语句嵌入到JDBC代码中;再比如jsp开发过程中,我们将前端html代码与java代码进行耦合。以上两种情况都是硬编码。 硬编码耦合度高,不利于模块拆分然后进行协同开发。同时由于硬编码是直接将操作数据的代码片段,或者读取配置文件片段嵌入到代码中,如果我们是C/S开发,我们每次更新数据操作方式和更新配置文件位置时候,都需要重新部署项目,同时客服端也需要重新安装软件,非常不友好。
软编码: 软编码就是讲数据和源代码进行解耦,提高程序开发效率。对于上文中出现的第一个问题,我们可以使用MyBatis框架,将SQL语句写到MyBatis框架中的配置文件中,这样就可以将SQL语句和底层代码进行分离,就只暴露出SQL语句供程序员编写。 对于上文中的第二个问题,我们可以采用MVC框架的设计模式,将jsp拆分为前端HTML代码和后端的逻辑代码,这样有利于提高程序的开发效率和测试效率。
二、明日工作计划
-
java程序开发常用设计模式之代理模式(动态代理和静态代理模式)的原理和使用
-
回顾MyBatis框架中连接池的使用和事务管理
-
回顾MyBatis框架中一对一,一对多查询
-
回顾Spring框架基础知识
三、问题和思考
1、preparedStatement代替statement
- 在使用原生JDBC操作数据库时候,要注意我们需要采用preparedStatement代替statement来获取SQL语句。$color{red}这样我们可以防止SQL注入。 $
关系:PreparedStatement继承自Statement,都是接口
区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高
-
preparedStatement (预编译SQL语句)
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; public class PreparedStatementTest { public static void main(String[] args) { test_autoCommit(); } public static void test_autoCommit() { String driver="oracle.jdbc.driver.OracleDriver"; String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user="briup"; String password="briup"; Connection conn=null; PreparedStatement ps=null; try { //1、注册驱动 Class.forName(driver); //2、获取连接 conn= DriverManager.getConnection(url, user, password); //System.out.println(conn); //3、创建prepareStatement对象 String sql="insert into lover values(?,?,?)"; ps=conn.prepareStatement(sql); //4、执行sql语句 ps.setInt(1,21);//代表设置给第一个?号位置的值为Int类型的21 ps.setString(2,"hello");//代表设置给第二个?号位置的值为String类型的hello java.util.Date utilDate=new java.util.Date();//进行类型转换,由util类型的date转化为sql类型的 ps.setDate(3, new java.sql.Date(utilDate.getTime())); //ps.execute();//执行 System.out.println(ps.execute());//执行表输出返回的结果,结果为false,因为没有返回的结果集 //5、处理结果集 } catch (Exception e) { e.printStackTrace(); } finally{ //6、关闭资源 try { if(ps!=null)ps.close(); } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null)conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
-
statement(字符串拼接构成SQL语句,可能会产生SQL注入问题)
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class StatementTest { public static void main(String[] args) { test_autoCommit(); } public static void test_autoCommit() { String driver="oracle.jdbc.driver.OracleDriver"; String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user="briup"; String password="briup"; Connection conn=null; Statement stat=null; try { //1、注册驱动 Class.forName(driver); //2、获取连接 conn= DriverManager.getConnection(url, user, password); conn.setAutoCommit(false); //System.out.println(conn); //3、创建statement对象 stat=conn.createStatement(); //4、执行sql语句 String sql="insert into lover values(22,'suxingxing',to_date('21-9-2016','dd-mm-yyyy'))"; //注意格式 // stat.execute(sql); System.out.println(stat.execute(sql)); //返回值为false,因为同样没有ResultSet返回集 conn.commit(); //5、处理结果集 } catch (Exception e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally{ //6、关闭资源 try { if(stat!=null)stat.close(); } catch (SQLException e) { e.printStackTrace(); } try { if(conn!=null)conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
2、什么是SQL注入?
-
SQL注入
就是通过把SQL命令插入到Web表单提交或页面请求url的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
-
实战举例
有个登陆框如下:
可以看到除了账号密码之外,还有一个公司名的输入框,根据输入框的形式不难推出SQL的写法如下:SELECT * From table_name WHERE name=‘XX’ and password=‘YY’ and corporate=‘ZZ’
如果我们按照上式这样书写SQL语句,没有什么问题。
但是如果我们账号,密码都不写,同时 最后个字段里面我们填写特殊的字符串 ‘ or 1=1--
则最后生成的SQL语句:
SELECT * From table_name WHERE name=’’ and password=’’ and corporate=’’ or 1=1-’
-
分析
从代码可以看出,前一半单引号被闭合,后一半单引号被 “–”给注释掉,中间多了一个永远成立的条件“1=1”,这就造成任何字符都能成功登录的结果。
-
注意
不要以为在输入框做个检查就够了,不要忘记了,我们web提交表单,是可以模拟url直接访问过去,绕开前端JS代码检查。因此,对于后端业务,我们一定要认为所有数据从前端穿过来的数据都是不安全的,我们获取到数据后的第一步操作就是校验数据。
-
解决SQL注入
- 前端检查用户输入数据的合法性(不能解决SQL注入问题,但是可以提高用户的体验度);
- 后端检查用户输入数据的合法性;
- 将用户的登录名、密码等数据加密保存(这一步骤相当重要,可以避免由于其它原因导致数据库数据泄露造成信息泄露,推荐使用uuid加密);
- 预处理SQL(preparedStatement处理方式)。
- 使用存储过程实现查询,虽然不推荐,但也是一个方法。
-
使用预处理SQL解决SQL注入
是因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了!
具体像这样。例如刚刚那条SQL: SELECT * From table_name WHERE name=’’ and password=’’ and corporate=’’ or 1=1-’ 开启预编译执行SQL的时候,则不会这么处理。会当成一个属性值。什么意思。随便你怎么加,都是一个值。也就是说,如果中间有产生歧义的,都将被处理掉,最后执行相当于是这样: SELECT * From table_name WHERE name=’’ and password=’’ and corporate="'or 1=1–"