zoukankan      html  css  js  c++  java
  • 浅谈SQL注入漏洞以及防范策略

    --HeShiwei 2014-5-15

    什么是SQL注入 

    SQL注入,指的是用户通过向登录框输入恶意字符,利用代码的字符串拼接漏洞进行网站注入攻击,最终导致整个网站用户表信息泄露的攻击方式。黑客就是利用了程序员的字符串拼接sql语句。这个漏洞在几年前很流行,因为利用它实在是太简单。随着近几年程序员安全意识提高,注入漏洞早已不见踪影。

      假如你去面试,HR看到写的程序还在用字符串拼接,基本没戏。但是我们的学校依然教拼接字符串。用winform或 wpf做的XX管理系统,问题也不大因为用的人不多。一旦用asp.Net做网站,还拼接sql语句。后果可想而知。为此专门以Sql Server为例做了一个非常简单的登录验证,说明此问题的严重性:

     这是一个典型的登录案例:

    private string strConn = "server=.\sqlexpress;database=School;uid=sa;pwd=123456";
    
    private void btnConfirm_Click(object sender, EventArgs e)
    {
    if (String.IsNullOrEmpty(txtUserName.Text.Trim())
        || String.IsNullOrEmpty(txtPassWord.Text.Trim()))
    {
        MessageBox.Show("输入错误,请检查!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
        return;
    }
    
    //创建连接对象
    using (SqlConnection conn = new SqlConnection(strConn))
    {
        //创建命令对象
        using (SqlCommand cmd = conn.CreateCommand())
        {
            SqlDataReader dr = null;
            cmd.CommandText = "select * from UserInfo where uName='"+txtUserName.Text.Trim()+"' and uPass='" + txtPassWord.Text.Trim() + "'";
    
            //尝试连接、执行
            try
            {
                conn.Open();
                dr = cmd.ExecuteReader();
            }
            catch (Exception ex)
            {
                MessageBox.Show("数据库错误:"+ex.Message);
                return;
            }
    
            //是否存在数据(存在数据表示登录成功)
            if (dr.HasRows)
            {
                //指针指向第一条数据
                dr.Read();
    
                MessageBox.Show("登录成功 当前登录用户:"+dr.GetString(1));
            }
            else
            {
                MessageBox.Show("此用户不存在!");
            }
    
    
        }
    }

    下面是用户表(UserInfo)的数据:

    当我们在任何一个文本框输入万能字符串:

    ' or '1'='1

    发现一个奇怪的现象:

    为什么会这样,我们看设断点,看看拼出了什么样的sql语句:

    select * from UserInfo where uName='admin' and uPass='' or '1'='1'

    还有一种情况:

    看看凭借出了什么样的sql语句:

    select * from UserInfo where uName='admin'--' and uPass='这里随意输!'

    '--'后面都是被注释的。所以真正执行的是:

    select * from UserInfo where uName='admin'

    这样一来,只要知道任意一个用户名就能登录系统。

    这就是最最简单的一种sql注入漏洞,由此可见程序员一旦不幸使用sql拼接,登录验证就是一摆设。

    注入漏洞的防范措施:使用参数化查询。

    using (SqlCommand cmd = conn.CreateCommand())
    {
        SqlDataReader dr = null;
        //使用参数代替值
        cmd.CommandText = "select * from UserInfo where uName=@name and uPass=@pass";
        //建立参数对象
        cmd.Parameters.Add(new SqlParameter("@name", txtUserName.Text.Trim()));
        cmd.Parameters.Add(new SqlParameter("@pass", txtPassWord.Text.Trim()));
    try { conn.Open(); dr = cmd.ExecuteReader(); } catch (Exception ex) { MessageBox.Show("数据库错误:"+ex.Message); return; } if (dr.HasRows) { dr.Read(); MessageBox.Show("登录成功 当前登录用户:"+dr.GetString(1)); } else { MessageBox.Show("此用户不存在!"); } }

    上面的登录验证太简单,附上一个带15分钟内限定登录次数的。 

    更正之前《登录小案例》密码错3次15分钟内不准登录

    附:SQL语句

    create database School
    go
    use School
    go
    create table UserInfo
    (
        uId int constraint pk_UserInfo_uId primary key(uId) identity(1,1),
        uName nvarchar(32) not null constraint uq_UserInfo_uName unique(uName),
        uPass varchar(16) not null constraint ck_UserInfo_uPass check(len(uPass)>=3),
        uEmail varchar(32) null,
        uErrTimes int not null constraint df_UserInfo_uErrTimes default(0),
        uLastErrTime datetime not null constraint df_UserInfo_uLastErrTime default('1990-1-1')
    )
    go
    insert into UserInfo
    values 
    ('admin','888','137233130@qq.com',default,default),
    ('admin1','999','137233130@qq.com',default,default),
    ('admin2','000','137233130@qq.com',default,default)
    
    
    select * from UserInfo
  • 相关阅读:
    BZOJ2435 NOI2011道路修建
    BZOJ2431 HAOI2009逆序对数列(动态规划)
    BZOJ2456 mode
    BZOJ2324 ZJOI2011营救皮卡丘(floyd+上下界费用流)
    BZOJ2303 APIO2011方格染色(并查集)
    BZOJ2299 HAOI2011向量(数论)
    BZOJ2169 连边(动态规划)
    BZOJ2159 Crash的文明世界(树形dp+斯特林数)
    洛谷 P1306 斐波那契公约数 解题报告
    洛谷 P2389 电脑班的裁员 解题报告
  • 原文地址:https://www.cnblogs.com/hoosway/p/3730607.html
Copyright © 2011-2022 走看看