Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como devo passar um nome de tabela para um proc armazenado?


Em primeiro lugar, você deve NUNCA fazer composições de comandos SQL em um aplicativo cliente como este, isso é o que é injeção de SQL. (Tudo bem para uma ferramenta de administração que não possui privs próprios, mas não para um aplicativo de uso compartilhado).

Em segundo lugar, sim, uma chamada parametrizada para um procedimento armazenado é mais limpa e segura.

No entanto , como você precisará usar o SQL dinâmico para fazer isso, ainda não deseja incluir a string passada no texto da consulta executada. Em vez disso, você deseja usar a string passada para procurar os nomes do real tabelas que o usuário deve ter permissão para consultar no caminho.

Aqui está um exemplo simples e ingênuo:
CREATE PROC spCountAnyTableRows( @PassedTableName as NVarchar(255) ) AS
-- Counts the number of rows from any non-system Table, *SAFELY*
BEGIN
    DECLARE @ActualTableName AS NVarchar(255)

    SELECT @ActualTableName = QUOTENAME( TABLE_NAME )
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME = @PassedTableName

    DECLARE @sql AS NVARCHAR(MAX)
    SELECT @sql = 'SELECT COUNT(*) FROM ' + @ActualTableName + ';'

    EXEC(@SQL)
END

Alguns perguntaram razoavelmente por que isso é mais seguro. Espero que o pequeno Bobby Tables possa deixar isso mais claro:0

Respostas para mais perguntas:

  1. QUOTENAME por si só não é seguro. A MS nos encoraja a usá-lo, mas eles não deram uma garantia de que ele não possa ser enganado por hackers. FYI, segurança real é tudo sobre as garantias. A pesquisa de tabela com QUOTENAME, é outra história, é inquebrável.

  2. QUOTENAME não é estritamente necessário para este exemplo, a tradução Lookup em INFORMATION_SCHEMA sozinha normalmente é suficiente. QUOTENAME está aqui porque é uma boa forma de segurança incluir uma solução completa e correta. QUOTENAME aqui está na verdade protegendo contra um problema potencial distinto, mas semelhante, conhecido como injeção latente .

Devo observar que você pode fazer a mesma coisa com nomes de coluna dinâmicos e o INFORMATION_SCHEMA.COLUMNS tabela.

Você também pode ignorar a necessidade de procedimentos armazenados usando uma consulta SQL parametrizada (consulte aqui:https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters?view=rede-4.8). Mas acho que os procedimentos armazenados fornecem um recurso de segurança mais gerenciável e menos propenso a erros para casos como esse.