如何防止sql注入
 
1、检查变量数据类型和格式
如果你的SQL语句是类似where id={$id}这种形式,数据库里所有的id都是数字,那么就应该在SQL被执行前,检查确保变量id是int类型;如果是接受邮箱,那就应该检查并严格确保变量一定是邮箱的格式,其他的类型比如日期、时间等也是一个道理。总结起来:只要是有固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。
比如,我们前面接受username参数例子中,我们的产品设计应该是在用户注册的一开始,就有一个用户名的规则,比如5-20个字符,只能由大小写字母、数字以及一些安全的符号组成,不包含特殊字符。此时我们应该有一个check_username的函数来进行统一的检查。不过,仍然有很多例外情况并不能应用到这一准则,比如文章发布系统,评论系统等必须要允许用户提交任意字符串的场景,这就需要采用过滤等其他方案了。
 
2、过滤特殊符号
对于无法确定固定格式的变量,一定要进行特殊符号过滤或转义处理。以PHP为例,通常是采用addslashes函数,它会在指定的预定义字符前添加反斜杠转义,这些预定义的字符是:单引号 (') 双引号 (") 反斜杠 (\) NULL。
来看2条SQL语句:
  1. $uid = isset($_GET['uid']) ? $_GET['uid'] : ;
    $uid = addslashes(uid);
    $sql = "SELECT uid,username FROM user WHERE uid='{$uid}'";
  2.  
  3. 以及
  4.  
  5. $uid = isset($_GET['uid']) ? $_GET['uid'] : ;
    $uid = addslashes(uid);
    $sql = "SELECT uid,username FROM user WHERE uid={$uid}";
上面两个查询语句都经过了php的addslashes函数过滤转义,但在安全性上却大不相同,在MySQL中,对于int类型字段的条件查询,上面个语句的查询效果完全一样,由于第一句SQL的变量被单引号包含起来,SQL注入的时候,黑客面临的首要问题是必须要先闭合前面的单引号,这样才能使后面的语句作为SQL执行,并且还要注释掉原SQL语句中的后面的单引号,这样才可以成功注入,由于代码里使用了addslashes函数,黑客的攻击会无从下手,但第二句没有用引号包含变量,那黑客也不用考虑去闭合、注释,所以即便同样采用addslashes转义,也还是存在SQL攻击漏洞。
 
对于PHP程序+MySQL构架的程序,在动态的SQL语句中,使用单引号把变量包含起来配合addslashes函数是应对SQL注入攻击的有效手段,但这做的还不够,像上面的2条SQL语句,根据「检查数据类型」的原则,uid都应该经过intval函数格式为int型,这样不仅能有效避免第二条语句的SQL注入漏洞,还能使得程序看起来更自然,尤其是在NoSQL(如MongoDB)中,变量类型一定要与字段类型相匹配才可以。
 
从上面可以看出,第二个SQL语句是有漏洞的,不过由于使用了addslashes函数,你会发现黑客的攻击语句也存在不能使用特殊符号的条件限制,类似where username='plhwin'这样的攻击语句是没法执行的,但是黑客可以将字符串转为16进制编码数据或使用char函数进行转化,同样能达到相同的目的,如果对这部分内容感兴趣,可以点击这里查看。而且由于SQL保留关键字,如「HAVING」、「ORDER BY」的存在,即使是基于黑白名单的过滤方法仍然会有或多或少问题,那么是否还有其他方法来防御SQL注入呢?
 
3、绑定变量,使用预编译语句
MySQL的mysqli驱动提供了预编译语句的支持,不同的程序语言,都分别有使用预编译语句的方法,我们这里仍然以PHP为例,编写userinfo2.php代码:
  1. <?php
  2. header('Content-type:text/html; charset=UTF-8');
  3. $username = isset($_GET['username']) ? $_GET['username'] : '';
  4. $userinfo = array();
  5. if($username)
  6. {
  7. //使用mysqli驱动连接demo数据库
  8. $mysqli = new mysqli("localhost", "root", "root", 'demo');
  9. //使用问号替代变量位置
  10. $sql = "SELECT uid,username FROM user WHERE username=?";
  11. $stmt = $mysqli->prepare($sql);
  12. //绑定变量
  13. $stmt->bind_param("s", $username);
  14. $stmt->execute();
  15. $stmt->bind_result($uid, $username);
  16. while ($stmt->fetch())
  17. {
  18. $row = array();
  19. $row['uid'] = $uid;
  20. $row['username'] = $username;
  21. $userinfo[] = $row;
  22. }
  23. }
  24. echo '<pre>',print_r($userinfo, ),'</pre>';
  25. ?>
从上面的代码可以看到,我们程序里并没有使用addslashes函数,但是浏览器里运行 http://localhost/test/userinfo2.php?username=plhwin' AND 1=1-- hack 里得不到任何结果,说明SQL漏洞在这个程序里并不存在。
 
实际上,绑定变量使用预编译语句是预防SQL注入的最佳方式,使用预编译的SQL语句语义不会发生改变,在SQL语句中,变量用问号?表示,黑客即使本事再大,也无法改变SQL语句的结构,像上面例子中,username变量传递的 plhwin' AND 1=1-- hack 参数,也只会当作username字符串来解释查询,从根本上杜绝了SQL注入攻击的发生。
  这种方式能防范SQL注入的原理是在SQL参数未注入之前,提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。也就是说其后注入进来的参数系统将不会认为它会是一条SQL语句,而默认其是一条一个参数。
 
数据库信息加密安全
相信大家都还对2011年爆出的CSDN拖库事件记忆犹新,这件事情导致CSDN处在风口浪尖被大家痛骂的原因就在于他们竟然明文存储用户的密码,这引发了科技界对用户信息安全尤其是密码安全的强烈关注,我们在防范SQL注入的发生的同时,也应该未雨绸缪,说不定下一个被拖库的就是你,谁知道呢。
 
在Web开发中,传统的加解密大致可以分为三种:
1、对称加密:
即加密方和解密方都使用相同的加密算法和密钥,这种方案的密钥的保存非常关键,因为算法是公开的,而密钥是保密的,一旦密匙泄露,黑客仍然可以轻易解密。常见的对称加密算法有:AES、DES等。
 
2、非对称加密:
即使用不同的密钥来进行加解密,密钥被分为公钥和私钥,用私钥加密的数据必须使用公钥来解密,同样用公钥加密的数据必须用对应的私钥来解密,常见的非对称加密算法有:RSA等。
 
3、不可逆加密:
利用哈希算法使数据加密之后无法解密回原数据,这样的哈希算法常用的有:md5、SHA-1等。
 
在我们上面登录系统的示例代码中,$md5password = md5($password); 从这句代码可以看到采用了md5的不可逆加密算法来存储密码,这也是多年来业界常用的密码加密算法,但是这仍然不安全。为什么呢?
 
这是因为md5加密有一个特点:同样的字符串经过md5哈希计算之后生成的加密字符串也是相同的,由于业界采用这种加密的方式由来已久,黑客们也准备了自己强大的md5彩虹表来逆向匹配加密前的字符串,这种用于逆向反推MD5加密的彩虹表在互联网上随处可见,在Google里使用md5 解密作为关键词搜索,一下就能找到md5在线破解网站,把我们插入用户数据时候的MD5加密字符串e10adc3949ba59abbe56e057f20f883e填入进去,瞬间就能得到加密前的密码:123456。当然也并不是每一个都能成功,但可以肯定的是,这个彩虹表会越来越完善。
 
所以,我们有迫切的需求采用更好的方法对密码数据进行不可逆加密,通常的做法是为每个用户确定不同的密码加盐(salt)后,再混合用户的真实密码进行md5加密,如以下代码:
<?php//用户注册时候设置的password$password = $_POST['password'];//md5加密,传统做法直接将加密后的字符串存入数据库,但这不够,我们继续改良$passwordmd5 = md5($password);//为用户生成不同的密码盐,算法可以根据自己业务的需要而不同$salt = substr(uniqid(rand()), -6);//新的加密字符串包含了密码盐$passwordmd5 = md5($passwordmd5.$salt);
 
小结
  1. 、不要随意开启生产环境中Webserver的错误显示。
  2. 、永远不要信任来自用户端的变量输入,有固定格式的变量一定要严格检查对应的格式,没有固定格式的变量需要对引号等特殊字符进行必要的过滤转义。
  3. 、使用预编译绑定变量的SQL语句。
  4. 、做好数据库帐号权限管理。
  5. 、严格加密处理用户的机密信息。

1.4 如何防止sql注入的更多相关文章

  1. 个人网站对xss跨站脚本攻击(重点是富文本编辑器情况)和sql注入攻击的防范

    昨天本博客受到了xss跨站脚本注入攻击,3分钟攻陷--其实攻击者进攻的手法很简单,没啥技术含量.只能感叹自己之前竟然完全没防范. 这是数据库里留下的一些记录.最后那人弄了一个无限循环弹出框的脚本,估计 ...

  2. Web安全相关(五):SQL注入(SQL Injection)

    简介 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据 ...

  3. 从c#角度看万能密码SQL注入漏洞

    以前学习渗透时,虽然也玩过万能密码SQL注入漏洞登陆网站后台,但仅仅会用,并不理解其原理. 今天学习c#数据库这一块,正好学到了这方面的知识,才明白原来是怎么回事. 众所周知的万能密码SQL注入漏洞, ...

  4. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  5. 揭开SQL注入的神秘面纱PPT分享

        SQL注入是一个老生常谈但又经常会出现的问题.该课程是我在公司内部培训的课程,现在分享出来,希望对大家有帮助.     点击这里下载.

  6. 深入理解SQL注入绕过WAF和过滤机制

    知己知彼,百战不殆 --孙子兵法 [目录] 0x0 前言 0x1 WAF的常见特征 0x2 绕过WAF的方法 0x3 SQLi Filter的实现及Evasion 0x4 延伸及测试向量示例 0x5 ...

  7. jdbc java数据库连接 8)防止sql注入

    回顾下之前jdbc的开发步骤: 1:建项目,引入数据库驱动包 2:加载驱动 Class.forName(..); 3:获取连接对象 4:创建执行sql语句的stmt对象;  写sql 5:执行sql ...

  8. Entity Framework关于SQL注入安全问题

    1.EF生成的sql语句,用 parameter 进行传值,所以不会有sql注入问题 2.EF下有涉及外部输入参数传值的,禁止使用EF直接执行sql命令方式,使用实体 SQL   参考: https: ...

  9. 关于SQL注入和如何防止

    之前在笔试的时候没有很好的答出这个问题,因此我要总结一下问题,以免日后继续在这个地方跌倒,以下是自己的理解,如有错误请指出 一.什么是SQL注入 SQL注入就是服务器在根据业务去处理数据库的时候,客户 ...

  10. Java防止SQL注入2(通过filter过滤器功能进行拦截)

    首先说明一点,这个过滤器拦截其实是不靠谱的,比如说我的一篇文章是介绍sql注入的,或者评论的内容是有关sql的,那会过滤掉:且如果每个页面都经过这个过滤器,那么效率也是非常低的. 如果是要SQL注入拦 ...

