什么是SQL注入?

就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。 
例如一个简单的登录表单(这里把密码写成明文方便说明): 
 
当在表单中填写这样的语句进行提交登录时会出现这样的SQL语句

  1. select * from t_admin where admin_name='xxx' and admin_pwd='xxx'' or '1'

这样会查询出所有的用户信息,所有存在不安全隐患

常用的SQL注入方式

下面看看一些常用例测试的SQL注入语句。

1. 使用单引号及or关键字
  1. SELECT * FROM Users WHERE Username='$username' AND Password='$password'


我们针对上面的SQL语句分析,发现如果用下面的测试数据就能够进行SQL注入了 
引用 

username=1′or′1′=′1password=1’or’1’=’1 

看看整个SQL查询语句变成: 
引用

  1. 
SELECT * FROM Users WHERE Username='1' OR '1'='1' AND Password='1'OR '1'='1'


假设参数值是通过GET方法传递到服务器的,且域名为www.example.com 那么我们的访问请求就是: 
引用 

  http://www.example.com/index.php?username=1‘%20or%20’1’%20=%20’1password=1’%20or%20’1’%20=%20’1 

 对上面的SQL语句作简单分析后我们就知道由于该语句永远为真,所以肯定会返回一些数据,在这种情况下实际上并未验证用户名和密码,并且在某些系统中,用户表的第一行记录是管理员,那这样造成的后果则更为严重。

2. 使用括号



另外一个查询的例子如下: 引用 

  1. SELECT * FROM Users WHERE((Username='$username')AND(Password=MD5('$password')))


