Unsafe SQL code Injection Inspector


// /r:"C:\Program Files\Microsoft Visual Studio 10.0\VSTSDB\Deploy\Microsoft.Data.Schema.ScriptDom.dll";"C:\Program Files\Microsoft Visual Studio 10.0\VSTSDB\Deploy\Microsoft.Data.Schema.ScriptDom.Sql.dll"
namespace Microsoft.Security.Application.SecurityRuntimeEngine.PlugIns
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using Data.Schema.ScriptDom;
    using Data.Schema.ScriptDom.Sql;
    public class SqlInjectionInspector //: IRequestInspector, IConfigurablePlugIn
    {
        /// <summary>
        /// Returns a value indicating if the specified input could be a SQL injection attempt.
        /// </summary>
        /// <param name="input">The input to check.</param>
        /// <returns>True if the input is a possible SQL injection attempt, otherwise false</returns>
        private static bool IsSqlInjectible(string input)
        {
            return DetectCompleteSql(input) || DetectPartialSql(input) || DetectLogicInjection(input);
        }
        /// <summary>
        /// Detects logic short circuit attempts.
        /// </summary>
        /// <param name="input">The input to check.</param>
        /// <returns>True if a logic short circuit has been detected, otherwise false.</returns>
        private static bool DetectLogicInjection(string input)
        {
            // First determine whether there are two or more instances of single quotes.
            // This could potentially be SQL that attempts to change logic in a SQL query.
            int firstSingleQuoteIndex = input.IndexOf("'", StringComparison.Ordinal);
            // If there is no single quote in the input, then logic injection attack is unlikely.
            if (firstSingleQuoteIndex == -1)
            {
                return false;
            }
            int lastSingleQuoteIndex = input.LastIndexOf("'", StringComparison.Ordinal);
            // If there is only one single quote in the input, then logic injection attack is unlikely.
            if (firstSingleQuoteIndex == lastSingleQuoteIndex)
            {
                return false;
            }
            /* At this point, there is more than one single quote in the input.
             * Strip out any quotes after the first instance and then pass it to the parser.
             * For example, consider the query: select * from users where username=’ ” + param + “ ‘ “.
             * 
             * Input attack vectors:
             * (a) someText' or username='alias
             * (b) a' or 'a'='a
             * 
             * This function is designed to catch these types of attacks. */
            /* split the input into two sections. First variables contains everything from the
             * start to the first occurrence (including) of the single quote.
             * The second half contains everything after the first occurrence of the single quote. */
            string firstHalf = input.Substring(0, firstSingleQuoteIndex + 1);
            string secondHalf = input.Substring(firstSingleQuoteIndex + 1);
            /* Strip out any single quotes */
            secondHalf = secondHalf.Replace("'", string.Empty);
            string finalScrubbedInput = firstHalf + secondHalf;
            TSql100Parser parser = new TSql100Parser(false);
            IList<ParseError> errors;
            /* Try input with permutation. If input completes an invalid and partial SQL,
             * then there is potential for an attack. This will capture cases where
             * attackers attempt to escape out of valid SQL or modify logic. (i.e. OR 1=1)
             */
            const string SqlCommandPrefix = "SELECT * FROM USERS WHERE ID='";
            string completeSql = SqlCommandPrefix + finalScrubbedInput;
            using (StringReader sr = new StringReader(completeSql))
            {
                parser.Parse(sr, out errors);
            }
            return errors == null || errors.Count <= 0;
        }
        /// <summary>
        /// Detects partial SQL command injection.
        /// </summary>
        /// <param name="input">The input to check.</param>
        /// <returns>True if a partial command has been detected, otherwise false.</returns>
        private static bool DetectPartialSql(string input)
        {
            // Only processing input greater than 2 characters
            if (input.Length < 3)
            {
                return false;
            }
            TSql100Parser parser = new TSql100Parser(false);
            IList<ParseError> errors;
            // Try input with permutation. If input completes an invalid and partial SQL,
            // then there is potential for an attack. This will capture cases where
            // attackers attempt to escape out of valid SQL or modify logic. (i.e. OR 1=1)
            const string StartSql = "SELECT * FROM USERS WHERE ID='";
            string completedSql = StartSql + input;
            using (StringReader sr = new StringReader(completedSql))
            {
                parser.Parse(sr, out errors);
            }
            return errors == null || errors.Count <= 0;
        }
        /// <summary>
        /// Detects a complete SQL command in the specified input.
        /// </summary>
        /// <param name="input">The input to check.</param>
        /// <returns>True if a logic short circuit has been detected, otherwise false.</returns>
        private static bool DetectCompleteSql(string input)
        {
            // Parser treats strings of length 1 or 2 as stored procedure calls. These will be skipped as they do not form complete SQL.
            input = input.Trim();
            string[] numberOfTokens = input.Split(' ');
            if (numberOfTokens.Length < 3)
            {
                return false;
            }
            // Try input in raw format. Detects complete SQL.
            using (StringReader sr = new StringReader(input))
            {
                TSql100Parser parser = new TSql100Parser(false);
                IList<ParseError> errors;
                parser.Parse(sr, out errors);
                return errors == null || errors.Count <= 0;
            }
        }
    }
}

posted @ 2011-05-26 00:50  于斯人也  阅读(658)  评论(0编辑  收藏  举报