Безопасная обработка данных и проверка доступа в хранимых процедурах

В формах, таблицах и других компонентах во всех процедурах нельзя доверять входящим параметрам, кроме @username.

Любые данные злоумышленник может подменить через специальные инструменты.

Причем не всегда спасает даже ограничение по ролям. Например, менеджер может подставить в форму клиента другой @itemID и получить доступ к чужому клиенту.

Нельзя надеяться на то, что в @itemID придет допустимая строка, т.к. пользователь может просто подменить ее в сниппете компонента или в URL.

 

КАК НЕ НАДО ДЕЛАТЬ:  

CREATE PROCEDURE [dbo].[fm_project_saveItem]
   @username nvarchar(256), 
   @itemID int,
   @parameters ExtendedDictionaryParameter readonly
AS
BEGIN
   declare @code nvarchar(max)
   set @code=(select value from @parameters where [key]='code')

   update projects set code=@code where id=@itemID

    -- 1 SELECT (Result, Msg)
    select 1 Result, 'Сохранено' Msg
END

 Это неправильная процедура. Не проверяется входящий пользователь, не проверяется - может ли он изменить код указанного проекта. 

 Корректная процедура:

CREATE PROCEDURE [dbo].[fm_project_saveItem]
   @username nvarchar(256), 
   @itemID int,
   @parameters ExtendedDictionaryParameter readonly
AS
BEGIN
   declare @code nvarchar(max)
   set @code=(select value from @parameters where [key]='code')

   if(dbo.sec_hasProjectRight(@itemID, @username, 'editCode')=0) begin
      select 0 Result, 'No rights' Msg
      return
   end

   update projects set code=@code where id=@itemID

    -- 1 SELECT (Result, Msg)
    select 1 Result, 'Сохранено' Msg
END

Проверяем в процедуре доступ. Если что не так - возвращаем ошибку. Важно доступ проверять именно через функцию, чтобы потом не менять во многих местах проверку доступа.  

Важные нюансы

Шаблон процедуры проверки доступа к некоторой сущности (Проект): 

-- пример функции проверки доступа к Проекту
Create FUNCTION [dbo].[sec_hasProjectRight]  (
         @id int, 
         @username nvarchar(128),
         @right nvarchar(128)  -- edit, read, or other
)
returns bit
AS
BEGIN
    declare @res bit = 0
    if(exists(select 1 from pr_projectUsers 
      where projectID=@projectID and username=@username)) begin
     set @res =1
    end

    return @res
end

 

Страница-источник на сайте falconspace.ru