SQL Server 2008: насколько безопасна хранимая процедура CLR, загружающая неуправляемые библиотеки

У нас есть обычная (т. Е. Не расширенная) хранимая процедура в SQL Server 2000, которая вызывает внешний исполняемый файл. Этот exe, в свою очередь, загружает .dll, полученный из SDK, и вызывает из него некоторые процедуры (например, Init, DoStuff, Shutdown).

Единственная причина, по которой у нас есть этот внешний исполняемый файл, заключается в том, что мы не хотели создавать расширенную хранимую процедуру, которая вызывала бы .dll. Мы полагали, что если dll выйдет из строя (что маловероятно, но все же), то процесс SQL Server также выйдет из строя, а это не то, что мы хотели. С внешним exe только этот exe вылетит.

Сейчас мы обновляем SQL Server 2008 и рассматриваем возможность создания хранимой процедуры CLR, которая вызывает это, и, следовательно, избавляемся от exe. Этот SP, конечно, будет помечен как НЕБЕЗОПАСНЫЙ. В связи с этим возникает вопрос, безопасно ли (безопаснее, достаточно безопасно и т. Д.) Делать это таким образом по сравнению с расширенным подходом SP?

Единственная важная вещь, которую я выследил на BOL, это:

Указание UNSAFE позволяет коду в сборке выполнять недопустимые операции с пространством процессов SQL Server и, следовательно, потенциально может поставить под угрозу надежность и масштабируемость SQL Server.

, но я не уверен, отвечает ли он на мой вопрос, потому что я не за «надежностью и масштабируемостью», а за стабильностью и поддержанием работоспособности.

PS: Мы хотим избавиться от exe, потому что он вызывает неудобства при управлении разрешениями SP (вы знаете, что то, что внезапно применяется к вам, если вы вызываете SP, который содержит xp_cmdshell).


person GSerg    schedule 15.04.2009    source источник
comment
Можете ли вы перепроектировать свой процесс, чтобы он был более разрозненным? Поместите вашу работу в таблицу очереди и попросите внешний процесс забрать работу из очереди и записать результат обратно? Есть много способов вызвать вещи «вне процесса». Это зависит от того, действительно ли он должен быть в процессе или нет (т. Е. Нужны ли результаты немедленно).   -  person Nick.McDermaid    schedule 08.04.2016


Ответы (2)


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

Интеграция со средой CLR намного более надежна, чем расширенные хранимые процедуры, но код по-прежнему выполняется внутри процесса, поэтому ошибки могут вывести из строя или повредить SQL Server. (Для сравнения: теоретически процедура SAFE CLR не сможет повредить SQL Server, хотя даже она может вызвать проблемы, снижающие доступность вашего сервера без полного отключения SQL Server.)

По сути, единственные способы избежать сбоя SQL Server в этом сценарии:

  1. Избегайте использования функциональности, которая дает сбой.
  2. Исправьте ошибочный код.
  3. Запустите код в отдельном процессе (запустите исполняемый файл, вызовите службу Windows, вызовите веб-службу и т. Д.). Вы можете написать управляемую .NET DLL для выполнения этого взаимодействия. Скорее всего, вам все равно нужно будет загрузить его НЕ БЕЗОПАСНО, но - если он написан правильно - на самом деле это может быть довольно безопасно.
person Jason Kresowaty    schedule 04.07.2009

В связи с этим возникает вопрос, безопасно ли (безопаснее, достаточно безопасно и т. Д.) Делать это таким образом по сравнению с подходом расширенного SP?

В общем да. Я имею в виду, что если вы выполняете оболочку для процесса ОС, то вы выполняете оболочку для процесса ОС. Я не понимаю, как использование API расширенных хранимых процедур для этого обязательно будет безопаснее, чем API SQLCLR, особенно когда сбой может произойти из-за процесса ОС, находящегося вне базы данных.

Конечно, я не уверен в XP API, поскольку не использовал его, но я знаю следующее:

  • XP API устарел, и рекомендуется, чтобы все новые проекты, которые можно было реализовать с помощью любой из этих технологий, выполнялись в SQLCLR.
  • SQLCLR допускает более детальные разрешения, чем два других, включая возможность олицетворения (если вход в систему, выполняющий объекты SQLCLR, является входом в Windows).
  • SQLCLR API разделяется с точки зрения процесса и памяти как владельцем базы данных, так и владельцем сборки (т. Е. Пользователем, указанным в предложении AUTHORIZATION). Следовательно, у вас может возникнуть проблема со сборкой в ​​одной БД, не затрагивая объекты SQLCLR в других БД (или даже в той же БД, если есть сборки, принадлежащие другому пользователю, хотя на практике это, вероятно, редко когда-либо случается, поскольку большинство людей просто используйте значение по умолчанию dbo).

Я не уверен, отвечает ли он на мой вопрос, поскольку я не за «надежностью и масштабируемостью», а за стабильностью и поддержанием работоспособности.

