Как исправить Inline C # запрос, склонный к внедрению SQL - PullRequest
1 голос
/ 15 марта 2019

Ниже приведен мой запрос, который я написал, чтобы получить простое максимальное значение для данного предложения where.

Единственная проблема состоит в том, что он должен пройти сканирование veracode, которое определяет, склонен ли запрос к какой-либо инъекции SQL.

Это мой запрос

string strconnectionString = @Data Source = xxx\server; Initial Catalog =DBname;

Это пользовательские вводные данные, которые я сейчас просто прописываю

private DateTime? GetFirmsLastDate()
{
    // My user inputs hardcoded for now 
    string tableName = "abc";
    string columnName = "CalculationTable";
    string filterColumn = "CalcValue";
    string firmName = "Bank1";

    using(SqlConnection connection = new SqlConnection(strconnectionString)
    {
        using(Sqlcommand cmd = new SqlCommand())
        {
            cmd.Connection = connection;
            cmd.CommandType = System.Data.CommandType.Text;

            cmd.CommandText = String.Format(@"Select MAX(K.{3}) FROM {1} K WHERE K.{2} ={0}" ,
                                             Sanitizer.GetSafeHtmlFragment(firmName), 
                                             Sanitizer.GetSafeHtmlFragment(tableName),
                                             Sanitizer.GetSafeHtmlFragment(filterColumn),
                                             Sanitizer.GetSafeHtmlFragment(column)

            connection.Open();
            object dateVal = cmd.ExecuteScalar();

            return (dataVal != DBNull.Value) : DateTime.Parse(dateVal.ToString()) : null;
        }
    }
}

Почему мне пришлось использовать встроенный запрос TableName,Это текстовое поле, в котором пользователь может ввести имя таблицы.Я не могу указать tableName в качестве параметра для этой цели, я должен подготовить свое заявление при передаче SqlCommand.

Спасибо за ваше время.

1 Ответ

1 голос
/ 15 марта 2019

Единственный способ, которым я могу думать о том, чтобы сделать это "безопасно", - это изменить свой встроенный запрос на параметризованный вызов хранимой процедуры, а затем изящно обработать имена объектов там. Это, однако, требует, чтобы у проверяемого столбца всегда был один и тот же тип данных (в данном случае я предположил int):

CREATE PROC TableMaxCount @Table sysname, @Column sysname, @Value int AS
BEGIN

      DECLARE @SQL nvarchar(MAX);
      SET @SQL = N'SELECT MAX(' + QUOTENAME(@Column) + NCHAR(13) + NCHAR(10) +
                 N'FROM ' + QUOTENAME(@Table) + NCHAR(13) + NCHAR(10) +
                 N'WHERE ' + QUOTENAME(@Column) + N' = @Value;';
      EXEC sp_executesql @SQL, N'@Value int', @Value = @Value;

END

Это, однако, приведет к ошибке, если пользователь введет значение, которое не является таблицей или столбцом для чтения. Если это нежелательно, и вы хотите проверить имена объектов, вы можете сделать что-то более похожее на это:

CREATE PROC TableMaxCount @Table sysname, @Column sysname, @Value int AS
BEGIN

      DECLARE @SQL nvarchar(MAX);
      SELECT @SQL = N'SELECT MAX(' + QUOTENAME(c.[name]) + NCHAR(13) + NCHAR(10) +
                    N'FROM ' + QUOTENAME(t.[name]) + NCHAR(13) + NCHAR(10) +
                    N'WHERE ' + QUOTENAME(c.[name]) + N' = @Value;'
      FROM sys.tables t
           JOIN sys.columns c ON t.object_id = c.object_id
           JOIN sys.schemas s ON t.schema_id = s.schema_id
      WHERE t.[name] = @Table
        AND c.[name] = @Column
        AND s.[name] = N'dbo'; --Assumes always dbo schema

      EXEC sp_executesql @SQL, N'@Value int', @Value = @Value;

END

Боюсь, мой C # в лучшем случае ужасен, но, надеюсь, вы уже знаете, как использовать параметризованный код для вызова SQL. Если нет, я знаю, что документация действительно охватывает это. ( Свойство SqlCommand.Parameters )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...