SQL替换查询变量内容

3
我正在寻找一条SQL查询语句来清理被黑客攻击的SQL Server数据库。我有一些基础的SQL知识,但不知道如何解决以下问题。
我们的一个网站的SQL Server数据库最近遭到了黑客攻击。成千上万的记录都被填充了隐藏的div,其中包含各种可疑的引用。我们的ISP表示数据库内容不是他们的责任,他们也不知道如何帮助我们清理数据库。没有可用的干净备份。手动浏览所有记录的工作量太大了。
所以我现在在拼命寻找一条SQL查询语句,以从数据库中删除这些块的隐藏文本。
两个有用的信息:
1. 所有垃圾邮件内容都包含在div标签中。标签之间的信息在每个实例中都不同,但它们都是以div标签开头和结尾的。 2. 我们的原始数据将具有一些HTML内容,但永远不会包含div标签。因此,如果我们能找到一种方法,从起始div到包括关闭div的所有内容都可以删除,那么我们就可以解决问题。
非常感谢您的帮助。谢谢您的时间。

6
在继续之前,您需要回到代码并修复 SQL 注入漏洞。当您构建一个包含来自用户的内容而没有参数的字符串时,您的代码是容易受到攻击的。我知道这似乎有些颠倒,但您可能需要先解决这个问题,然后再处理数据。大多数情况下,一旦有人发现了这种漏洞,他们就会继续利用它,所以任何数据清理都是无意义的,因为它只会再次被损坏。完成这个步骤后,您可以开始进行清理工作。 - Sean Lange
1
清理工作本身也会很有趣。你需要非常熟悉substring、patindex和charindex。 - Sean Lange
1
另外,一旦您恢复业务,请定期备份您的数据库。拜托了。 - Jeffrey Van Laethem
1
我明白这一点,但这将会隐藏它们,直到他们修复代码以防止其再次出现。这最多只是一个权宜之计。 - Sean Lange
感谢您迅速回复,@SeanLange。该网站正在运行(*blush) Classic ASP。不幸的是,Bobby Tables 在这方面似乎没有提供太多帮助。但我会深入研究SQL注入预防;这是个好主意。 - m4v21
显示剩余7条评论
3个回答

3

如果您的假设正确,可以尝试此操作。另一个假设是黑客没有添加嵌套DIV。在运行更新之前,请彻底测试此操作。并在运行更新之前备份您的数据。

CREATE TABLE #temp(id INT IDENTITY, html VARCHAR(MAX));

INSERT #temp(html)
VALUES('<p>Some text</p><strong>other text</strong><div>added by hacker</div>')
,('<p>Some text</p><strong>other text<div>added by hacker within html tag</div></strong>')
,('<p>Some text</p><div>some other text added by <a href="http://google.com">hack</a></div><strong>other text</strong>');


SELECT html
,  CHARINDEX('<div',html) AS startPos
, CHARINDEX('</div>',html) AS endPos
, (CHARINDEX('</div>',html)+6)-(CHARINDEX('<div',html)) AS stringLenToRemove
, SUBSTRING(html, CHARINDEX('<div',html), (CHARINDEX('</div>',html)+6)-(CHARINDEX('<div',html))) AS HtmlAddedByHack
,REPLACE(html,SUBSTRING(html, CHARINDEX('<div',html), (CHARINDEX('</div>',html)+6)-(CHARINDEX('<div',html))), '') AS sanitizedHtml
FROM #temp;

--UPDATE #temp
--SET html = REPLACE(html,SUBSTRING(html, CHARINDEX('<div',html), (CHARINDEX('</div>',html)+6)-(CHARINDEX('<div',html))), '');

--SELECT  *
--FROM    #temp;

非常感谢您的建议,DK。到目前为止,这是我唯一能够理解的代码建议:] 它看起来相当合乎逻辑,也符合我的想法。我会尝试这个建议并告诉您结果。 - m4v21
嗨DK,我一直在尝试上述内容,并已成功让这段代码产生了结果。现在我正在运行的是: - m4v21
正如您所看到的,我正在限制查询一个记录以进行测试。操作是搜索第一个div的实例,然后成功地删除它。但是存在两个问题:1)记录包含多个实例(但我可以运行查询多次以将它们全部删除);2)当我重复查询时,某个时刻会用尽divs并开始删除记录的前六个字符(可能是来自代码中的+6)。如何告诉查询在没有更多div的情况下不要删除任何内容? - m4v21
你可以添加一个where子句来确保只有包含问题的行被清理:WHERE html like '%<div>%' and html like '%</div>%' - Dharmendar Kumar 'DK'
你的意思是指数据库中的每个表/列吗?您可以循环遍历所有表中的所有列,并创建动态SQL,然后执行动态SQL。但是我在执行此操作时会非常小心。建议您将数据库恢复到单独的实例中;进行更改,测试并交换数据库。 - Dharmendar Kumar 'DK'
显示剩余8条评论