随机推荐

  1. Android硬件抽象层(HAL)概要介绍【转】

    本文转载自:http://blog.csdn.net/luoshengyang/article/details/6567257 Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装 ...

  2. Java 9 逆天的十大新特性

    在介绍java9之前,我们先来看看java成立到现在的所有版本. 1990年初,最初被命名为Oak: 1995年5月23日,Java语言诞生: 1996年1月,第一个JDK-JDK1.0诞生: 199 ...

  3. Sqoop-1.4.4工具import和export使用详解

    转自:http://blog.csdn.net/wodatoucai/article/details/46343291 Sqoop可以在HDFS/Hive和关系型数据库之间进行数据的导入导出,其中主要 ...

  4. jquery获取点击标签内的子标签内容和值实例

    今天有点累了,就不多做其他的描述解释.在插入的代码里相关解释也都有. <!--<%@ page language="java" import="java.ut ...

  5. 在windows下进行linux开发:利用Vagrant+virtualbox

    1,介绍Vagrant 我们做web开发的时候经常要安装各种本地测试环境,比如apache,php,mysql,redis等等.出于个人使用习惯,可能我们还是比较习惯用windows.虽然说在wind ...

  6. Struts 2简介

    Struts 2简介 Struts 2 编辑 同义词 Struts2一般指Struts 2 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中 ...

  7. PHP基于单例模式编写PDO类的方法

    一.单例模式简介 简单的说,一个对象(在学习设计模式之前,需要比较了解面向对象思想)只负责一个特定的任务: 二.为什么要使用PHP单例模式? 1.php的应用主要在于数据库应用, 所以一个应用中会存在 ...

  8. Vue2.0总结———vue使用过程常见的一些问题

    Vue目前的的开发模式主要有两种:1.直接页面级的开发,script直接引入Vue2.工程性开发,webpack+loader或者直接使用脚手架工具Vue-cli,里面的文件都配置好了 webpack ...

  9. PHP获取一年中每个星期的开始和结束日期的方法

    这篇文章主要介绍了PHP获取一年中每个星期的开始和结束日期的方法,涉及php对日期操作的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例讲述了PHP获取一年中每个星期的开始和结束日期的方法. ...

  10. BEC listen and translation exercise 43

    Reach for the stars so if you fall you land on a cloud.飞向星空吧,就算坠落,接住你的也是云彩. Anyway, exam failure can ...