154 lines
5.4 KiB
Transact-SQL
154 lines
5.4 KiB
Transact-SQL
SET ANSI_NULLS ON
|
|
GO
|
|
SET QUOTED_IDENTIFIER ON
|
|
GO
|
|
|
|
-- [PRDEX_TEST_DYNAMIC_SQL]
|
|
-- =================================================================
|
|
-- Central guard for dynamic SQL safety checks
|
|
--
|
|
-- Returns: INTEGER; 0 = ok; 0 <> nicht ok
|
|
-- =================================================================
|
|
-- Copyright (c) 2025 by Digital Data GmbH
|
|
--
|
|
-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim
|
|
-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works
|
|
-- =================================================================
|
|
-- Creation Date / Author: 24.02.2026 / MK
|
|
-- Version Date / Editor: 24.02.2026 / MK
|
|
-- Version Number: 1.0.0.0
|
|
-- =================================================================
|
|
-- History:
|
|
-- 24.02.2026 / MK - First Version
|
|
|
|
CREATE OR ALTER PROCEDURE [dbo].[PRDEX_TEST_DYNAMIC_SQL](
|
|
@pQUERY NVARCHAR(MAX),
|
|
@pRETURN_STATUS INT,
|
|
@pQUERY_NAME NVARCHAR(100) = N'@QUERY'
|
|
)
|
|
AS
|
|
BEGIN TRY
|
|
|
|
--================================================-- Set session options --===============================================--
|
|
SET NOCOUNT ON;
|
|
----------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--=========================================-- declare new vars because of parameter sniffing --===========================--
|
|
DECLARE @QUERY NVARCHAR(MAX) = ISNULL(@pQUERY,N''),
|
|
@RETURN_STATUS INT = ISNULL(@pRETURN_STATUS,50000),
|
|
@QUERY_NAME NVARCHAR(100) = ISNULL(@pQUERY_NAME,N'@QUERY'),
|
|
@QUERY_SCAN NVARCHAR(MAX) = N'',
|
|
@QUERY_SCAN_NORM NVARCHAR(MAX) = N'',
|
|
@COMMENT_START INT = 0,
|
|
@COMMENT_END INT = 0,
|
|
@SCAN_POS INT = 1,
|
|
@TOKEN_START INT = 0,
|
|
@TOKEN_END INT = 0,
|
|
@QUOTE_START INT = 0,
|
|
@QUOTE_END INT = 0,
|
|
@TOKEN NVARCHAR(200) = N'',
|
|
@HAS_UNRESOLVED_PLACEHOLDER BIT = 0,
|
|
@HAS_RESTRICTED_SQL BIT = 0,
|
|
@RETURN_ERROR_TEXT NVARCHAR(MAX) = N'';
|
|
----------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--=========================================-- validate query content --====================================================--
|
|
SET @QUERY_SCAN = UPPER(@QUERY);
|
|
|
|
SET @COMMENT_START = CHARINDEX('/*',@QUERY_SCAN);
|
|
WHILE (@COMMENT_START > 0)
|
|
BEGIN
|
|
SET @COMMENT_END = CHARINDEX('*/',@QUERY_SCAN,@COMMENT_START + 2);
|
|
|
|
IF (@COMMENT_END = 0)
|
|
BREAK;
|
|
|
|
SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@COMMENT_START,(@COMMENT_END - @COMMENT_START + 2),REPLICATE(' ',(@COMMENT_END - @COMMENT_START + 2)));
|
|
SET @COMMENT_START = CHARINDEX('/*',@QUERY_SCAN,@COMMENT_START + 1);
|
|
END;
|
|
|
|
SET @COMMENT_START = CHARINDEX('--',@QUERY_SCAN);
|
|
WHILE (@COMMENT_START > 0)
|
|
BEGIN
|
|
SET @COMMENT_END = CHARINDEX(CHAR(10),@QUERY_SCAN,@COMMENT_START + 2);
|
|
|
|
IF (@COMMENT_END = 0)
|
|
SET @COMMENT_END = LEN(@QUERY_SCAN) + 1;
|
|
|
|
SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@COMMENT_START,(@COMMENT_END - @COMMENT_START),REPLICATE(' ',(@COMMENT_END - @COMMENT_START)));
|
|
SET @COMMENT_START = CHARINDEX('--',@QUERY_SCAN,@COMMENT_START + 1);
|
|
END;
|
|
|
|
SET @QUERY_SCAN_NORM = REPLACE(REPLACE(REPLACE(@QUERY_SCAN,CHAR(9),' '),CHAR(10),' '),CHAR(13),' ');
|
|
|
|
WHILE (CHARINDEX(' ',@QUERY_SCAN_NORM) > 0)
|
|
BEGIN
|
|
SET @QUERY_SCAN_NORM = REPLACE(@QUERY_SCAN_NORM,' ',' ');
|
|
END;
|
|
|
|
SET @QUOTE_START = CHARINDEX('''',@QUERY_SCAN);
|
|
WHILE (@QUOTE_START > 0)
|
|
BEGIN
|
|
SET @QUOTE_END = CHARINDEX('''',@QUERY_SCAN,@QUOTE_START + 1);
|
|
|
|
IF (@QUOTE_END = 0)
|
|
BREAK;
|
|
|
|
SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@QUOTE_START,(@QUOTE_END - @QUOTE_START + 1),REPLICATE(' ',(@QUOTE_END - @QUOTE_START + 1)));
|
|
SET @QUOTE_START = CHARINDEX('''',@QUERY_SCAN,@QUOTE_START + 1);
|
|
END;
|
|
|
|
WHILE (1 = 1)
|
|
BEGIN
|
|
SET @TOKEN_START = CHARINDEX('%',@QUERY_SCAN,@SCAN_POS);
|
|
|
|
IF (@TOKEN_START = 0)
|
|
BREAK;
|
|
|
|
SET @TOKEN_END = CHARINDEX('%',@QUERY_SCAN,@TOKEN_START + 1);
|
|
|
|
IF (@TOKEN_END = 0)
|
|
BREAK;
|
|
|
|
SET @TOKEN = SUBSTRING(@QUERY_SCAN,@TOKEN_START + 1,@TOKEN_END - @TOKEN_START - 1);
|
|
|
|
IF (LEN(@TOKEN) > 0)
|
|
AND (LEFT(@TOKEN,1) LIKE '[A-Z_]')
|
|
AND (@TOKEN NOT LIKE '%[^A-Z0-9_]%')
|
|
BEGIN
|
|
SET @HAS_UNRESOLVED_PLACEHOLDER = 1;
|
|
BREAK;
|
|
END;
|
|
|
|
SET @SCAN_POS = @TOKEN_END + 1;
|
|
END;
|
|
|
|
SET @HAS_RESTRICTED_SQL = CASE WHEN
|
|
(CHARINDEX(';--',@QUERY_SCAN_NORM) > 0) OR
|
|
(CHARINDEX('; --',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%XP_CMDSHELL%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%SP_OA%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%OPENROWSET%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%OPENDATASOURCE%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%BULK INSERT%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%SP_CONFIGURE%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%RECONFIGURE%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%ALTER SERVER%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%ALTER LOGIN%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%CREATE LOGIN%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%DROP LOGIN%',@QUERY_SCAN_NORM) > 0) OR
|
|
(PATINDEX('%DROP DATABASE%',@QUERY_SCAN_NORM) > 0)
|
|
THEN 1 ELSE 0 END;
|
|
----------------------------------------------------------------------------------------------------------------------------
|
|
|
|
IF (@HAS_UNRESOLVED_PLACEHOLDER = 1) OR (@HAS_RESTRICTED_SQL = 1) BEGIN
|
|
SET @RETURN_ERROR_TEXT = CONCAT('Blocked unsafe query content in ',@QUERY_NAME,'. Detected unresolved placeholder tokens (%TOKEN%) or restricted statements.');
|
|
THROW @RETURN_STATUS,@RETURN_ERROR_TEXT,1;
|
|
END;
|
|
|
|
RETURN 0;
|
|
|
|
END TRY BEGIN CATCH
|
|
THROW;
|
|
END CATCH;
|
|
GO |