1

使用PATINDEX的UDF可能能够实现此目的。

假设:

  • 所有恶意内容都在<DIV>...</DIV>部分中
  • 不存在不是恶意内容的<DIV>...</DIV>部分
  • 在将其应用于您的实时数据库之前,请在数据备份上广泛测试此功能

首先从这里使用此UDF进行模式替换:

CREATE FUNCTION dbo.PatternReplace
(
   @InputString VARCHAR(4000),
   @Pattern VARCHAR(100),
   @ReplaceText VARCHAR(4000)
)
RETURNS VARCHAR(4000)
AS
BEGIN
   DECLARE @Result VARCHAR(4000) SET @Result = ''
   -- First character in a match
   DECLARE @First INT
   -- Next character to start search on
   DECLARE @Next INT SET @Next = 1
   -- Length of the total string -- 8001 if @InputString is NULL
   DECLARE @Len INT SET @Len = COALESCE(LEN(@InputString), 8001)
   -- End of a pattern
   DECLARE @EndPattern INT

   WHILE (@Next <= @Len) 
   BEGIN
      SET @First = PATINDEX('%' + @Pattern + '%', SUBSTRING(@InputString, @Next, @Len))
      IF COALESCE(@First, 0) = 0 --no match - return
      BEGIN
         SET @Result = @Result + 
            CASE --return NULL, just like REPLACE, if inputs are NULL
               WHEN  @InputString IS NULL
                     OR @Pattern IS NULL
                     OR @ReplaceText IS NULL THEN NULL
               ELSE SUBSTRING(@InputString, @Next, @Len)
            END
         BREAK
      END
      ELSE
      BEGIN
         -- Concatenate characters before the match to the result
         SET @Result = @Result + SUBSTRING(@InputString, @Next, @First - 1)
         SET @Next = @Next + @First - 1

         SET @EndPattern = 1
         -- Find start of end pattern range
         WHILE PATINDEX(@Pattern, SUBSTRING(@InputString, @Next, @EndPattern)) = 0
            SET @EndPattern = @EndPattern + 1
         -- Find end of pattern range
         WHILE PATINDEX(@Pattern, SUBSTRING(@InputString, @Next, @EndPattern)) > 0
               AND @Len >= (@Next + @EndPattern - 1)
            SET @EndPattern = @EndPattern + 1

         --Either at the end of the pattern or @Next + @EndPattern = @Len
         SET @Result = @Result + @ReplaceText
         SET @Next = @Next + @EndPattern - 1
      END
   END
   RETURN(@Result)
END

然后,利用UDF:
UPDATE ContentTable SET ContentColumn=dbo.PatternReplace('<DIV>%</DIV>', '')

1
也许可以像这样使用光标....
Declare @ColumnName sysname , @TableName sysname 
        ,@Schema sysname , @Sql Nvarchar(MAX);

Declare Cur CURSOR FOR 
Select c.name , t.name , s.name
from sys.columns c 
inner join sys.tables  t on c.object_id = t.object_id
inner join sys.types   p on p.user_type_id = c.user_type_id
inner join sys.schemas s on t.schema_id = s.schema_id
where t.is_ms_shipped = 0
and p.name in ('varchar','nvarchar', 'char', 'nchar')

OPEN Cur 

 FETCH NEXT FROM Cur INTO @ColumnName , @TableName , @Schema

WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @Sql = N'UPDATE '+ QUOTENAME(@Schema) +'.' + QUOTENAME(@TableName) 
             + N' SET ' + QUOTENAME(@ColumnName) + N' = '
             + N'LEFT(' + QUOTENAME(@ColumnName) + N', CHARINDEX(''<div>'', 
                          ' + QUOTENAME(@ColumnName) + N') - 1) 
                      + SUBSTRING(' + QUOTENAME(@ColumnName) + N', 
                      CHARINDEX(''</div>'', ' + QUOTENAME(@ColumnName) + N') + 6
                      , LEN(' + QUOTENAME(@ColumnName) + N'))
                Where ' + QUOTENAME(@ColumnName) + N' IS NOT NULL 
                AND LEN(' + QUOTENAME(@ColumnName) + N') > 6' 

     Exec sp_executesql @Sql 

     FETCH NEXT FROM Cur INTO @ColumnName , @TableName , @Schema
END 

CLOSE Cur 
DEALLOCATE Cur

注意

光标循环遍历所有表格并选择具有 varchar, nvarchar, char, nchar 数据类型的列,然后创建一个更新语句以删除 <div> </div> 标签之间的任何字符串(如果存在),否则列保持不变。

警告

在实际运行脚本之前,请先对其进行测试以防止对实时数据库造成影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接