Обеспечение безопасности хранимых процедур SQL Server от SQL-инъекций - PullRequest
5 голосов
/ 19 декабря 2011

Это может быть легко введено здесь, потому что параметр @ID может быть практически любым в этом операторе SQL, введя его, однако, как вы предотвращаете этот эксплойт?

Я предпочитаю специально предотвращать этот эксплойт в этомуровень, а не уровень приложения, какие-либо предложения?

CREATE PROCEDURE [dbo].[GetDataByID]
@ID bigint,
@Table varchar(150)
AS
BEGIN

Declare @SQL Varchar(1000)

SELECT @SQL = 'SELECT * FROM ' + @Table + ' WHERE ID = ' + CONVERT(varchar,@ID)

SET NOCOUNT ON;

EXEC(@sql)  
END

Ответы [ 4 ]

9 голосов
/ 19 декабря 2011

Проверьте на этой странице , здесь есть замечательное руководство по динамическому sql и опциям для их безопасного выполнения

В вашем случае это должно быть так:

SELECT @SQL =  N'SELECT * FROM ' + quotename(@Table) + N' WHERE ID = @xid' 
EXEC sp_executesql @SQL, N'@xid bigint', @ID
1 голос
/ 19 декабря 2011

1) создать новую таблицу, которая будет иметь идентификационный PK и содержать имена таблиц строк
2) вставить все / только допустимые таблицы, которые вы разрешите в своей процедуре
3) использовать этот идентификационный PK в качествезначение входного параметра (TableID) для хранимой процедуры
4) в процедуре, просто найдите строковое значение (имя таблицы) из заданного идентификатора PK, и вы можете конкатенировать найденную строку в вашем запросе.5) с вашим предложением WHERE все в порядке, поскольку вы передаете int

0 голосов
/ 20 декабря 2011

Хотя я бы посоветовал против динамического sql в целом, в этом случае я думаю, что вы можете обойтись без него, проверив, содержит ли переменная @Table правильное имя таблицы.

  • Вопрос в том, планируете ли вы разрешить имена схем и / или перекрестные запросы к БД, я предполагаю, что вы не хотите выходить из БД (или сервера) здесь, но разрешаетедля разных схем (AdventureWorks показывает, как их можно использовать)
  • Вы МОЖЕТЕ также включить представления для @ Table.
  • Возможно, было бы «хорошо», если бы вы также проверили, найден ли объектна самом деле имеет столбец идентификатора и выдает ошибку, удобную для пользователя, если нет.Необязательно, хотя.

Простое размещение QuoteName () вокруг @table НЕ защитит вас от всего.Хотя отличная функция, она далека от совершенства.ИМХО, лучше всего было бы проанализировать переменную @Table, проверить, является ли ее содержимое допустимым, а затем создать динамический sql на основе полученных частей.Я начал делать большинство из вышеперечисленного, и на удивление, там требуется МНОГО проверки на то, что выглядит так просто, как это =)

CREATE PROCEDURE [dbo].[GetDataByID] ( 
                                        @ID bigint,
                                        @Table nvarchar(300)
                                      )
AS

DECLARE @sql nvarchar(max)

DECLARE @server_name sysname,
        @db_name     sysname,
        @schema_name sysname,
        @object_name sysname,
        @schema_id   int        

SELECT @server_name = ParseName(@Table, 4),
       @db_name     = ParseName(@Table, 3),
       @schema_name = ParseName(@Table, 2),
       @object_name = ParseName(@Table, 1)

IF ISNULL(@server_name, @@SERVERNAME) <> @@SERVERNAME
    BEGIN
        RaisError('Queries are restricted to this server only.', 16, 1)
        Return(-1)
    END

IF ISNULL(@db_name, DB_Name()) <> DB_Name()
    BEGIN
        RaisError('Queries are restricted to this database only.', 16, 1)
        Return(-1)
    END


IF @schema_name IS NULL
    BEGIN
        IF NOT EXISTS ( SELECT *
                          FROM sys.objects
                         WHERE name = @object_name
                           AND type IN ('U', 'V') )
            BEGIN
                RaisError('Requested @Table not found. [%s]', 16, 1, @object_name)
                Return(-1)
            END

        SELECT @sql = 'SELECT * FROM ' + QuoteName(@object_name) + ' WHERE ID = @ID'
    END
ELSE
    BEGIN

        SELECT @schema_id = Schema_id(@schema_name)

        IF @schema_id IS NULL 
            BEGIN
                RaisError('Unrecognized schema requested [%s].', 16, 1, @schema_name)
                Return(-1)
            END

        IF NOT EXISTS ( SELECT *
                          FROM sys.objects
                         WHERE name = @object_name
                           AND schema_id = @schema_id
                           AND type IN ('U', 'V') )
            BEGIN
                RaisError('Requested @Table not found. [%s].[%s]', 16, 1, @schema_name, @object_name)
                Return(-1)
            END

        SELECT @sql = 'SELECT * FROM ' + QuoteName(@schema_name) + '.' + QuoteName(@object_name) + ' WHERE ID = @ID'
    END

EXEC sp_executesql @stmt   = @sql,
                   @params = N'@ID bigint',
                   @ID     = @ID

Return(0)       

Supra компилируется, но вам может понадобиться сгладить некоторые ошибки, как я нене доходит до проверки всех путей кода.

0 голосов
/ 19 декабря 2011

Я бы рекомендовал вообще избегать динамического SQL.Проблемы заключаются в следующем:

  • Очевидный сценарий инъекционного присоединения
  • Атаки с бинарными инъекциями намного умнее и могут обойти традиционное экранирование строк
  • Производительность большая -SQL Server предназначен для управления планами выполнения хранимых процедур, и они будут выполняться быстрее, чем запросы, которые создаются динамически.Если вы используете динамический SQL, нет никакой реальной пользы от использования хранимой процедуры вообще.Если вам нужна гибкость в коде для выбора из нескольких таблиц, вы должны рассмотреть ORM или что-то еще, чтобы сделать ваш код проще.Учитывая, что вы должны передавать таблицу динамически, я бы сказал, что нет никакого смысла в процедуре, подобной описанной выше, и другое решение - лучший вариант.Если вы просто пишете против SQL (т.е. без ORM), то генерирование кода отдельными процессорами будет даже лучшим вариантом.

ПРИМЕЧАНИЕ QUOTENAME НЕ гарантирует, что вы безопасны для инъекций.Усечение инъекции все еще возможно.Прочитайте http://msdn.microsoft.com/en-us/library/ms161953.aspx перед его использованием.

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