2011-12-19 9 views
5

Это может быть легко введено здесь, потому что параметр @ID может быть практически любым в этом выражении SQL, введя его, однако, как предотвратить этот эксплойт?Выполнение хранимой процедуры SQL Server Безопасно от 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 
+1

Просто крошечная вещь, которая не сильно влияет на вещи, но разве это не проблема '@ Table', это проблема? '@ ID' является' bigint', поэтому это может быть только число, когда вы достигаете точки построения динамического оператора SQL, не так ли? –

+0

Я полагаю, что оба .. –

ответ

9

Проверить this page, он имеет прекрасный путеводитель по динамическим SQL, и варианты для их выполнения безопасно

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

SELECT @SQL = N'SELECT * FROM ' + quotename(@Table) + N' WHERE ID = @xid' 
EXEC sp_executesql @SQL, N'@xid bigint', @ID 
+0

+1 Для связи с Соммарског. – Oded

+1

+1 в первый раз, когда я действительно знаю кого-то, чья деятельность я натолкнулся на StackOverflow;) – Tao

+0

lol! Привет, Тао! :) –

1

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

0

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

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

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

+0

Благодарим за отзыв, но можете ли вы опубликовать рабочую ссылку о QUOTENAME? –

+0

Не знаете, что там произошло :) Должно работать сейчас. – Gats

0

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

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

Простое размещение имени 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 компилируется, но вы, возможно, придется сглаживать некоторые ошибки, как я Ждут» t достаточно дойти до проверки всех кодов.

Смежные вопросы