SQL注入攻击是黑客攻击数据库常用的手段之一。随着B/S模式应用程序开发的发展,越来越多的程序员使用这种模式来编写应用程序。但是,由于程序员的水平和经验参差不齐,相当一部分程序员在编写代码时并没有判断用户输入数据的合法性,使得应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果获取一些自己想要获取的数据。这就是所谓的SQLInjection,即SQL注入。1.背景如果某大学开发了一个在线课程系统,要求学生选课后完成学业,数据库中有一个表course,里面存储了每个学生的选课信息和完成情况。具体设计如下:数据如下:本系统以mysql为数据库,使用Jdbc进行数据库相关操作。系统提供了查询学生课程完成状态的功能,代码如下。@RestControllerpublicclassController{@AutowiredSqlInjectsqlInject;@GetMapping("list")publicListcourseList(@RequestParam("studentId")StringstudentId){Listorders=sqlInject.orderList(studentId);returnorders;}}@ServicepublicclassSqlInject{@AutowiredprivateJdbcTemplatejdbcTemplate;publicListorderList(StringstudentId){Stringsql="selectid,course_id,student_id,statusfromcoursewherestudent_id="+studentId;returnjdbcTemplate.query(sql,newBeanPropertyRowMapper(Course.class));}}2.注入攻击演示**1**。一般情况下,只需要传入student_id就可以查询到学生选修的课程和完成情况,就可以查到相关数据了。根据响应结果,我们可以快速写出对应的sql,如下:selectid,course_id,student_id,statusfromcoursewherestudent_id=42。如果我们要获取这张表的所有数据,只需要保证上面sql的where条件永远为真即可。selectid,course_id,student_id,statusfromcoursewherestudent_id=4or1=1在请求接口的时候,设置studendId为4或者1=1,这样这个sql的where条件就一直为真。SQL相当于下面selectid,course_id,student_id,statusfromcourse请求结果如下,我们得到了这张表的所有数据3.查询mysql版本号,使用union拼接sqlunionselect1,1,version(),14。查询数据库名称unionselect1,1,database(),15。查询当前mysql用户的所有库unionselect1,1,(SELECTGROUP_CONCAT(schema_name)FROMinformation_schema.schemata)schemaName,1看了上面的演示,你害怕了吗?你所有的数据配置都完全暴露了。此外,还可以完成很多操作,比如更新数据、删除数据库、删除表等等。三、如何防止sql注入1、在代码层防止sql注入攻击最好的方案是预编译sqlpublicListorderList(StringstudentId){Stringsql="selectid,course_id,student_id,statusfromcoursewherestudent_id=?";returnjdbcTemplate.query(sql,newObject[]{studentId},newBeanPropertyRowMapper(Course.class));}这样我们传入的参数4或者1=1就会被认为是一个student_id,所以不会有sql注入.2.确认每条数据的类型,比如数字,数据库必须使用int类型来存储3.指定数据长度,可以在一定程度上防止sql注入4.严格限制数据库权限,可以将危害降到最低sql注入的实现5.避免直接响应一些sql异常信息。sql异常发生后,自定义异常响应6.过滤参数中包含的一些数据库关键字@ComponentpublicclassSqlInjectionFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainchain)throwsIOException{vletSquetRepTreptionHttpServletRequest)servletRequest;HttServpServletRequestresvr=(所有请求参数名Enumerationparams=req.getParameterNames();Stringsql="";while(params.hasMoreElements()){//获取参数名().toString();//获取参数对应的值String[]value=req.getParameterValues(name);for(inti=0;i=0){returntrue;}}returnfalse;}}本文转载自微信公众号“Java之旅”,转载文章可通过以下二维码关注,转载请联系Java之旅公众号。