ref:web 防止SQL注入方法

ref:https://blog.csdn.net/beidou321/article/details/6482618java

小结:spring采用JdbcTemplate来操做sql,通常不要自行拼接sql,而是使用参数化的构造方式,则不会存在注入问题。程序员

SQL注入每每是在程序员编写包含用户输入的动态数据库查询时产生的,但其实防范SQL注入的方法很是简单。程序员只要spring

a)再也不写动态查询b)防止用户输入包含可以破坏查询逻辑的恶意SQL语句,就可以防范SQL注入。sql

在这篇文章中,咱们将会说明一些很是简单的防止SQL注入的方法。咱们用如下Java代码做为示例,数据库

String query ="SELECT account_balance FROM user_data WHERE user_name ="
  + request.getParameter("customerName");//sql语句拼接通常都有问题。除+外还有append函数也能够搜索下。 try {
Statement statement  = connection.createStatement( …);
ResultSet results = Statement.executeQuery(query);
}

在以上代码中,咱们能够看到并未对变量customerName作验证,customerName的值能够直接附在query语句的后面传送到数据库执行,则攻击者能够将任意的sql语句注入。编程

通常来讲,sql注入有两种:int型注入和字符串注入。对于int注入,只要在拼接时严格设置为int类型,例如intval或者java中函数参数为int,便可防止注入。api

对于字符串注入,只要对'进行转义便可。 安全

防范方法1:参数化查询app

参数化查询是全部开发人员在作数据库查询时首先须要学习的,参数化查询迫使全部开发者首先要定义好全部的SQL代码,而后再将每一个参数逐个传入,这种编码风格就可以让数据库辨明代码和数据。编程语言

参数化查询可以确保攻击者没法改变查询的内容,在下面修正过的例子中,若是攻击者输入了UsrID是“’or ‘1 ‘=’1”,参数化查询会去查找一个彻底知足名字为‘or ‘1 ‘=’ 1的用户。

对于不一样编程语言,有一些不一样的建议:

Java EE——使用带绑定变量的PreparedStatement()

.Net——使用带绑定变量的诸如SqlCommand()OleDbCommand()的参数化查询;

PHP——使用带强类型的参数化查询PDO(使用bindParam());

Hibernate——使用带绑定变量的createQuery()

Java示例:

String custname = request.getParameter("customerName");
String query ="SELECT account_balance FROM user_data WHERE user_name= ?";
PreparedStatement pstmt =connection.prepareStatement(query);
Pstmt.setString(1,custname);
ResultSet results = pstmt.executeQuery();

C# .Net示例:
String query ="SELECT account_balance FROM user_data WHERE user_name = ?";
Try {     
OleDbCommand command = new OleDbCommand(query,connection);
command.Parameters.Add(new OleDbParameter("customerName",CustomerName.Text));
OleDbDataReader reader = command.ExecuteReader();
}catch (OleDbException se){
//error handling
}

 

防范方法二:存储过程

存储过程和参数化查询的做用是同样的,惟一的不一样在于存储过程是预先定义并存放在数据库中,从而被应用程序调用的。

Java存储过程示例:
      String custname = request.getParameter("customerName");
      try {
CallableStatement cs = connection.prepareCall("call sp_getAccountBalance(?)}");
cs.setString(1,custname);
Result results = cs.executeQuery();
      }catch(SQLException se){
             //error handling
      }

VB .Net存储过程示例:
Try
Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance",connection)
 command.CommandType = CommandType.StoredProcedure
 command.Parameters.Add(new SqlParameter("@CustomerName",CustomerName.Text))
 Dim reader As SqlDataReader = command.ExecuteReader()
 ‘…

Catch se As SqlException
 ‘error handling
End Try

 

防范方法三:对全部用户输入进行转义

咱们知道每一个DBMS都有一个字符转义机制来告知DBMS输入的是数据而不是代码,若是咱们将全部用户的输入都进行转义,那么DBMS就不会混淆数据和代码,也就不会出现SQL注入了。

固然,若是要采用这种方法,那么你就须要对所使用的数据库转义机制,也可使用现存的诸如OWASP ESAPIescaping routinesESAPI目前是基于MySQLOracle的转义机制的,使用起来也很方便。一个OracleESAPI的使用示例以下:

ESAPI.encoder().encodeForSQL(new OracleCodec(),queryparam);

那么,假设你有一个要访问Oracle数据库的动态查询代码以下:

String query =SELECT user_id FROM user_data WHERE user_name = ‘+req.getParameter(userID)+’ and user_password = ‘+req.getParameter(pwd)+;

try {

      Statement statement = connection.createStatement(…);

      ResultSet results = statement.executeQuery(query) ;

}

那么,你就必须重写你的动态查询的第一行以下:

Codec ORACLE_CODEC = new OracleCodec();
String query ="SELECT user_id FROM user_data WHERE user_name = "+//注意必须有引号,若是没有,则int类型注入就可绕过。
ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter("userID"))+" and user_password = ‘"+
ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter("pwd"))+"’"; 

固然,为了保证本身代码的可读性,咱们也能够构建本身的OracleEncoder

Encoder e = new OracleEncoder();

String query =SELECT user_id FROM user_data WHERE user_name = ‘

      + oe.encode(req.getParameter(userID)) +’ and user_password = ‘

      + oe.encode(req.getParameter(pwd))+;

除了上面所说的三种防范方法之外,咱们还建议能够用如下两种附加的方法来防范SQL注入:最小权限法、输入验证白名单法。

最小权限法:

为了不注入攻击对数据库形成的损害,咱们能够把每一个数据库用户的权限尽量缩小,不要把DBA或管理员的权限赋予你应用程序帐户,在给用户权限时是基于用户须要什么样的权限,而不是用户不须要什么样的权限。当一个用户只须要读的权限时,咱们就只给他读的权限,当用户只须要一张表的部分数据时,咱们宁愿另建一个视图让他访问。若是你的策略是都是用存储过程的话,那么仅容许应用程序的帐户执行这些查询,而不给他们直接访问数据库表的权限。诸如此类的最小权限法可以在很大程度上保证咱们数据库的安全。

输入验证白名单法:

输入验证可以在数据传递到SQL查询前就察觉到输入是否正确合法,采用白名单而不是黑名单则能在更大程度上保证数据的合法性。

相关文章
相关标签/搜索