AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 307467
Accepted
Martin Riddar
Martin Riddar
Asked: 2022-02-15 05:43:38 +0800 CST2022-02-15 05:43:38 +0800 CST 2022-02-15 05:43:38 +0800 CST

允许创建表(动态名称)并插入但仅此而已

  • 772

我正在尝试找到一种方法,允许应用程序在 SQL Server 2019 上创建表并将数据插入其中,同时防止注入攻击,以防应用程序凭据泄漏。在编写可以并行运行的代码和编写不受 sql 注入攻击的动态 sql 时,我的经验是有限的。
表名基于来自应用程序的输入,即如果输入为“nds”,则表名应为lake.nds_raw_log。
据我了解,没有办法通过直接授予此应用程序的角色权限来执行此操作,因为创建表与删除或更改它们没有分开。

我想出的是作为 dbo 执行存储过程。当然它不长,但我有两个问题:

  • 感觉很做作,根据我的经验,有一种更简单的方法。
  • 我相信如果我在查询新创建的表时检索到错误的表,我需要将它作为可序列化运行以避免孤立表。这实际上不应该是一个大问题,因为它不会在第一次开始生产后经常发生,所以也许我不应该关心它。
    create procedure [lake].[create_terminal_raw_log_table]
    (
        @terminal_name nvarchar(100)
    )
    with execute as 'dbo'
    as
        begin try
            set transaction isolation level serializable
            begin transaction
                --create table
                declare @dynamic_sql nvarchar(1000) =
                    'create table [lake].' + quotename(@terminal_name) + '
                    (
                        id bigint not null,
                        [timestamp] datetime2(3) not null,
                        cmd varbinary(max) not null
                    );'
                exec sp_executesql @dynamic_sql
    
                /*get name of new table, this is why I believe that I need serializable isolation
                since other tables can be created in parallel*/
                declare @table_name nvarchar(100) =
                (
                    select top 1
                        [name] as table_name
                    from sys.tables
                    order by create_date desc
                )
        
                --rename table
                declare
                    @old_name nvarchar(100) = '[lake].' + @table_name,
                    @new_name nvarchar(100) = @table_name + '_raw_log'
                begin try
                    exec sp_rename
                        @objname = @old_name,
                        @newname = @new_name
                end try
                begin catch
                    set @dynamic_sql = 'drop table ' + @old_name
                    exec sp_executesql @dynamic_sql
                    ;throw
                end catch
    
                --create primary key
                set @dynamic_sql = 'alter table [lake].' + @new_name + ' add constraint pk__' + @new_name + ' primary key(id)'
                exec sp_executesql @dynamic_sql
    
            commit transaction
        end try
        begin catch
            rollback --I thought a rollback would occur when I throw after dropping the table but that doesn't seem to be the case
            ;throw
        end catch

所以我想这可以归结为3个问题:

  • 这个存储过程实际上可以免受 SQL 注入攻击吗?
  • 有更简单的方法吗?
  • 将事务级别设置为可序列化将保护代码在从 sys.tables 中选择时不会选择错误的表是否正确?
sql-server sql-server-2019
  • 1 1 个回答
  • 65 Views

1 个回答

  • Voted
  1. Best Answer
    AMtwo
    2022-02-15T07:17:46+08:002022-02-15T07:17:46+08:00

    除非我遗漏了业务需求或代码中的细节,否则我认为您正在使您的程序变得比必要的复杂得多。

    不需要创建表,然后查找表的名称,然后重命名表,然后添加主键约束,所有这些都作为单独的步骤,包装在事务中以确保一致性。相反,您可以一步完成。

    关于您的代码的其他一些代码审查类型注释:

    • 您正在使用nvarchar变量来支持 unicode,但使用“常规”单引号进行分配。要支持 unicode 字符串,您需要使用N'前缀来引用 unicode 字符串。
    • 有一个内联约束创建是可能的CREATE TABLE
    • 引用对象时应尽可能使用模式前缀,包括sys在sp_executesql.
    • 永远不要依赖存储过程的顺序位置。在传递参数时显式命名参数。大多数开发人员(包括用于系统存储过程的 Microsoft)都避免更改参数的位置——但如果他们这样做,如果您假设该位置,它将破坏您的代码。命名参数从来没有这个问题。

    这是我的程序版本:

    CREATE OR ALTER PROCEDURE [lake].[create_terminal_raw_log_table]
        (
            @terminal_name nvarchar(100)
        )
    WITH EXECUTE AS 'dbo'
    AS
        DECLARE @table_name nvarchar(128);
        DECLARE @dynamic_sql nvarchar(1000);
        
        -- We want the table name to be the input value with `_raw_log` appended:
        -- I could skip even using this variable, 
          -- and just use `@terminal_name + N'_raw_log'` 
          -- in the two spots I reference @table_name
          -- but if you use the table name a bunch of times, 
          -- this is easier.
        SET @table_name = @terminal_name + N'_raw_log';
    
        --Use dynamic SQL to create the table
            --With the PK Constraint created in-line.
        SET @dynamic_sql = N'create table [lake].' + QUOTENAME(@table_name) + N'
                        (
                            id bigint not null,
                            [timestamp] datetime2(3) not null,
                            cmd varbinary(max) not null,
                            CONSTRAINT ' + QUOTENAME(N'PK_' + @table_name) + N' 
                                PRIMARY KEY CLUSTERED (id)
                        );';
        EXEC sys.sp_executesql @stmt = @dynamic_sql;
    GO
    

    确保你测试!

    您需要进行一些快速的健全性测试,以确保您的程序确实有效。我喜欢确保使用 unicode 字符(我总是使用表情符号)和任何其他特定问题(如 SQL 注入、对象名称中的空格、最小或最大长度等)进行测试。

    例如:

    EXEC [lake].[create_terminal_raw_log_table] @terminal_name = N'nds';
    EXEC [lake].[create_terminal_raw_log_table] @terminal_name = N'amtwo';
    EXEC [lake].[create_terminal_raw_log_table] @terminal_name = N'; DROP PROCEDURE [lake].[create_terminal_raw_log_table];';
    EXEC [lake].[create_terminal_raw_log_table] @terminal_name = N'It Works!! ??';
    
    SELECT 
        TableName = o.[name]
    FROM sys.objects AS o 
    JOIN sys.schemas AS s ON s.schema_id = o.schema_id
    WHERE s.name = N'lake'
    AND o.type = 'U';
    

    返回这些结果:

    TableName
    -------------------------------------------------------------------
    nds_raw_log
    amtwo_raw_log
    ; DROP PROCEDURE [lake].[create_terminal_raw_log_table];_raw_log
    It Works!! ??_raw_log
    
    (4 rows affected)
    
    • 1

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve