SQL注入学习过程:
1.以前学asp时,防止SQL注入,人家和我说过滤select,update,delete等关键字。
2.刚学asp.net时,还是按以前的做法,过滤select,update,delete等关键字。
3.后来发现asp.net可以用Parameter,只要用Parameter参数的SQL语句或存储过程就能防止注入。
4.后来上CSDN多了,发现用Parameter参数的SQL语句或存储过程不是绝对防止注入的,只要动态拼接SQL或存储过程,即使带Parameter参数,还是能注入的。目前我得出防止SQL注入的观点:
1.带Parameter参数的SQL或储存过程不能动态拼接,否则还是能注入。
2.如果动态拼接SQL或储存过程,在传入字符串类型的数据时,用Replace("'","''"),也能防止注入。但是网上说1个单引号替换成2个单引号,不能完全避免注入。
但是我的理解就是单引号就是注入的灵魂,如果SQL语句的WHERE部分是动态拼接,如:错误的写法:        cmd.CommandText = "SELECT * FROM 表 WHERE 字段='" + username + "'";    
        //这里动态拼接SQL,但是没username = username.Replace("'", "''");所以肯定能注入。
正确的写法:        cmd.CommandText = "SELECT * FROM 表 WHERE 字段=@username";    
        cmd.Parameters.Add("@username", username);
        //这里是标准的命令参数写法,不是动态拼接的SQL我的写法:        username = username.Replace("'", "''");
        cmd.CommandText = "SELECT * FROM 表 WHERE 字段='" + username + "'";    
        //这里动态拼接SQL,但是已经在传入SQL之前就把1个单引号替换成2个单引号,所以我觉得不能注入。网上说用16进制的SQL语句可以绕过单引号和一些类似select,update,delete等关键字进行注入。我想绕过那些关键字,肯定没问题,毕竟都转换成16进制了,然后可以注入了(类似每个varchar类型的字段上都加上<script src="..."></script>或更恶毒的操作),但是我觉得这些注入的前提SQL是动态拼接的,且没把1个单引号替换成2个单引号(我试过确实能注入),既然这样,我是不是只要把1个单引号替换成2个单引号,就能绝对防止字符串类型数据的注入了呢?那些说1个单引号替换成2个单引号,不能完全避免注入的说法,有人能解释说明一下吗?最好有例子。谢谢了。

解决方案 »

  1.   


    1.带Parameter参数的SQL或储存过程不能动态拼接,否则还是能注入。
    动态拼接就注入?
      

  2.   

    就拿网上通用的分页存储过程来说
    它就是动态拼接的先DECLARE SQL,然后拼接SQL,需要的字段,表明,WHERE条件,排序方式等等,很灵活,但是是动态拼接的,
    最后通过EXEC(SQL)来执行,这样肯定能注入。参考链接
    http://www.cnblogs.com/yukaizhao/archive/2007/03/09/pagination_proc_problem.html
      

  3.   

    我一般都是伪静态,不使用ID=?这样的链接,另外也是主要过滤单引号和or ,and等SQL注入的关键字,没有出现过问题
      

  4.   

    其实现在微软推行的ORM框架里面的linq entity 都可以避免写sql语句了,这样的话,被注入的几率又降低了只是效率上可能也会低一些
      

  5.   


    文中,代码declare @strsql varchar(8000)
    declare @strwhere varchar(1000)
    set @strwhere = 'username like ''%jim'' dog%'''
    set @strsql = 'select top 20 *  from [useraccount]  where ' + @strwhere + ' order by id desc'
    exec (@strsql)
    这里必须对 @strwhere 变量中的写法是错误的。还是那句话,要多读读SQL语法。语法中一个字符常量串中的单引号要变为两个单引号,那么如果单引号中还有一个将作为作为字符串常量的内容其中的单引号因为嵌套的关系自然就需要再将两个单引号分别再改为两个单引号,也就是说要写set @strwhere = 'username like ''%jim'''' dog%'''
    这才能说你的 @strwhere 变量中是一个合格的 SQL 语句片段。否则,就只能说是一个胡乱写的字符串,而不是符合SQL语法的。
      

  6.   

    这里必须对 @strwhere 变量中的写法是错误的   -->   这里必须很快意识到 @strwhere 变量中的写法是错误的仔细看一下     'username like ''%jim'' dog%'''既然待匹配的字符串的开头和结尾是两个单引号,那么中间的引号难道还能再写为两个单引号么?实际上比较仔细认真的人一眼就能看出这个问题。
      

  7.   


    并非如此。如果不用程序员去手写存储过程,才能说这个部分基本上可以避免漏洞。手写t-sql存储过程跟写c#等代码一样都有这个问题要注意。
      

  8.   

    正常地来说,假设我们要在t-sql存储过程中拼字符串,我们可以写declare @strsql varchar(8000)
    declare @strwhere varchar(1000)
    set @strsql = 'select top 20 *  from [useraccount]  where username like ''' + replace(@strlike,'''','''''') + ''' order by id desc'
    exec (@strsql)请注意,这才是正确的t-sql编程。如果对T-SQL语法不了解不谨慎,不要过分强求写过多的存储过程,用高级的.net代码来完成程序处理吧,或者开始使用Linq,那样不容易出错。