码迷,mamicode.com
首页 > 数据库 > 详细

SQL注入问题的深入研究

时间:2015-08-18 15:58:53      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:

 

  大家如果写过后台访问数据库的方法,拼接过SQL语句,那么SQL注入的问题一定是大家碰到过的,其表面原因就是用户输入的数据,在拼接SQL语句的过程中,超越了数据本身,成为了SQL语句查询逻辑的一部分,相对于这种问题的解决方案,已经非常成熟了,我就偷懒直接截了个图来贴出解决方案,引用http://www.cnblogs.com/SkySoot/archive/2012/07/16/2593907.html

 技术分享

  问题来了,当初我在项目里面碰到过这个问题,是采用参数化命令来解决这个问题,那会时间紧没有功夫研究,现在想想,到底是为什么能够通过下面的方式,就能够避免注入了,如果ID也是拼接成攻击性的sql语句,为什么就不会产生注入问题。

  string sql = "SELECT * FROM Person where ID = @ID";
  SqlCommand cmd = new SqlCommand(sql, conn);
  cmd.Parameters.AddWithValue("@ID", ID);

  看这个问题首先得看看SqlCommand的编译原理了,虽然这可想而知是一条漫长的路,但是我觉得编程还是需要有颗探究所以然的心,哪怕看不懂,万事开头难。

  我通过ILSpy看了下SQLCommand的源码,从ExcuteNonQuery一直往下深究,我的思路是,总归传入的parameters有地方调用,虽然很多的参数我并不一定知晓其中的原理,但是只要我看到怎么处理parameter时,我就能找到我想要的,于是我一层层往下看,至少往下找了5层吧,发现了这个方法:

        private void BuildExecuteSql(CommandBehavior behavior, string commandText, SqlParameterCollection parameters, ref _SqlRPC rpc)

        {

            int num = this.CountSendableParameters(parameters);

            int num2;

            if (num > 0)

            {

                num2 = 2;

            }

            else

            {

                num2 = 1;

            }

            this.GetRPCObject(num + num2, ref rpc);

            rpc.ProcID = 10;

            rpc.rpcName = "sp_executesql";

            if (commandText == null)

            {

                commandText = this.GetCommandText(behavior);

            }

            SqlParameter sqlParameter = new SqlParameter(null, (commandText.Length << 1 <= 8000) ? SqlDbType.NVarChar : SqlDbType.NText, commandText.Length);

            sqlParameter.Value = commandText;

            rpc.parameters[0] = sqlParameter;

            if (num > 0)

            {

                string text = this.BuildParamList(this._stateObj.Parser, this.BatchRPCMode ? parameters : this._parameters);

                sqlParameter = new SqlParameter(null, (text.Length << 1 <= 8000) ? SqlDbType.NVarChar : SqlDbType.NText, text.Length);

                sqlParameter.Value = text;

                rpc.parameters[1] = sqlParameter;

                bool inSchema = CommandBehavior.Default != (behavior & CommandBehavior.SchemaOnly);

                this.SetUpRPCParameters(rpc, num2, inSchema, parameters);

            }

        }


  大家看到这个标黄的地方,我瞬间明白了,本质上在C#里面调用类库执行sql语句,其实都是在走sp_executesql这个命令,熟悉sql的筒子们都知道,sp_executesql这个命令是用来处理动态sql的,实际上是将数值参数化,要执行的动态Sql是不会变化,即不会重新编译,只是参数在不停的变化。如此就解决了我的疑问,实际上C#并不会去对SQL语句做过多的处理,而是将对应的语句和参数传给SQL去处理。

  这是我在博客园上写的第一篇文章,这个技术点其实也没有特别高深,只是我在工作过程中突然碰到想到了这个问题,然后上网搜也没有对应的解答,所以想要仔细研究下,不管写的怎么样,希望我自己和大家都能有个探索本质的精神,而不是仅仅停留在表面,由此写下来与大家分享下我的心得,谢谢。
  
  如果有什么不对的地方,希望大家指正,谢谢。

  最后粘一段我觉得在我研究过程中比较有用的代码

           private void SetUpRPCParameters(_SqlRPC rpc, int startCount, bool inSchema, SqlParameterCollection parameters)
        {
            int parameterCount = this.GetParameterCount(parameters);
            int num = startCount;
            TdsParser parser = this._activeConnection.Parser;
            bool isYukonOrNewer = parser.IsYukonOrNewer;
            for (int i = 0; i < parameterCount; i++)
            {
                SqlParameter sqlParameter = parameters[i];
                sqlParameter.Validate(i, CommandType.StoredProcedure == this.CommandType);
                if (!sqlParameter.ValidateTypeLengths(isYukonOrNewer).IsPlp && sqlParameter.Direction != ParameterDirection.Output)
                {
                    sqlParameter.FixStreamDataForNonPLP();
                }
                if (SqlCommand.ShouldSendParameter(sqlParameter))
                {
                    rpc.parameters[num] = sqlParameter;
                    if (sqlParameter.Direction == ParameterDirection.InputOutput || sqlParameter.Direction == ParameterDirection.Output)
                    {
                        rpc.paramoptions[num] = 1;
                    }
                    if (sqlParameter.Direction != ParameterDirection.Output && sqlParameter.Value == null && (!inSchema || SqlDbType.Structured == sqlParameter.SqlDbType))
                    {
                        byte[] expr_B4_cp_0 = rpc.paramoptions;
                        int expr_B4_cp_1 = num;
                        expr_B4_cp_0[expr_B4_cp_1] |= 2;
                    }
                    num++;
                }
            }
        }

SQL注入问题的深入研究

标签:

原文地址:http://www.cnblogs.com/akec/p/4730849.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!