2014-01-04 1 views
1

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

Я ищу лучший способ проверить, что поставляемый запрос имеет только тип SELECT - это означает, что пользователь не может запустить DELETE, UPDATE и т. Д. Конечно, проверка должна быть на стороне сервера. Проект написан на C#.

Первой проверкой является проверка того, что запрос начинается с SELECT, но этого недостаточно из-за подзапросов. Я думал проверить, содержит ли строка запроса (C#) некоторые зарезервированные слова, такие как EXEC, DELETE, UPDATE, INSERT.

Есть ли способы «взломать» эту проверку (используя & nbsp или другие символы)? Какие зарезервированные слова должны быть заблокированы? Любые другие мысли или идеи?

Большое спасибо за ваше время!

+0

Если безопасность очень важна, не делайте этого. Подумайте о другом подходе! – Kaf

+0

Вы хотите разрешить использование определенных пользователем функций? Можете ли вы достичь желаемого уровня безопасности, ограничив доступ, то есть только предоставляя доступ для чтения к данным, которые пользователь должен уметь видеть? – HABO

+0

@Kaf нет никакого другого подхода для реализации требования (по крайней мере, я не вижу) – Vlad

ответ

0

Можете ли вы предоставить пользователю ограниченный графический интерфейс, где они могут нажимать на кнопку? Таким образом, запрос корректен по построению.

Следующая идея заключалась бы в создании специального пользователя, который имеет только права доступа. Это должно быть на 100% надежным в соответствии с документами (если бы это было не так, было бы невозможно защитить сервер). Но я не доверяю этому 100%, потому что могут быть ошибки в SQL Server или ваша реализация безопасности. Определите, достаточно ли этого для вас.

В качестве альтернативы, используйте SMO для анализа запроса и проверки его. Убедитесь, что он соответствует белому списку (например, точно один SELECT, никаких вызовов функций, нет EXEC, ...). Это трудно.

+0

Раньше мы использовали point-and-click, но он слишком ограничен - пользователь должен иметь возможность создавать сложные запросы. Я не думаю, что создание специального типа пользователя является опцией, поскольку тот же пользователь также может запускать большое количество других запросов (программное обеспечение определено). Белые списки запросов, кажется, путь, но, как вы сказали, трудно думать обо всех сценариях. Любая помощь очень ценится! – Vlad

+2

Не можете ли вы использовать ограниченного пользователя только для этого отчета? Просто измените строку соединения для этого запроса. IMO - это единственный практический способ разрешить запросы свободной формы. Вы даже можете использовать Resource Governor для ограничения использования ресурсов и обеспечения безопасности запросов. Попросите выполнить запрос под изоляцией SNAPSHOT, чтобы сделать его безопасным для параллелизма (без блокировки, без блокировки). Установите низкий CommandTimeout. – usr

2

Я также думаю, что использование ограниченного пользователя для запросов - хорошая идея, но если вы выполняете парсер, я бы использовал классы, предоставленные в Microsoft.SqlServer.Management.SqlParser.Parser namespace. В частности, используйте Scanner class для tokenize строки запроса, затем черный список жетонов или шаблонов жетонов, соответствующих операциям, которые вы пытаетесь предотвратить. Это полезно для обработки крайних случаев, когда запрещенные ключевые слова фактически содержатся в квадратных скобках или кавычках и не используются в качестве команд. Код, чтобы сделать это будет выглядеть примерно так:

Scanner scanner = new Scanner(new ParseOptions()); 
string query = "DELETE FROM MyTable WHERE 0 = 1"; 
scanner.SetSource(query, 0); 
int state = 0, start, end, token; 
bool pair, param; 
do { 
    token = scanner.GetNext(ref state, out start, out end, out pair, out param); 
    // Do some stuff here with the token 
} while (token != 128); // 128 signifies the end of the query 

Если вы исследуете значения, присвоенные token, вы увидите, что значения совпадают с порядком лексем в запросе, поэтому значение 226 соответствует DELETE, 242 - FROM и т. д. Вы также можете использовать начальный и конечный выходы для проверки самого токена. Насколько мне известно, на странице документации нет ссылок на все номера токенов, поэтому вам придется немного поиграть с ними, чтобы выяснить, какие номера совпадают с токенами, которые вы смотрите.

DLL для пространства имен можно найти на C: \ Windows \ assembly \ Microsoft.SqlServer.Management.SqlParser.dll. Надеюсь, это поможет.

+0

Спасибо за обмен, я никогда не слышал о токен-сканере раньше – Vlad

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