防sql注入 盲注等措施 ESAPI的使用

系统 2367 0

SQL 注入往往是在程序员编写包含用户输入的动态 数据库 查询时产生的,但其实防范 SQL 注入的方法非常简单。程序员只要 a )不再写动态查询,或 b )防止用户输入包含能够破坏查询逻辑的恶意 SQL 语句,就能够防范 SQL 注入。在这篇 文章 中,我们将会说明一些非常简单的防止 SQL 注入的方法。

我们用以下 Java 代码作为示例,

String query = SELECT account_balance FROM user_data WHERE user_name =

+ request.getParameter( customerName );

 

try {

Statement statement  =   connection.createStatement( …);

ResultSet results =   Statement.executeQuery(query);

}

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

防范方法 1 :参数化查询

参数化查询是所有开发人员在做数据库查询时首先需要 学习 的,参数化查询迫使所有开发者首先要定义好所有的 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 ESAPI escaping routines ESAPI 目前是基于 MySQL Oracle 的转义机制的,使用起来也很方便。一个 Oracle ESAPI 的使用示例如下:

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 = ‘ +

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 查询前就察觉到输入是否正确合法,采用白名单而不是黑名单则能在更大程度上保证数据的合法性。

防sql注入 盲注等措施 ESAPI的使用


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论