Correct escaping of delimited identifers in SQL Server without using QUOTENAME

后端 未结 2 1290
滥情空心
滥情空心 2021-01-02 05:34

Is there anything else that the code must do to sanitize identifiers (table, view, column) other than to wrap them in double quotation marks and \"double up\" double

2条回答
  •  没有蜡笔的小新
    2021-01-02 06:26

    Your QuoteName function needs to check the length, because the T-SQL QUOTENAME function specifies the maximum length it returns. Using your example:

    String.Format(@"declare @delimitedIdentifier nvarchar(258);
    set @delimitedIdentifier = {0};", QuoteName(identifier));
    

    If QuoteName(identifier) is longer than 258 characters, it will be silently truncated when assigned to @delimitedIdentifier. When that happens, you open up the possibility for @delimitedIdentifier to be escaped improperly.

    There is an MSDN article by Bala Neerumalla, a "security software developer at Microsoft", that explains the topic in more depth. The article also contains the closest thing I have found to "definitive documentation about how to escape quoted identifiers in SQL Server":

    The escaping mechanism is simply doubling up the occurrences of right square brackets. You don't need to do anything with other characters, including left square brackets.

    This is the C# code I am currently using:

    /// 
    /// Returns a string with the delimiters added to make the input string
    /// a valid SQL Server delimited identifier. Brackets are used as the
    /// delimiter. Unlike the T-SQL version, an ArgumentException is thrown
    /// instead of returning a null for invalid arguments.
    /// 
    /// sysname, limited to 128 characters.
    /// An escaped identifier, no longer than 258 characters.
    public static string QuoteName(string name) { return QuoteName(name, '['); }
    
    /// 
    /// Returns a string with the delimiters added to make the input string
    /// a valid SQL Server delimited identifier. Unlike the T-SQL version,
    /// an ArgumentException is thrown instead of returning a null for
    /// invalid arguments.
    /// 
    /// sysname, limited to 128 characters.
    /// Can be a single quotation mark ( ' ), a
    /// left or right bracket ( [] ), or a double quotation mark ( " ).
    /// An escaped identifier, no longer than 258 characters.
    public static string QuoteName(string name, char quoteCharacter) {
        name = name ?? String.Empty;
        const int sysnameLength = 128;
        if (name.Length > sysnameLength) {
            throw new ArgumentException(String.Format(
                "name is longer than {0} characters", sysnameLength));
        }
        switch (quoteCharacter) {
            case '\'':
                return String.Format("'{0}'", name.Replace("'", "''"));
            case '"':
                return String.Format("\"{0}\"", name.Replace("\"", "\"\""));
            case '[':
            case ']':
                return String.Format("[{0}]", name.Replace("]", "]]"));
            default:
                throw new ArgumentException(
                    "quoteCharacter must be one of: ', \", [, or ]");
        }
    }
    

提交回复
热议问题