在这个例子中,存在两个问题,一个是括号的用法,还有一个是MD5哈希函数的用法。对于第一个问题,我们很容找出缺少的右括号解决,对于第二个问题,我们可以想办法使第二个条件失效。我们在查询语句的最后加上一个注释符以表示后面的都是注释,常见的注释起始符是/*(在Oracle中是–),也就是说,我们用如下的用户名和密码: 
引用 

username=1′or′1′=′1′))/∗password = foo 

那么整条SQL语句就变为: 
引用

  1. 
 SELECT * FROM Users WHERE(( Username='1'or '1'='1'))/*')AND (Password=MD5('$password')))



那么看看URL请求就变为: 
引用 
http://www.example.com/index.php?username=1‘%20or%20’1’%20=%20’1’))/*&password=foo 

#####3.Union查询SQL注入测试 
 


Union查询SQL注入测试 
 还有一种测试是利用Union的,利用Union可以连接查询,从而从其他表中得到信息,假设如下查询: 
引用

  1. 
 SELECT Name, Phone, Address FROM Users WHERE Id=$id


然后我们设置id的值为: 
引用 

$id =1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCarTable 

那么整体的查询就变为: 
引用

  1. 
SELECT Name, Phone,Address FROM Users WHERE Id=1 UNION ALL SELECT creaditCardNumber,1,1 FROM CreditCarTable


显示这就能得到所有信用卡用户的信息。 

盲目SQL注入测试 
 在上面我们提到过盲SQL注入,即bind SQL Injection,它意味着对于某个操作我们得不到任何信息,通常这是由于程序员已经编写了特定的出错返回页面,从而隐藏了数据库结构的信息。 

 但利用推理方法,有时候我们能够恢复特定字段的值。这种方法通常采用一组对服务器的布尔查询,依据返回的结果来推断结果的含义。仍然延续上面的www.example.com有一个参数名为id, 那么我们输入以下url请求: 
引用 

 http://www.exampe.com/index.php?id=1’ 

显然由于语法错误,我们会得到一个预先定义好的出错页面,假设服务器上的查询语句为 
引用 

SELECT field1,field2,field3 FROM Users WHERE Id=’Id′假设我们想要的带哦用户名字段的值,那么通过一些函数,我们就可以逐字符的读取用户名的值。在这里我们使用以下的函数:引用
SUBSTRING(text,start,length),ASCII(char),LENGTH(text)
我们定义id为:引用Id=1’ AND ASCII(SUBSTRING(username,1,1))=97 AND ‘1’=’1 

那么最终的SQL查询语句为: 
引用 

  1. SELECT field1,field2,field3 FROM Users WHERE Id='1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1'


那么,如果在数据库中有用户名的第一字符的ASCII码为97的话,那么我们就能得到一个真值u,那么就继续寻找该用户名的下一个字符;如果没有的话,那么我们就增猜测第一个字符的ASCII码为98的用户名,这样反复下去就能判断出合法的用户名

常用SQL注入的解决方案

1.添加图形码进行验证

添加图形码在一定程序上增加代码的安全性,给机器强制破解有一定的拦截作用,但不能阻止所有的攻击,故还是需要在程序上进行安全性考虑

2.使用预备义语句和参数化查询

使用预处理语句和参数化查询。预处理语句和参数分别发送到数据库服务器进行解析,参数将会被当作普通字符处理。这种方式使得攻击者无法注入恶意的SQL。常用的方式有两种

2.1 使用PDO(PHP Data Objects )
  1. $stmt = $pdo->prepare('SELECT * FROM t_admin WHERE admin_name = :name');
  2. $stmt->execute(array('name' => $name));
  3. foreach ($stmt as $row) {
  4. // do something with $row
  5. }

注意,在默认情况使用PDO并没有让MySQL数据库执行真正的预处理语句(原因见下文)。为了解决这个问题,你应该禁止PDO模拟预处理语句。一个正确使用PDO创建数据库连接的例子如下

  1. $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
  2. $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
2.2 使用MySQLi
  1. $stmt = $dbConnection->prepare('SELECT * FROM t_admin WHERE admin_name = ?');
  2. $stmt->bind_param('s', $name);
  3. $stmt->execute();
  4. $result = $stmt->get_result();
  5. while ($row = $result->fetch_assoc()) {
  6. // do something with $row
  7. }
3.对用户传递的参数进行处理

我们知道Web上提交数据有两种方式,一种是get、一种是post,那么很多常见的sql注射就是从get方式入手的,而且注射的语句里面一定是包含一些sql语句的,因为没有sql语句,那么如何进行,sql语句有四大句:select 、update、delete、insert,那么我们如果在我们提交的数据中进行过滤是不是能够避免这些问题呢? 
于是我们使用正则就构建如下函数:

  1. <?php
  2. function inject_check($sql_str)
  3. {
  4. return eregi('select|insert|update|delete|');
  5. }
  6. function verify_id($id=null)
  7. {
  8. if (!$id) { exit('没有提交参数!'); } // 是否为空判断
  9. elseif (inject_check($id)) { exit('提交的参数非法!'); } // 注射判断
  10. elseif (!is_numeric($id)) { exit('提交的参数非法!'); } // 数字判断
  11. $id = intval($id); // 整型化
  12. return $id;
  13. }
  14. ?>

那么我们就能够进行校验了,于是我们上面的程序代码就变成了下面的:

  1. <?php
  2. if (inject_check($_GET['id']))
  3. {
  4. exit('你提交的数据非法,请检查后重新提交!');
  5. }
  6. else
  7. {
  8. $id = verify_id($_GET['id']); // 这里引用了我们的过滤函数,对$id进行过滤
  9. echo '提交的数据合法,请继续!';
  10. }
  11. ?>

好,问题到这里似乎都解决了,但是我们有没有考虑过post提交的数据,大批量的数据呢? 
比如一些字符可能会对数据库造成危害,比如 ’ _ ‘, ’ %’,这些字符都有特殊意义,那么我们如果进行控制呢?还有一点,就是当我们的php.ini里面的magic_quotes_gpc = off的时候,那么提交的不符合数据库规则的数据都是不会自动在前面加’ ‘的,那么我们要控制这些问题,于是构建如下函数:

  1. <?php
  2. function str_check( $str )
  3. {
  4. if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否打开
  5. {
  6. $str = addslashes($str); // 进行过滤
  7. }
  8. $str = str_replace("_", "\_", $str); // 把 '_'过滤掉
  9. $str = str_replace("%", "\%", $str); // 把' % '过滤掉
  10. return $str;
  11. }
  12. ?>
  1. 最后,再考虑提交一些大批量数据的情况,比如发贴,或者写文章、新闻,我们需要一些函数来帮我们过滤和进行转换,再上面函数的基础上,对提交的数据进行引号转义及将HTML标签转换成HTML实体,可以构建如下函数:
  1. <?php
  2. function post_check($post)
  3. {
  4. if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否为打开
  5. {
  6. $post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤
  7. }
  8. $post = str_replace("_", "\_", $post); // 把 '_'过滤掉
  9. $post = str_replace("%", "\%", $post); // 把' % '过滤掉
  10. $post = nl2br($post); // 回车转换
  11. $post= htmlspecialchars($post); // html标记转换
  12. return $post;
  13. }
  14. ?>
  15. 或者根据API文档中的:
    TP框架防止sql注入:

对于WEB应用来说,SQL注入攻击无疑是首要防范的安全问题,系统底层对于数据安全方面本身进行了很多的处理和相应的防范机制,例如:

  1. $User = M("User"); // 实例化User对象
  2. $User->find($_GET["id"]);

即便用户输入了一些恶意的id参数,系统也会强制转换成整型,避免恶意注入。这是因为,系统会对数据进行强制的数据类型检测,并且对数据来源进行数据格式转换。而且,对于字符串类型的数据,ThinkPHP都会进行escape_string处理(real_escape_string,mysql_escape_string),如果你采用PDO方式的话,还支持参数绑定。

通常的安全隐患在于你的查询条件使用了字符串参数,然后其中一些变量又依赖由客户端的用户输入。

要有效的防止SQL注入问题,我们建议:

  • 查询条件尽量使用数组方式,这是更为安全的方式;
  • 如果不得已必须使用字符串查询条件,使用预处理机制;
  • 使用自动验证和自动完成机制进行针对应用的自定义过滤;
  • 如果环境允许,尽量使用PDO方式,并使用参数绑定

查询条件预处理

where方法使用字符串条件的时候,支持预处理(安全过滤),并支持两种方式传入预处理参数,例如:

  1. $Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
  2. // 或者
  3. $Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();

模型的query和execute方法 同样支持预处理机制,例如:

  1. $model->query('select * from user where id=%d and status=%d',$id,$status);
  2. //或者
  3. $model->query('select * from user where id=%d and status=%d',array($id,$status));

execute方法用法同query方法。

  1.  

PHPSQL注入的更多相关文章

  1. 关于ECSHOP中sql注入漏洞修复

    标签:ecshop sql注入漏洞修复 公司部署了一个ecshop网站用于做网上商城使用,部署在阿里云服务器上,第二天收到阿里云控制台发来的告警信息,发现ecshop网站目录下文件sql注入漏洞以及程 ...

  2. 2012 PHP热门资料64个+经典源码50个——下载目录 :

    完整附件0豆下载:http://down.51cto.com/data/419216 附件部分预览: PHP精彩应用实例程序源码集锦 http://down.51cto.com/zt/39 无师自通: ...

  3. 转:攻击JavaWeb应用[1]-javaEE基础

    http://www.cnblogs.com/oh3o/p/3224562.html JSP: 全名为java server page,其根本是一个简化的Servlet. Servlet:Servle ...

  4. 一个PHP的SQL注入完整过程

    本篇文章介绍的内容是一个PHP的SQL注入完整过程,现在分享给大家,有需要的朋友可以参考一下 希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里 ...

  5. webapi - 使用依赖注入

    本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...

  6. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

  7. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  8. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  9. .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整(续)-使用配置文件动态注入

    上次实现了依赖注入,但是web项目必须要引用业务逻辑层和数据存储层的实现,项目解耦并不完全:另一方面,要同时注入业务逻辑层和数据访问层,注入的服务直接写在Startup中显得非常臃肿.理想的方式是,w ...

随机推荐

  1. Grunt-Kmc基于KISSY项目打包

    Grunt-Kmc基于KISSY项目打包 1. Grunt-Kmc 是基于nodejs开发的,所以未安装nodeJS,先需要安装nodejs.安装步骤如下:        1. 下载安装文件,下载地址 ...

  2. js 对于jquery each 多层循环的问题和原生js多层循环问题

    一.在jquery中,我们使用循环的时候,提供两种方式:jquery.each 和(循环体).each  两种方式不是同. 对于return 在作用这两个的函数的时候需要注意: 首先我们需要知道我们的 ...

  3. 清北学堂寒假集训DAY1

    第一天,上午讲了些基本的技巧和简单算法,主要就是适应这里. 中午跑到食堂吃了顿“饭”(我并没有挖苦233333),然后回宿舍休息休息 因为 迎接我们的是模拟啊啊啊啊啊阿 下午题一发下来,并没有想象中的 ...

  4. 写脚本时出现: Permission denied

    例如对文件 remove.sh sudo chmod -R 777 remove.sh

  5. day69

    昨日回顾: 1 路由层:  1简单配置  2无名分组  3有名分组  4反向解析--模板层,视图层  5路由分发  include  6名称空间   7伪静态 2 作业:  urlpatterns = ...

  6. VB6 选择文件夹路径

    '--------------------------------------------------------------------------------------- ' Module : ...

  7. 2017-2018-2 20155229《网络对抗技术》Exp1:逆向及Bof基础实践

    逆向及Bof基础实践 实践基础知识 管道命令: 能够将一个命令的执行结果经过筛选,只保留需要的信息. cut:选取指定列. 按指定字符分隔:只显示第n 列的数据 cut -d '分隔符' -f n 选 ...

  8. 6、使用jconsole+VisualVM分析JVM

    一.不断增加对象触发GC的代码 VM 参数:-Xms100m -Xmx100m -XX:+UseSerialGC import java.util.ArrayList; import java.uti ...

  9. Oracle出现与并行相关的ORA-00600时的调查方法

    出现了 ORA-00600[kxfpqsod_qc_sod], 如何调查呢? 例如:从trace 文件的 Call Stack,可以看到 Error: ORA-600 [kxfpqsod_qc_sod ...

  10. 汇编 LEA 指令

    知识点:  LEA指令  &与LEA  OD里修改汇编代码 一.LEA指令格式 有效地址传送指令 LEA 格式: LEA 操作数A, 操作数B 功能: 将操作数B的有效地址传送到指定的的 ...