Доступ приложения к процедурам SQL Server без db_owner
Выдавайте права на операции через роли, учитывайте цепочки владения и динамический SQL и проверяйте фактический доступ ограниченной учётной записи.
Приложению, которому нужна только сводка счетов, не требуется изменять все таблицы или схему базы. Выдача db_owner может убрать ошибки развёртывания, одновременно скрыв реальные зависимости. Небольшую поверхность разрешений проще проверять и сохранять стабильной по мере роста системы.
Хранимые процедуры способны стать такой границей, если их содержимое и отношения владения понятны. Важно не только наличие соединения, но и то, какие чтения и записи приложение выполняет через конкретные разрешённые точки входа.
Выдаём операцию через роль
Пример создаёт учебную таблицу с адресами и процедуру, возвращающую только количество и сумму. Используйте одноразовую базу. GO является разделителем пакетов клиента; драйверу без его поддержки нужно отправлять части отдельно.
-- Run in a disposable practice database as its administrator.
CREATE TABLE dbo.PermissionInvoiceDemo (
InvoiceId int PRIMARY KEY,
CustomerEmail nvarchar(200) NOT NULL,
Total decimal(12,2) NOT NULL
);
INSERT dbo.PermissionInvoiceDemo VALUES
(1, N'example1@example.invalid', 40.00),
(2, N'example2@example.invalid', 60.00);
GO
CREATE PROCEDURE dbo.GetInvoiceSummaryDemo
AS
BEGIN
SET NOCOUNT ON;
SELECT COUNT_BIG(*) AS InvoiceCount, SUM(Total) AS InvoiceTotal
FROM dbo.PermissionInvoiceDemo;
END;
GO
CREATE ROLE InvoiceSummaryReaderDemo AUTHORIZATION dbo;
CREATE USER InvoiceReportUserDemo WITHOUT LOGIN;
ALTER ROLE InvoiceSummaryReaderDemo ADD MEMBER InvoiceReportUserDemo;
GRANT EXECUTE ON OBJECT::dbo.GetInvoiceSummaryDemo
TO InvoiceSummaryReaderDemo;
WITHOUT LOGIN намеренно создаёт пользователя для локальной проверки разрешений, а не реальную учётную запись соединения. При развёртывании создайте или сопоставьте настоящего пользователя приложения согласно существующей аутентификации и включите его в узкую роль.
Роль получает EXECUTE на одну процедуру без общего SELECT на таблицу. Оба объекта имеют общего владельца через dbo, а запрос процедуры статический. Непрерывная цепочка владения позволяет авторизовать вызов без отдельного требования табличного разрешения вызывающего пользователя.
Ожидаются два счёта с суммой 100,00. Адреса не возвращаются. Это демонстрация объектной границы, а не универсальная гарантия конфиденциальности: агрегаты по маленьким группам тоже способны раскрывать сведения и требуют проверки.
Понимаем пределы защиты
Отсутствие прямого доступа не делает процедуру автоматически безопасной. Произвольные имена объектов, непроверенный динамический SQL и возврат строк всех арендаторов могут предоставлять чрезмерные возможности. Содержимое процедуры нужно рассматривать вместе с разрешением на вызов.
Динамический SQL не получает ту же гарантию статической цепочки владения. sp_executesql с параметрами решает передачу значений и снижает риск инъекции, но автоматически не выдаёт права на сформированный оператор. Назначение db_owner приложению не является подходящим исправлением.
Для необходимого динамического или межграничного доступа рассмотрите строго ограниченную подпись модуля либо осознанно выбранный контекст выполнения. Сертификатная подпись может добавлять узкие права на время исполнения. После изменения модуля требуется повторная подпись, поэтому этот шаг должен присутствовать в развёртывании. Управление сертификатом и точные возможности должны оставаться проверяемыми.
Не включайте TRUSTWORTHY или широкие межбазовые цепочки владения ради обычного исправления одного отказа. Они меняют намного большую границу доверия. Проектируйте конкретную межбазовую операцию явно.
Проверяем ограниченную идентичность
Успешный запуск от sysadmin почти ничего не доказывает о правах приложения. Этот контролируемый тест выполняет сводку от ограниченного пользователя и возвращает исходный контекст даже при ошибке.
EXECUTE AS USER = N'InvoiceReportUserDemo';
BEGIN TRY
EXEC dbo.GetInvoiceSummaryDemo;
END TRY
BEGIN CATCH
REVERT;
THROW;
END CATCH;
REVERT;
Отдельно убедитесь, что прямое чтение CustomerEmail запрещено. Проверяйте разрешённые и запрещённые действия. Одних GRANT в каталоге недостаточно: членство в ролях, прямые права, DENY, владение и старшие привилегии меняют фактический результат.
Разделите идентичности развёртывания и обычного выполнения. Развёртывание может создавать процедуры; пользовательские запросы не должны наследовать эту возможность. Новая операция получает конкретное разрешение вместо расширения роли на все существующие и будущие объекты.
Осторожно оценивайте EXECUTE уровня схемы. Он подходит для сознательно управляемой API-схемы, но автоматически распространяется на будущие процедуры. Это решение управления доступом, а не просто сокращённая запись.
Включите содержательную проверку в выпуск: поддерживаемые операции выполняются, защищённые столбцы напрямую недоступны, объекты нельзя изменять. Дополнительно проверьте отсутствие широких ролей у настоящего пользователя: ограниченный учебный тест не обнаружит лишние права производственной учётной записи. Так случайное расширение привилегий становится заметным до превращения в постоянную конфигурацию.
Техническая документация: Microsoft Learn: Database Engine permissions · Microsoft Learn: GRANT object permissions · Microsoft Learn: Sign a procedure with a certificate.