zoukankan      html  css  js  c++  java
  • (4.16)存储过程的加密与解密

    (4.16)存储过程的加密与解密

    存储过程加密概念:无法查看到过程的内容,也无法右键生成create等脚本

    适用范围:从SQL2008到SQL2016,2017和2019还没试过,2005反正不行

    【1】先决条件DAC 

    【1.1】远程DAC启用(如果本机就不用这一步)

    --执行下面的SQL可以启用远程使用DAC:
    Use master
    GO
    /* 0 = Allow Local Connection, 1 = Allow Remote Connections*/ 
    sp_configure 'remote admin connections', 1 
    GO
    RECONFIGURE
    GO

    【1.2】SSMS启动DAC

    注意,要以DAC的方式新建查询才能够使用~(详情参考:SQL Server DAC——专用管理员连接

    在主菜单的“文件”中,依次选“新建”、“数据库引擎查询”,在弹出的“连接到服务器”对话窗口的“服务器名称”框中,
         输入“admin:<你的实例的名称>”。

    【2】推荐加密解密

    【2.1】SP加密

    use master
    go
    alter procedure sp_test
    @num int with encryption
    as
    begin
        select 1 union all
        select 2
    
        select * from  test1
        update  test1
        set str=10
    end

     加密后,有把锁,如下图。

      

    加密的SP,获取相关创建脚本会报错。如下图

              

    【2.2】查看加密SP

    --列出当前数据库中所有加密的存储过程
    select DB_NAME() dbname,SCHEMA_NAME(A.schema_id) schemaname,A.name spname,case when A.object_id not in (
                                      select distinct object_id from sys.numbered_procedures) 
                            then 0 else 1 
                            end is_numbered
    from sys.all_objects A inner join sys.sql_modules B 
    on A.object_id=B.object_id  where A.type='P' and A.is_ms_shipped=0 and B.definition is null 
    and A.object_id>0 and A.name not like 'dbtwin_%'
    go

    【2.3】解密

    (1)解密SP

    /****** Object:  StoredProcedure [dbo].[dbtwin_sp_decrypt]    Script Date: 01/01/2020 21:09:31 ******/
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[dbtwin_sp_decrypt]') AND type in (N'P', N'PC'))
    DROP PROCEDURE [dbo].[dbtwin_sp_decrypt]
    GO
    
    /****** Object:  StoredProcedure [dbo].[dbtwin_sp_decrypt]    Script Date: 01/01/2020 21:09:31 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE [dbo].[dbtwin_sp_decrypt](@procname sysname = NULL)
    AS
    DECLARE @encrypted        NVARCHAR(MAX)
    DECLARE @encryptedLength  INT
    DECLARE @tempStr          NVARCHAR(MAX)
    DECLARE @tempHead         NVARCHAR(MAX)
    DECLARE @tempBody         NVARCHAR(MAX)
    DECLARE @dummySp          NVARCHAR(MAX)
    DECLARE @dummyEncrypted   NVARCHAR(MAX)
    DECLARE @decryptedMessage NVARCHAR(MAX)
    DECLARE @cnt              INT
    DECLARE @decryptedChar    NCHAR(1)
    
    SET NOCOUNT ON
    SET @encrypted = (SELECT imageval FROM sys.sysobjvalues WHERE object_name(objid)=@procname)
    SET @encryptedLength=DATALENGTH(@encrypted) / 2
    SET @tempStr  = N'PROCEDURE ' + @procname + N' WITH ENCRYPTION AS'
    
    BEGIN TRAN
        SET @tempHead = N'ALTER ' + @tempStr
        SET @tempBody = REPLICATE(N' ',(@encryptedLength - LEN(@tempHead))) 
        EXEC(@tempHead + @tempBody)
        SET @dummyEncrypted = (SELECT imageval FROM sys.sysobjvalues WHERE object_name(objid)=@procname)
    ROLLBACK TRAN
    
    SET @dummySp =N'CREATE ' + @tempStr + @tempBody
    SET @decryptedMessage =''
    SET @cnt = 1
    
    WHILE @cnt <> @encryptedLength
    BEGIN
     SET @decryptedChar =NCHAR(UNICODE(SUBSTRING(@encrypted,      @cnt, 1)) ^
                               UNICODE(SUBSTRING(@dummySp,        @cnt, 1)) ^
                               UNICODE(SUBSTRING(@dummyEncrypted, @cnt, 1)))
     SET @decryptedChar=ISNULL(@decryptedChar,N' ')
     SET @decryptedMessage = @decryptedMessage + @decryptedChar
     SET @cnt = @cnt + 1
    END
    SELECT @decryptedMessage
    
    GO

    解密演示

      

     【2.4】解密优化版

    /****** Object:  StoredProcedure [dbo].[dbtwin_sp_decrypt]    Script Date: 01/04/2020 19:27:12 ******/
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[dbtwin_sp_decrypt]') AND type in (N'P', N'PC'))
    DROP PROCEDURE [dbo].[dbtwin_sp_decrypt]
    GO
    
    /****** Object:  StoredProcedure [dbo].[dbtwin_sp_decrypt]    Script Date: 01/04/2020 19:27:12 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE [dbo].[dbtwin_sp_decrypt](@procname sysname = NULL)
    AS
    DECLARE @encrypted        NVARCHAR(MAX)
    DECLARE @encryptedLength  INT
    
    DECLARE @tempStr          NVARCHAR(MAX)
    DECLARE @tempHead         NVARCHAR(MAX)
    DECLARE @tempBody         NVARCHAR(MAX)
    
    DECLARE @dummySp          NVARCHAR(MAX)
    DECLARE @dummyEncrypted   NVARCHAR(MAX)
    
    DECLARE @decryptedMessage NVARCHAR(MAX)
    DECLARE @cnt              INT
    DECLARE @decryptedChar    NCHAR(1)
    DECLARE @x                NVARCHAR(MAX)
    
    SET NOCOUNT ON
    
    SET @encrypted = (SELECT imageval FROM sys.sysobjvalues WHERE object_name(objid)=@procname)
    SET @encryptedLength=DATALENGTH(@encrypted) / 2
    
    SET @tempStr  = N'PROCEDURE ' + @procname + N' WITH ENCRYPTION AS'
    
    BEGIN TRAN
    SET @tempHead = N'ALTER ' + @tempStr
    SET @x=N'-'
    SET @tempBody = REPLICATE(@x,(@encryptedLength - LEN(@tempHead))) 
    EXEC(@tempHead + @tempBody)
    SET @dummyEncrypted = (SELECT imageval FROM sys.sysobjvalues WHERE object_name(objid)=@procname)
    ROLLBACK TRAN
    
    SET @dummySp =N'CREATE ' + @tempStr + @tempBody
    
    SET @decryptedMessage =''
    SET @cnt              = 1
    
    WHILE @cnt <> @encryptedLength
    BEGIN
     SET @decryptedChar =NCHAR(UNICODE(SUBSTRING(@encrypted,      @cnt, 1)) ^
                               UNICODE(SUBSTRING(@dummySp,        @cnt, 1)) ^
                               UNICODE(SUBSTRING(@dummyEncrypted, @cnt, 1)))
     SET @decryptedMessage = @decryptedMessage + ISNULL(@decryptedChar,N' ')
     SET @cnt = @cnt + 1
    END
    
    DECLARE @TextLength int
    DECLARE @BasePos    int
    DECLARE @CurrentPos int
    
    SET @BasePos   =1
    SET @CurrentPos=1
    SET @TextLength = DATALENGTH(@decryptedMessage) / 2 
    WHILE @CurrentPos != 0  
    BEGIN  
       --通过回车查找行的结束  
       SET @CurrentPos = CHARINDEX(nchar(13)+ nchar(10), @decryptedMessage,@BasePos) 
       IF @CurrentPos != 0  
       BEGIN  
         PRINT SUBSTRING(@decryptedMessage, @BasePos, @CurrentPos - @BasePos )
       END  
       ELSE  
       BEGIN  
        IF @BasePos <= @TextLength  
        BEGIN  
         PRINT SUBSTRING(@decryptedMessage, @BasePos, @TextLength - @BasePos)
        END
       END   
       SET @BasePos = @CurrentPos + 2
    END
    
    GO

    【3】另外一种方法

    【3.1】SP加密

    use test
    go
    alter procedure sp_test
    @num int with encryption
    as
    begin
    
        select 1 union all
        select 2
    
        select * from  test..test1
        update  test..test1
        set num=10,num1=10
        where id = @num
    end

    【3.2】解密

    create procedure sp_DecryptObject 
    (
        @Object sysname,    --要解密的对象名:函数,存储过程,视图或触发器
        @MaxLength int=4000 --评估内容的长度
    )
    
    as
    set nocount on
    /* 1. 解密 */
    if not exists(select 1 from sys.objects a where a.object_id=object_id(@Object) And a.type in('P','V','TR','FN','IF','TF'))
    begin
        --SQL Server 2008
        raiserror ( N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。' ,16,1)
        --SQL Server 2012
        --throw 50001, N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。',1   
        return
    end
    if exists(select 1 from sys.sql_modules a where a.object_id=object_id(@Object) and a.definition is not null)
    begin
       --SQL Server 2008
        raiserror (N'对象没有加密!' ,16,1)
        --SQL Server 2012
        --throw 50001, N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。',1 
        return
    end
    declare  @sql nvarchar(max)                --解密出来的SQL语句
            ,@imageval nvarchar(max)        --加密字符串
            ,@tmpStr nvarchar(max)            --临时SQL语句
            ,@tmpStr_imageval nvarchar(max) --临时SQL语句(加密后)
            ,@type char(2)                    --对象类型('P','V','TR','FN','IF','TF')
            ,@objectID int                    --对象ID
            ,@i int                            --While循环使用
            ,@Oject1 nvarchar(1000)
    set @objectID=object_id(@Object)
    set @type=(select a.type from sys.objects a where a.object_id=@objectID)
    declare @Space4000 nchar(4000)
    set @Space4000=replicate('-',4000)
    /*
    
    @tmpStr 会构造下面的SQL语句
    -------------------------------------------------------------------------------
    alter trigger Tr_Name on Table_Name with encryption for update as return /**/
    alter proc Proc_Name with encryption  as select 1 as col /**/
    alter view View_Name with encryption as select 1 as col /**/
    alter function Fn_Name() returns int with encryption as begin return(0) end/**/
    */
    set @Oject1=quotename(object_schema_name(@objectID))+'.'+quotename(@Object)
    set @tmpStr=
            case     
                when @type ='P ' then N'Alter Procedure '+@Oject1+' with encryption as select 1 as column1 '
                when @type ='V ' then N'Alter View '+@Oject1+' with encryption as select 1 as column1 '
                when @type ='FN' then N'Alter Function '+@Oject1+'() returns int with encryption as begin return(0) end '
                when @type ='IF' then N'Alter Function '+@Oject1+'() returns table with encryption as return(Select a.name from sys.types a) '
                when @type ='TF' then N'Alter Function '+@Oject1+'() returns @t table(name nvarchar(50)) with encryption as begin return end '
                else 'Alter Trigger '+@Oject1+'on '+quotename(object_schema_name(@objectID))+'.'+(select Top(1) quotename(object_name(parent_id)) from sys.triggers a where a.object_id=@objectID)+' with encryption for update as return ' 
            end          
    
    set @tmpStr=@tmpStr+'/*'+@Space4000
    set @i=0
    while @i < (ceiling(@MaxLength*1.0/4000)-1)
    begin
        set @tmpStr=@tmpStr+ @Space4000
        Set @i=@i+1
    end
    set @tmpStr=@tmpStr+'*/'
    
    ------------
    set @imageval =(select top(1) a.imageval from sys.sysobjvalues a where a.objid=@objectID and a.valclass=1)
    begin tran
    exec(@tmpStr)
    set @tmpStr_imageval =(select top(1) a.imageval from sys.sysobjvalues a where a.objid=@objectID and a.valclass=1)
    rollback tran
    -------------
    
    set @tmpStr=stuff(@tmpStr,1,5,'create')
    set @sql=''
    set @i=1
    while @i<= (datalength(@imageval)/2)
    begin
       set @sql=@sql+isnull(nchar(unicode(substring(@tmpStr,@i,1)) ^ unicode(substring(@tmpStr_imageval,@i,1))^unicode(substring(@imageval,@i,1)) ),'')
       Set @i+=1
    end
    
    /* 2. 列印 */
    
    
    declare @patindex int    
    while @sql>''
    begin
        set @patindex=patindex('%'+char(13)+char(10)+'%',@sql)
        if @patindex >0
        begin
            print substring(@sql,1,@patindex-1)
            set @sql=stuff(@sql,1,@patindex+1,'')
        end    
        else 
        begin
            set @patindex=patindex('%'+char(13)+'%',@sql)
            if @patindex >0
            begin
                print substring(@sql,1,@patindex-1)
                set @sql=stuff(@sql,1,@patindex,'')
            end
            else
            begin
               set @patindex=patindex('%'+char(10)+'%',@sql)
               if @patindex >0
                begin
                    print substring(@sql,1,@patindex-1)
                    set @sql=stuff(@sql,1,@patindex,'')
                end        
                else
                begin
                   print @sql
                   set @sql=''
                end    
            end        
        end       
    end

     成功破解

    【4】解密过程原理

    SQL SERVER SP解密过程推导
    在SQL SERVER里,已知微软在加密和解密存储过程时用的是RC4算法。下面是解密存储过程的解题思路,读者可以据此自己写个解密小程序。
    想解密SP,其实就是解答下列一道证明题。
    已知条件:
      1. 已知需要解密的存储过程SP_A的密文为Ma。
      2. 用一个已知明文的SP_B替换SP_A,这样得到SP_B的明文和密文分别为Tb和Mb。
    求证:Ta=Ma⊕Tb⊕Mb,Ta即为需要解密的存储过程的明文。
    证明过程:
      1. 用DAC登录SQLSERVER,获取Ma和Mb: SELECT imageval FROM sys.sysobjvalues where …
      2. 由于RC4算法的加密和解密使用的是相同的秘钥,假设秘钥为K,那么:
        a. Mb=Tb⊕K
        b. 根据异或运算公式,可以得到下列该存储过程加解秘时使用的秘钥为:
        K=K⊕0=K⊕Tb⊕Tb=(K⊕Tb)⊕Tb=(Tb⊕K)⊕Tb=Mb⊕Tb
    3. 因为Ma=Ta⊕K,则再次利用异或运算公式,得到下列推导结果:
      Ta=Ta⊕0=Ta⊕(K⊕K)=(Ta⊕K)⊕K=Ma⊕K=Ma⊕Mb⊕Tb
    4. 即Ta=Ma⊕Tb⊕Mb,Ta就是需要解密的存储过程的明文。

    参考自:DBTWIN 无锡SQL集群服务商

  • 相关阅读:
    bootstrap4 Reboot details summary 美化(点选禁止选中文本,单行隐藏角标,多行后移)
    在C#中,Newtonsoft.Json + dynamic动态解析jsonString,jsonString转实体
    在C#中,Windows Console控制台 设置控制台标题、禁用关闭按钮、关闭快速编辑模式、插入模式
    MySql数据库中,判断表、表字段是否存在,不存在就新增
    Windows 10安装Docker 步骤及顺序
    AES加密解密 助手类 CBC加密模式
    处理模板页菜单高亮
    C# 按不同的字节编码,通过字节数去截取字符串
    2018年4月13日,祝自己24岁生日快乐!
    一个数值保存复选框的值
  • 原文地址:https://www.cnblogs.com/gered/p/10059911.html
Copyright © 2011-2022 走看看