数据类型检查,sql执行前,要进行数据类型检查,如果是邮箱,参数就必须是邮箱的格式,如果是日期,就必须是日期格式;

只要是有固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。

如果上述例子中id是int型的,效果会怎样呢?无法注入,因为输入注入参数会失败。比如上述中的name字段,我们应该在用户注册的时候,就确定一个用户名规则,比如5-20个字符,只能由大小写字母、数字以及汉字组成,不包含特殊字符。此时我们应该有一个函数来完成统一的用户名检查。不过,仍然有很多场景并不能用到这个方法,比如写博客,评论系统,弹幕系统,必须允许用户可以提交任意形式的字符才行,否则用户体验感太差了。

2、过滤特殊符号


3、绑定变量,使用预编译语句


五、预编译

=====

(一)预编译是什么


1、执行sql一般分为三步:

  • 语法和语义解析

  • 优化sql语句,制定执行计划

  • 执行sql,返回结果

2、PreparedStatement

很多情况下,我们的一条sql语句可能被反复执行,或每次执行的时候只有个别的值不同,比如query的where子句值不同,update的set子句值不同,insert的value值不同。

如果每次都需要经过上面的语法语义解析、语句优化、制定执行计划等操作,效率显而易见,很低。

所谓预编译就是将这些语句中的值用占位符替代,可以视为将sql语句模板化或者参数化,一般称这类语句叫PreparedStatement。

预编译语句的优势在于:一次编译、多次执行,省去了解析优化等繁琐过程,此外预编译语句能防止sql注入。

(二)预编译的sql语句处理


预编译语句PreparedStatement是java.sql中的一个接口,它是Statement的子接口。通过Statement对象执行sql语句时,需要将sql语句发送给DBMS,由DBMS首先进行编译后再执行。预编译语句和Statement不同,在创建PreparedStatement对象时就指定了sql语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的sql语句,而不需要像其它sql语句那样首先将其编译。预编译的sql语句处理性能稍微高于普通的传递变量的方法。

数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过DBMS访问数据库中的数据,数据库管理员也通过DBMS进行数据库的维护工作。它可以支持多个应用程序和用户去建立,修改和访问数据库。大部分DBMS提供数据定义语言DDL和数据操作语言DML,供用户定义数据库的模式结构与权限约束,实现对数据的追加、删除等操作。

(三)预编译语句的作用


1、提高效率

当需要对数据库进行数据插入、更新或删除的时候,程序会发送整个sql语句给数据库处理和执行。数据库处理一个sql语句,需要完成解析sql语句、检查语法和语义以及生产代码,处理时间要比执行语句所需要的时间长。预编译语句在创建的时候就已经是将指定的sql语句发送给了DBMS,完成了解析、检查、编译等工作。因此,当一个sql语句需要执行多次时,使用预编译语句可以减少处理时间,提高执行效率。

2、提高安全性

例如上面的sql注入攻击实例,登录验证,根本不用,直接进,加入又在后面追加上drop table student;我靠,防不胜防,数据表直接没了,很多数据库是不会成功的,但也有很多数据库可以使用这些语句执行,而如果使用预编译语句,传入的任何内容就不会和原来的语句发生任何匹配的关系。只要全使用预编译语句,就用不着对传入的数据做任何过虑,而如果使用普通的statement,有可能要对drop,等做费尽心机的判断和过虑。

(四)预编译语句的使用


1、创建PreparedStatement对象

String sql = “insert into studentvalues(?,?,?,?)”;//组织一条含有参数的SQL语句

PreparedStatement ps = conn.prepareStatement(sql);

insert into student values(?,?,?,?);//它已发送给DBMS,并为执行作好了准备。

2、传递IN参数

在执行 PreparedStatement 对象之前,必须设置每个 ? 参数的值。这可通过调用 setXXX 方法来完成,其中 XXX 是与该参数相应的类型。

(五)为什么PreparedStatement可以防止sql注入


Preparement样式为

select * from student where id=? and name=?

该SQL语句会在得到用户的输入之前先用数据库进行预编译,这样的话不管用户输入什么id和用户名的判断始终都是并的逻辑关系,防止了SQL注入。

简单总结,参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

,不会影响行进路线,无非跑的快点与慢点的区别。

===================================================================================================================================================================================================

六、mybatis与sql注入

===============

<?xml version="1.0" encoding="UTF-8" ?>

select * from student where id = ${stuNo}

insert into student(id,name,age) values (#{id},#{name},#{age})

(一)mybatis中#和$的区别


1、#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。

如:where id=#{id},如果传入的值是1,那么解析成sql时的值为where id=“1”, 如果传入的值是id,则解析成的sql为where id=“id”。

2、$将传入的数据直接显示生成在sql中。

如:where id=${id},如果传入的值是1,那么解析成sql时的值为where username=1;

如果传入的值是;drop table user;,则解析成的sql为:select * from student where id=1;drop table student;

3、#方式能够很大程序防止sql注入,$方式无法防止sql注入。

更多推荐

【MyBatis 1】SQL注入,springboot基础教程