正确的防御SQL注入

  sql注入的防御不是简单只做一些用户输入的escape处理,这样是不够的,只是提高了攻击者的门槛而已,还是不够安全。

例如 mysql_real_escape_string()函数会对输入的参数进行转义。

$sql="SELECT id,name,mail,cv,blog,twitter FROM register WHERE id= ".mysql_real_escape_string($_GET['id']);

当攻击者构造的注入代码如下时:

http://vuln.example.com/user.php?id=2,and,1=1,union,select,1,
concat(user,0x3a,password),3,4,5,6,from,mysql.user,where,
user=substring_index(current_user(),char(64),1)

 将会绕过这个函数注入成功,其原因在于这个函数仅仅会转义: '   "   \r   \n   NULL   Control-Z

这种基于黑名单的方法,或多或少地存在些问题,是不可能排除所有恶意符号或者说能利用的符号。

  围绕着SQL注入攻击产生的两个关键条件:1.用户控住的输入参数  2.拼接过程中的数据当做代码执行。

有下面几个防御措施:

一.使用预编译语句

  一般来说,防御SQL注入的最好效果就是使用预编译语句,绑定变量。例如在Java中使用预编译的SQL语句:

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

使用这种预编译的SQL语句,SQL语句的语义不会发生改变,变量用?表示,攻击者无法改变SQL的结构。

在PHP中绑定变量的示例:

$query="INSERT INTO myCity(Name,CountCode,District)VALUES(?,?,?)";
$stmt=$mysqli->prepare($query);
$stmt->bind_param("sss",$var1,$var2,$var3);
$var1="StuName";
$var2="DEU";
$var3="Bid";
$stmt->execute();

在不同的语言中,都有着预编译语句的方法:

Java EE------ PreparedStatement()

.NET------SqlCommand() or OleDbCommand()

PHP------bind_Param()

Hibernate------createQuery()

SQLite------sqlite3_prepare()

二.使用存储函数 

使用安全的存储过程对抗SQL注入。使用存储过程与预编译语句的区别在于,存储过程要先将SQL语句定义在数据库中,所以存储过程也可能存在注入问题,得尽量避免在存储过程中使用动态的SQL语句。如果业务要求,实在无法避免,则可以考虑加上严格的输入过滤或者是编码函数来处理用户的输入数据。

Java中存储过程的示例,其中sp_getAccount是预先在数据中定义好的存储过程。

String username=request.getParameter("userName");
try{
CallableStatement cs=
connection.prepareCall(" {call sp_getAccount(?)} ");
cs.setString(1,username);
ResultSet results=cs.executeQuery();
}catch(SQLException se){
//....some error info and error handing
}

三.检查数据类型

检出数据类型,在很大程度上能够对抗SQL注入。

比如下面这段代码,就限制了输入数据只能为integer。

<?php

settype($offset,'integer');
$query="SELECT id ,name FROM produces ORDER BY name LIMIT
20 OFFSET ;"; $query=sprintf("SELECT id ,name,FROM produces ORDER BY name LIMIT 20 OFFSET %d;");
?>

其他数据格式或者类型检查也是有益的,但是提交字符串,则需要依赖其他的方法防御SQL注入,而不能使用'%s"代换"%d"。

四.使用安全函数

安全函数,数据库厂商都往往对此都做出了“指导”。可以参考OWASP ESAPI中的实现。这个函数由安全专家编写的,更值得信赖。

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

使用示例:

Codec ORACLE_CODEC=new OracleCode();
String query="SELECT user_id FROM user_data WHERE user_name=' "+
ESAPI.encoder().encoderForSQL( ORACLE_CODEC,req.getParameter("userID"))+" ' and
user_password=' "+
ESAPI.encoder().encoderForSQL( ORACLE_CODEC,req.getParameter("pwd"))+" ' ";

最新文章

  1. Spearman秩相关系数和Pearson皮尔森相关系数
  2. 网络初见&amp;网络监测
  3. Spring入门_03_构造注入
  4. strcpy vs memcpy
  5. crossdomain.xml的配置详解
  6. 2015GitWebRTC编译实录4
  7. 利用js闭包获取索引号
  8. Get请求出现乱码的解决方案
  9. 腾讯出品的抓包工具Rythem
  10. PLSQL 导入表到Oracle------》从一个表空间导入到其它表空间
  11. Java经典案例之-“成绩等级划分”
  12. win7系统中使用DOS命令是出现乱码的解决方法
  13. H - Pair: normal and paranormal URAL - 2019
  14. Linux下Redis的安装配置
  15. 关于webpack官网的学习
  16. Golang命令行拷贝文件
  17. free详解
  18. HTML5学习笔记3
  19. iOS之富文本(二)
  20. Python常用的标准库以及第三方库有哪些?

热门文章

  1. Jenkins自动化构建配置
  2. xargs原理剖析及用法详解
  3. [Linux] LVS虚拟服务器四层负载均衡
  4. [PHP]算法-堆排序的PHP实现
  5. 解决org.hibernate.exception.SQLGrammarException:could not insert
  6. 【Java每日一题】20170302
  7. SpringBoot的打包失败
  8. Laravel条件查询数据单条数据first,多条数据get
  9. js 小写金额转大写
  10. JS中的反柯里化( uncurrying)