当前位置:Gxlcms > 数据库问题 > SQL注入问题的深入研究

SQL注入问题的深入研究

时间:2021-07-01 10:21:17 帮助过:6人阅读

 技术分享

  问题来了,当初我在项目里面碰到过这个问题,是采用参数化命令来解决这个问题,那会时间紧没有功夫研究,现在想想,到底是为什么能够通过下面的方式,就能够避免注入了,如果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注入问题的深入研究

标签:

人气教程排行