Что ж, безусловно, есть вещи, которые вы можете делать в SQLCLR, когда для Assembly установлено значение UNSAFE:

  • потенциально запись в реестр (в зависимости от доступа, предоставленного учетной записи входа в систему, выполняющей процесс SQL Server, или входа в систему, выполняющего функцию SQLCLR, если олицетворение включено, и это вход в систему Windows).
  • потенциально писать в файловую систему
  • потенциально взаимодействовать с процессами, запущенными в системе
  • совместно использовать память с другими SPID SQL Server (то есть сеансами), выполняющими функции из той же сборки (что означает, что конкретная сборка в этой БД принадлежит этому пользователю). Это, вероятно, ускользает от людей больше всего, поскольку это неожиданно, когда вы привыкли к консольным приложениям и приложениям Windows, имеющим свои собственные индивидуальные пространства памяти, но здесь, поскольку это один домен приложений для каждой сборки на каждую БД на каждого владельца, все сеансы, выполняющие этот код, имеют общий доступ все static переменные. Большая часть кода написана с предположением, что AppDomain является частным, и поэтому хранение значений в статических переменных эффективно, поскольку оно кэширует значение, но в SQLCLR вы можете получить неожиданное поведение, если два процесса перезаписывают значения друг друга и читают другие. значение сеанса.
  • потенциальные утечки памяти. Атрибуты защиты хоста пытаются помешать вам использовать встроенные функции .NET, которые могли бы это сделать, например, использование TimeZoneInfo для преобразования времени между идентификаторами TimeZoneID, но атрибуты защиты хоста не применяются к UNSAFE сборкам.
  • Возможно, что поток, выполняющий метод SQLCLR, обрабатывается по-другому при выполнении кода UNSAFE / FullTrust (совместная многозадачность против вытесняющего). Я думал, что читал, что потоки UNSAFE управляются по-другому, но я не уверен, где это читал, и ищу источник.

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

Итак, что вы можете сделать, это либо:

  1. продолжайте вызывать EXE с помощью оболочки SQLCLR для Process.Start(). Это дает вам как разделение процесса / памяти , так и возможность более легко управлять разрешениями для одной хранимой процедуры, которая будет вызывать только этот EXE-файл, и никто не может его изменить (по крайней мере, без изменения этого кода SQLCLR. и переустановка сборки).

  2. установите экземпляр SQL Server Express на тот же компьютер, загрузите туда объекты SQLCLR и создайте связанные серверы в обоих направлениях (от текущего экземпляра SQL Server к новому экземпляру SQL Server Express и обратно), чтобы вы могли легко обмениваться данными между ними. Это позволит вам поместить выполнение SQLCLR в карантин и уберечь его от основного процесса SQL Server.

Конечно, все все сказано, насколько это действительно беспокоит? Это означает, насколько вероятно, что процесс полностью выйдет из строя и уничтожит все вместе с ним? Конечно, это не невозможно, но обычно сбой приводит к отключению только AppDomain, а не самого хоста CLR. Я думаю, что гораздо более вероятно, что код, который не дает сбоев, но написан плохо и потребляет слишком много памяти и / или процессора, будет проблемой, с которой люди столкнутся.

person Solomon Rutzky    schedule 08.04.2016
comment
Да, я знаю, что XP API устарел, но опять же, вопрос с 2009 года :). В конце концов, мы сохранили внешний процесс как отдельный exe, и это было нормально. Мы также стали свидетелями несвязанной, чисто хранимой процедуры CLR, время от времени извлекающей весь SQL-сервер (она использовала HttpWebRequest, а иногда при медленном соединении приводила к сбою с исключением, которое невозможно было поймать, даже если оно находилось внутри try block, из-за которого весь .NET рушится с забавным сообщением журнала, которое также отключает сервер), после чего указанная процедура также была перенесена в отдельный exe. - person GSerg; 08.04.2016
comment
@GSerg Да, я понимаю, что этот вопрос был задан много лет назад, но решил, что сделаю ответ точным для всех, кто читает сейчас, тем более, что XP API устарел, когда был выпущен SQL Server 2005 ;-). Что касается сбоя, который вы видели в связи с HttpWebRequest, вы помните какие-либо подробности? Я хотел бы это задокументировать. У меня есть идея, но я не понимаю, как это может вызвать сбой. Большинство людей не знают, что по умолчанию веб-соединения ограничены двумя на URI, дополнительные запросы ждут в очереди, поэтому у вас могут закончиться потоки. У вас еще есть записи об этом забавном сообщении в журнале? - person Solomon Rutzky; 08.04.2016
comment
Появилось сообщение. Произошла фатальная ошибка в среде CLR .NET Framework. SQL Server завершает работу. Если ошибка повторяется после перезапуска сервера, обратитесь в службу поддержки клиентов. - person GSerg; 08.04.2016
comment
У нас также есть следы стека из аварийных дампов; Исходя из этих трассировок стека, наша лучшая интерпретация заключалась в том, что при чтении ошибки из сетевого сокета (например, в искаженном TCP-пакете) среда выполнения создает и раскручивает стек, уничтожая все управляемые объекты, включая удаление исходного сокета. Это удивляет деструктор сокета, он также выдает ошибку, что приводит к двойной ошибке, и среда выполнения рушится. - person GSerg; 08.04.2016
comment
@GSerg Интересно. Спасибо, что поделились этими подробностями. Интересно, была ли это проблема с CLR v2 или, в частности, с одной из связанных версий Framework (2.0, 3.0 и 3.5). Если это так, то я полагаю, что это не будет проблемой для SQL Server 2012 и новее, поскольку он находится на CLR v4.0 (версии Framework 4.0 и новее). Интересно, как это можно проверить / как можно принудительно / смоделировать такую ​​сетевую ошибку. - person Solomon Rutzky; 08.04.2016