Java开发工程师(Web方向) - 03.数据库开发 - 第3章.SQL注入与防范

it2022-05-05  171

第3章--SQL注入与防范

SQL注入与防范

经常遇到的问题:数据安全问题,尤其是sql注入导致的数据库的安全漏洞

国内著名漏洞曝光平台:WooYun.org

数据库泄露的风险:用户信息、交易信息的泄露等

什么是SQL数据库注入?

Web应用下,终端用户是无法直接访问数据库的,他们必须通过发送http请求到Java服务器,由Java服务器访问后端数据库。因此,恶意用户想要获取数据库中的数据,必须通过Java服务器来访问后端数据库而无法绕行。他们的唯一途径就是利用应用程序的漏洞,伪装自己的请求,欺骗业务程序,达到访问数据库的目的。

之前学习的代码:用户登录场景

User user = null; String sql = "select * from user where userName = '" + userName + "' and password = '" + password + "'"; rs = stmt.executeQuery(sql); while(rs.next()) { user = new User(); user.setUserName(rs.getString("userName")); user.setCardNum(rs.getString("cardNum")); } return user;

 

Java应用程序接收到用户的输入后,检索后端数据库,匹配数据库记录。

如果:

用户输入为ZhangSan’;--  密码随便输入(因为不知道真实密码)

也会登陆成功,为什么呢?

select * from user where userName = 'ZhangSan'; -- 'and password='111';

密码条件被注释

总结:数据库注入就是用户在输入部分输入SQL命令,破坏原有SQL的语义,以达到欺骗服务器并发送恶意SQL的业务程序的漏洞。

原因:SQL语句为动态拼接的,语义未知。

解决方案:除了动态拼接,还有什么办法能使用web传入的参数呢?

参数化sql的实现:1. 确定sql的语义;2. 传入参数

利用Connection对象的.preparedStatement(sql)方法;

preparedStatement()相对于Statement的最大优点:提供了参数化sql的实现(格式化的sql)

select * from user where userName = ? and password = ?

?为占位符,替代了一个参数。sql的语义确定了。

根据参数的类型:.setInt(); .setString(); .setBoolean(); 来替代参数化sql中的占位符。

除了使用PreparedStatement,我们还应该有一些其他的注意事项:

1. 执行严格的数据库权限管理

仅给予Web应用访问数据库的最小权限

严格禁止Drop table等权限

2. 封装数据库错误:不能将数据库异常直接暴露给用户(因为数据库异常通常包含了大量的数据库信息)

禁止直接将后端数据库异常信息暴露给用户

对后端异常信息进行必要的封装,避免用户直接查看到后端异常

3. 机密信息禁止明文存储

涉密信息需要加密处理

针对MySQL,可使用AES_ENCRYPT/AES_DECRYPT进行加密和解密

课堂交流区:

其他的SQL注入场景:可以使用 "or 1"

i.e. select name from student where name = '' or 1; -- '';

会返回所有

 

 

SQL注入与防范单元测试

本次得分为: 100.00/100.00, 本次测试的提交时间为: 2017-08-24 1 多选(40分)

以下哪项描述是正确的?

A.PreparedStatement可以实现参数化SQL,防止SQL注入的风险。13.33/40.00B.SQL注入的本质是因为外部用户恶意改变了原有程序的执行语义,导致数据泄露。13.33/40.00C.SQL注入可以导致外部用户获取整个数据库的信息。13.33/40.00D.使用PreparedStatement,如果用户使用SQL注释符,也可能会改变SQL的语义执行。 2 判断(10分)

SQL 注入是由于应用程序动态拼接SQL,用户利用该漏洞,注入特殊SQL语句,导致应用程序执行恶意SQL命令的现象。

A.√10.00/10.00B.× 3 判断(10分)

Statement接口可以实现参数化SQL,防止动态拼接SQL导致的SQL注入漏洞。

A.×10.00/10.00B.√ 4 判断(10分)

应谨慎给予用户Delete权限,防止用户数据被恶意删除。

A.×B.√10.00/10.00 5 判断(10分)

SQL注入漏洞是由于数据库密码泄露,导致用户登陆到数据库上执行了恶意操作。

A.√B.×10.00/10.00 6 判断(10分)

PreparedStatement需要设置格式化SQL语句,格式化SQL语句就是将SQL的参数使用占位符替代的SQL语句。

A.×B.√10.00/10.00 7 判断(10分)

应用程序需要捕获SQL异常,将异常信息展现给用户,方便用户处理。

A.√B.×10.00/10.00

 

 

SQL注入与防范单元作业

请完成SQL注入与防范的编程题目。

1(100分)

有一张学生表

idnamenumber1XiaoMing1002XiaoLi1013XiaoZhao102

现在需要根据学生名称获取学生的期末考试分数。

public static void getStudent(String name) throws ClassNotFoundException { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { Class.forName(JDBC_DRIVER); conn = DriverManager.getConnection(DB_URL, USER, PASS); stmt = conn.createStatement(); rs = stmt.executeQuery("select name,score from student where name =' " + name +"'"); while (rs.next()) { System.out.println(rs.getString("name") + ":" + rs.getInt("score")); } } catch (SQLException e) { // ignore } finally { if (rs != null) { try { rs.close(); } catch (Exception e) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (Exception e) { // ignore } } if (conn != null) { try { conn.close(); } catch (SQLException e) { // ignore } } } }

 

1. 请指出上面这段程序存在什么安全风险?并给出具体的测试用例。

2. 请重新编写应用程序,解决上述风险。

答:

安全风险:上述程序使用Statement对象,有SQL注入的风险。

程序错误:

1. stmt.executeQuery(sql)中的sql语句有误,多了一个空格导致

"select name,number from student where name ='  XiaoZhao'" 返回的为empty set

2. 数据库中columns分别为id, name和number,而程序中select语句包含的attributes为name和number

SQL注入测试用例:

getStudent("' or 1;#");

解决SQL注入、修改错误后的代码:

import java.sql.Connection; import java.sql.DriverManager; //import java.sql.Statement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class Assignment { static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/helloworld"; static final String USER = "matt"; static final String PASS = "matt"; public static void getStudent(String name) throws ClassNotFoundException { Connection conn = null; // Statement stmt = null; PreparedStatement ptmt = null; ResultSet rs = null; try { Class.forName(JDBC_DRIVER); conn = DriverManager.getConnection(DB_URL, USER, PASS); // stmt = conn.createStatement(); String sql = "select name,number from student where name = ?"; ptmt = conn.prepareStatement(sql); ptmt.setString(1, name); // rs = stmt.executeQuery("select name,number from student where name =' " + name +"'"); rs = ptmt.executeQuery(); while (rs.next()) { System.out.println(rs.getString("name") + ":" + rs.getInt("number")); } } catch (SQLException e) { // ignore } finally { if (rs != null) { try { rs.close(); } catch (Exception e) { // ignore } } // if (stmt != null) { if (ptmt != null) { try { // stmt.close(); ptmt.close(); } catch (Exception e) { // ignore } } if (conn != null) { try { conn.close(); } catch (SQLException e) { // ignore } } } } public static void main (String[] args) throws ClassNotFoundException { getStudent("XiaoZhao"); getStudent("' or 1;#"); } }

 

 

 

 

转载于:https://www.cnblogs.com/FudgeBear/p/7420273.html

相关资源:各显卡算力对照表!

最新回复(0)