Не создайте динамический SQL, как это!Представьте себе, если бы я запустил:
EXEC GenericCountAll '*/DROP PROCEDURE dboGenericCountAll;--', '1);/*';
В результате был бы выполнен SQL:
SELECT COUNT(1);/*) FROM */ DROP PROCEDURE dboGenericCountAll;--
Это просто DROP
ваша процедура.И это просто простой пример.Если бы я знал, что могу продолжать делать злонамеренные действия, я мог бы даже создать новый логин или пользователя и сделать a db_owner
или sysadmin
(в зависимости от разрешений того, что когда-либо использовалось для запуска этой процедуры).
Я тоже не знаю, в чем смысл @@ROWCOUNT
, сомневаюсь, что это необходимо.Таким образом, чтобы сделать это БЕЗОПАСНЫМ, вам нужно сделать что-то вроде этого:
ALTER procedure [dbo].[GenericCountAll]
@TableName sysname, --Note the datatype change
@ColumnName sysname
AS
BEGIN
DECLARE @SQL nvarchar(MAX);
SELECT N'SELECT COUNT(' + QUOTENAME(c.[name]) + N') AS RowCount' + NCHAR(10) +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.name) + N';'
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.[name] = @TableName
AND c.[name] = @ColumnName;
/*
If either the column or the table doesn't exist, then @SQL
will have a value of NULL. This is a good thing, as it
is a great way to further avoid injection, if a bogus
table or column name is passed
*/
IF @SQL IS NOT NULL BEGIN;
PRINT @SQL; --Your best debugging friend
EXEC sp_executesql @SQL;
END ELSE BEGIN;
RAISERROR(N'Table does not exist, or the Column does not exist for the Table provided.',11,1);
END;
END