在网络上,看到有SQL Server 2000和SQL Server 2005 的存储过程加密和解密的方法,后来分析了其中的代码,发现它们的原理都是一样的。后来自己根据实际的应用环境,编写了两个存储过程,一个加密存储过程(sp_EncryptObject),和一个解密存储过程(sp_EncryptObject),它们可以应用于SQL Server中的储过程,函数,视图,以及触发器。

感觉这两个存储过程蛮有意思的,拿来与大家分享;如果你看过类似的,就当作重温一下也好。

用于加密的存储过程 (sp_EncryptObject) :


存储过程(sp_EncryptObject)加密的方法是在存储过程,函数,视图的“As”位置前加上“with encryption”;如果是触发器,就在“for”位置前加“with encryption”。

如果触发器是{ AFTER | INSTEAD OF} 需要修改下面代码"For"位置:

  1. if objectproperty(object_id(@Object),'ExecIsAfterTrigger')=0 set @Replace='As' ; else set @Replace='For ';

存储过程完成代码:

  1. Use master
  2. Go
  3. if object_ID('[sp_EncryptObject]') is not null
  4. Drop Procedure [sp_EncryptObject]
  5. Go
  6. create procedure sp_EncryptObject
  7. (
  8. @Object sysname='All'
  9. )
  10. as
  11. /*
  12. 当@Object=All的时候,对所有的函数,存储过程,视图和触发器进行加密
  13. 调用方法:
  14. 1. Execute sp_EncryptObject 'All'
  15. 2. Execute sp_EncryptObject 'ObjectName'
  16. */
  17. begin
  18. set nocount on
  19.  
  20. if @Object <>'All'
  21. begin
  22. 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'))
  23. begin
  24. --SQL Server 2008
  25. raiserror 50001 N'无效的加密对象!加密对象必须是函数,存储过程,视图或触发器。'
  26.  
  27. --SQL Server 2012
  28. --throw 50001, N'无效的加密对象!加密对象必须是函数,存储过程,视图或触发器。',1
  29.  
  30. return
  31. end
  32.  
  33. if exists(select 1 from sys.sql_modules a where a.object_id=object_id(@Object) and a.definition is null)
  34. begin
  35. --SQL Server 2008
  36. raiserror 50001 N'对象已经加密!'
  37.  
  38. --SQL Server 2012
  39. --throw 50001, N'对象已经加密!',1
  40. return
  41. end
  42. end
  43.  
  44. declare @sql nvarchar(max),@C1 nchar(1),@C2 nchar(1),@type nvarchar(50),@Replace nvarchar(50)
  45. set @C1=nchar(13)
  46. set @C2=nchar(10)
  47.  
  48. declare cur_Object
  49. cursor for
  50. select object_name(a.object_id) As ObjectName,a.definition
  51. from sys.sql_modules a
  52. inner join sys.objects b on b.object_id=a.object_id
  53. and b.is_ms_shipped=0
  54. and not exists(select 1
  55. from sys.extended_properties x
  56. where x.major_id=b.object_id
  57. and x.minor_id=0
  58. and x.class=1
  59. and x.name='microsoft_database_tools_support'
  60. )
  61. where b.type in('P','V','TR','FN','IF','TF')
  62. and (b.name=@Object or @Object='All')
  63. and b.name <>'sp_EncryptObject'
  64. and a.definition is not null
  65. order by Case
  66. when b.type ='V' then 1
  67. when b.type ='TR' then 2
  68. when b.type in('FN','IF','TF') then 3
  69. else 4 end,b.create_date,b.object_id
  70.  
  71. open cur_Object
  72. fetch next from cur_Object into @Object,@sql
  73. while @@fetch_status=0
  74. begin
  75.  
  76. Begin Try
  77.  
  78. if objectproperty(object_id(@Object),'ExecIsAfterTrigger')=0 set @Replace='As' ; else set @Replace='For ';
  79.  
  80. if (patindex('%'+@C1+@C2+@Replace+@C1+@C2+'%',@sql)>0)
  81. begin
  82. set @sql=Replace(@sql,@C1+@C2+@Replace+@C1+@C2,@C1+@C2+'With Encryption'+@C1+@C2+@Replace+@C1+@C2)
  83. end
  84. else if(patindex('%'+@C1+@Replace+@C1+'%',@sql)>0)
  85. begin
  86. set @sql=Replace(@sql,@C1+@Replace+@C1,@C1+'With Encryption'+@C1+@Replace+@C1)
  87. end
  88. else if(patindex('%'+@C2+@Replace+@C2+'%',@sql)>0)
  89. begin
  90. set @sql=Replace(@sql,@C2+@Replace+@C2,@C2+'With Encryption'+@C2+@Replace+@C2)
  91. end
  92. else if(patindex('%'+@C2+@Replace+@C1+'%',@sql)>0)
  93. begin
  94. set @sql=Replace(@sql,@C2+@Replace+@C1,@C1+'With Encryption'+@C2+@Replace+@C1)
  95. end
  96. else if(patindex('%'+@C1+@C2+@Replace+'%',@sql)>0)
  97. begin
  98. set @sql=Replace(@sql,@C1+@C2+@Replace,@C1+@C2+'With Encryption'+@C1+@C2+@Replace)
  99. end
  100. else if(patindex('%'+@C1+@Replace+'%',@sql)>0)
  101. begin
  102. set @sql=Replace(@sql,@C1+@Replace,@C1+'With Encryption'+@C1+@Replace)
  103. end
  104. else if(patindex('%'+@C2+@Replace+'%',@sql)>0)
  105. begin
  106. set @sql=Replace(@sql,@C2+@Replace,@C2+'With Encryption'+@C2+@Replace)
  107. end
  108.  
  109. set @type =
  110. case
  111. when object_id(@Object,'P')>0 then 'Proc'
  112. when object_id(@Object,'V')>0 then 'View'
  113. when object_id(@Object,'TR')>0 then 'Trigger'
  114. when object_id(@Object,'FN')>0 or object_id(@Object,'IF')>0 or object_id(@Object,'TF')>0 then 'Function'
  115. end
  116. set @sql=Replace(@sql,'Create '+@type,'Alter '+@type)
  117.  
  118. Begin Transaction
  119. exec(@sql)
  120. print N'已完成加密对象('+@type+'):'+@Object
  121. Commit Transaction
  122.  
  123. End Try
  124. Begin Catch
  125. Declare @Error nvarchar(2047)
  126. Set @Error='Object: '+@Object+@C1+@C2+'Error: '+Error_message()
  127.  
  128. Rollback Transaction
  129. print @Error
  130. print @sql
  131. End Catch
  132.  
  133. fetch next from cur_Object into @Object,@sql
  134.  
  135. end
  136.  
  137. close cur_Object
  138. deallocate cur_Object
  139. end
  140.  
  141. Go
  142. exec sp_ms_marksystemobject 'sp_EncryptObject' --标识为系统对象
  143. go

如果SQL Server 2012,请修改下面两个位置的代码。在SQL Server 2012,建议在使用throw来代替raiserror。

解密方法:


解密过程,最重要采用异或方法:

[字符1]经过函数 fn_x(x)加密变成[加密后字符1],如果我们已知[加密后字符1],反过来查[字符1],可以这样:

[字符1]  =  [字符2]  ^  fn_x([字符2])  ^  [加密后字符1]

这里我列举一个简单的例子:

  1. --创建加密函数(fn_x
  2. if object_id('fn_x') is not null drop function fn_x
  3. go
  4. create function fn_x
  5. (
  6. @x nchar(1)
  7. )returns nchar(1)
  8. as
  9. begin
  10. return(nchar((65535-unicode(@x))))
  11. end
  12. go
  13. declare @nchar_1_encrypt nchar(1),@nchar_2 nchar(1)
  14.  
  15. --对字符'A'进行加密,存入变量@nchar_1_encrypt
  16. set @nchar_1_encrypt=dbo.fn_x(N'A')
  17.  
  18. --參考的字符@nchar_2
  19. set @nchar_2='x'
  20.  
  21. --算出@nchar_1_encrypt 加密前的字符
  22. select nchar(unicode(@nchar_2)^unicode(dbo.fn_x(@nchar_2))^unicode(@nchar_1_encrypt)) as [@nchar_1]
  23.  
  24. /*
  25. @nchar_1
  26. --------------------
  27. A
  28. */

[注]:  从SQL Server 2000至 SQL Server 2012 采用异或方法都可以解密

用于解密的存储过程(sp_DecryptObject):

  1. Use master
  2. Go
  3. if object_ID('[sp_DecryptObject]') is not null
  4. Drop Procedure [sp_DecryptObject]
  5. Go
  6. create procedure sp_DecryptObject
  7. (
  8. @Object sysname, --要解密的对象名:函数,存储过程,视图或触发器
  9. @MaxLength int=4000 --评估内容的长度
  10. )
  11. as
  12. set nocount on
  13. /* 1. 解密 */
  14.  
  15. 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'))
  16. begin
  17. --SQL Server 2008
  18. raiserror 50001 N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。'
  19.  
  20. --SQL Server 2012
  21. --throw 50001, N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。',1
  22. return
  23. end
  24.  
  25. if exists(select 1 from sys.sql_modules a where a.object_id=object_id(@Object) and a.definition is not null)
  26. begin
  27. --SQL Server 2008
  28. raiserror 50001 N'对象没有加密!'
  29.  
  30. --SQL Server 2012
  31. --throw 50001, N'无效的对象!要解密的对象必须是函数,存储过程,视图或触发器。',1
  32. return
  33. end
  34.  
  35. declare @sql nvarchar(max) --解密出来的SQL语句
  36. ,@imageval nvarchar(max) --加密字符串
  37. ,@tmpStr nvarchar(max) --临时SQL语句
  38. ,@tmpStr_imageval nvarchar(max) --临时SQL语句(加密后)
  39. ,@type char(2) --对象类型('P','V','TR','FN','IF','TF')
  40. ,@objectID int --对象ID
  41. ,@i int --While循环使用
  42. ,@Oject1 nvarchar(1000)
  43.  
  44. set @objectID=object_id(@Object)
  45. set @type=(select a.type from sys.objects a where a.object_id=@objectID)
  46.  
  47. declare @Space4000 nchar(4000)
  48. set @Space4000=replicate('-',4000)
  49.  
  50. /*
  51. @tmpStr 会构造下面的SQL语句
  52. -------------------------------------------------------------------------------
  53. alter trigger Tr_Name on Table_Name with encryption for update as return /**/
  54. alter proc Proc_Name with encryption as select 1 as col /**/
  55. alter view View_Name with encryption as select 1 as col /**/
  56. alter function Fn_Name() returns int with encryption as begin return(0) end/**/
  57. */
  58. set @Oject1=quotename(object_schema_name(@objectID))+'.'+quotename(@Object)
  59. set @tmpStr=
  60. case
  61. when @type ='P ' then N'Alter Procedure '+@Oject1+' with encryption as select 1 as column1 '
  62. when @type ='V ' then N'Alter View '+@Oject1+' with encryption as select 1 as column1 '
  63. when @type ='FN' then N'Alter Function '+@Oject1+'() returns int with encryption as begin return(0) end '
  64. when @type ='IF' then N'Alter Function '+@Oject1+'() returns table with encryption as return(Select a.name from sys.types a) '
  65. when @type ='TF' then N'Alter Function '+@Oject1+'() returns @t table(name nvarchar(50)) with encryption as begin return end '
  66. 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 '
  67. end
  68.  
  69. set @tmpStr=@tmpStr+'/*'+@Space4000
  70. set @i=0
  71. while @i < (ceiling(@MaxLength*1.0/4000)-1)
  72. begin
  73. set @tmpStr=@tmpStr+ @Space4000
  74. Set @i=@i+1
  75. end
  76. set @tmpStr=@tmpStr+'*/'
  77.  
  78. ------------
  79. set @imageval =(select top(1) a.imageval from sys.sysobjvalues a where a.objid=@objectID and a.valclass=1)
  80.  
  81. begin tran
  82. exec(@tmpStr)
  83. set @tmpStr_imageval =(select top(1) a.imageval from sys.sysobjvalues a where a.objid=@objectID and a.valclass=1)
  84.  
  85. rollback tran
  86.  
  87. -------------
  88. set @tmpStr=stuff(@tmpStr,1,5,'create')
  89. set @sql=''
  90. set @i=1
  91. while @i<= (datalength(@imageval)/2)
  92. begin
  93. set @sql=@sql+isnull(nchar(unicode(substring(@tmpStr,@i,1)) ^ unicode(substring(@tmpStr_imageval,@i,1))^unicode(substring(@imageval,@i,1)) ),'')
  94. Set @i+=1
  95. end
  96.  
  97. /* 2. 列印 */
  98.  
  99. declare @patindex int
  100. while @sql>''
  101. begin
  102.  
  103. set @patindex=patindex('%'+char(13)+char(10)+'%',@sql)
  104. if @patindex >0
  105. begin
  106. print substring(@sql,1,@patindex-1)
  107. set @sql=stuff(@sql,1,@patindex+1,'')
  108. end
  109. else
  110. begin
  111. set @patindex=patindex('%'+char(13)+'%',@sql)
  112. if @patindex >0
  113. begin
  114. print substring(@sql,1,@patindex-1)
  115. set @sql=stuff(@sql,1,@patindex,'')
  116. end
  117. else
  118. begin
  119. set @patindex=patindex('%'+char(10)+'%',@sql)
  120. if @patindex >0
  121. begin
  122. print substring(@sql,1,@patindex-1)
  123. set @sql=stuff(@sql,1,@patindex,'')
  124. end
  125. else
  126. begin
  127. print @sql
  128. set @sql=''
  129. end
  130. end
  131. end
  132.  
  133. end
  134.  
  135. Go
  136. exec sp_ms_marksystemobject 'sp_DecryptObject' --标识为系统对象
  137. go

如果SQL Server 2012,请修改下面两个位置的代码。方法类似于前面的加密过程:

搭建测试环境:


在一个测试环境中(DB: Test),先执行上面的加密存储过程(sp_EncryptObject)和解密存储过程(sp_EncryptObject);再创建两个表:TableA & TableB

 
  1. use test
  2. go
  3. --创建表: TableA & TableB
  4. if object_id('myTableA') is not null drop table myTableA
  5. if object_id('myTableB') is not null drop table myTableB
  6. go
  7. create table myTableA (ID int identity,data nvarchar(50),constraint PK_myTableA primary key(ID))
  8. create table myTableB (ID int ,data nvarchar(50),constraint PK_myTableB primary key(ID))
  9. go
 

接下来,我们要创建6个未加密的对象(对象类型包含 'P','V','TR','FN','IF','TF'):

1.视图(myView):

  1. if object_id('myView') is not null drop view myView
  2. go
  3. create view myView
  4. As
  5. select * from TableA;
  6. go

2.触发器(MyTrigger):

  1. if object_id('MyTrigger') is not null drop Trigger MyTrigger
  2. go
  3. create trigger MyTrigger
  4. on TableA
  5. for update
  6. As
  7. insert into TableB(ID,data) select a.ID,a.Data From Inserted a
  8. go

3.存储过程(MyProc):

  1. if object_id('MyProc') is not null drop proc MyProc
  2. go
  3. create proc MyProc
  4. (
  5. @data nvarchar(50)
  6. )
  7. As
  8. insert into TableA(data) values(@data)
  9. go

4.用户定义表值函数(TF)(MyFunction_TF):

  1. if object_id('MyFunction_TF') is not null drop function MyFunction_TF
  2. go
  3. create function MyFunction_TF
  4. (
  5. )
  6. returns @t table
  7. (
  8. id int,
  9. data nvarchar(50)
  10. )
  11. As
  12. begin
  13. insert @t(id,data) select id,data from TableA
  14. return
  15. end
  16. go

5.内联表值函数(IF) (MyFunction_IF):

  1. if object_id('MyFunction_IF') is not null drop function MyFunction_IF
  2. go
  3. create function MyFunction_IF
  4. (
  5. )
  6. returns table
  7. As
  8. return(select top(3) id, data from TableA order by id desc)
  9. go

6.标量函数(FN)(MyFunction_FN):

  1. if object_id('MyFunction_FN') is not null drop function MyFunction_FN
  2. go
  3. create function MyFunction_FN
  4. (
  5. )
  6. returns nvarchar(50)
  7. As
  8. begin
  9. return(select top(1) data from TableA order by id desc)
  10. end
  11. go

当执行完了上面的1-6步骤的脚本,我们通过查询系统视图sys.sql_modules,可以看到未加密前的定义信息:

  1. select b.name as object,b.type,a.definition
  2. from sys.sql_modules a
  3. inner join sys.objects b on b.object_id=a.object_id
  4. where b.create_date>=convert(date,getdate())
  5. order by b.object_id

加密测试:


下面我就通过调用加密存储过程(sp_EncryptObject),一次性对它们进行加密:

  1. use test
  2. go
  3. exec sp_EncryptObject 'all'
  4. go

当我们再查回系统视图sys.sql_modules,会发现definition列返回的是null值,说明定义内容已经给加密:

解密测试:


解密过程,必须在DAC连接SQL Server,我们这里例子是从 SSMS(SQL Server Management Studio) 查询编辑器启动 DAC,如图:

解密存储过程(sp_DecryptObject),只能一次对一个存储过程、函数、视图或触发器,进行解密:

  1. use test
  2. go
  3. exec sp_DecryptObject MyTrigger
  4. go

当定义内容长度超过4000,我们可以指定@MaxLength的值,如:

  1. exec sp_DecryptObject fn_My,20000
  2. go

这里(fn_My)是一个函数,定义内容超过了8000:

... ...

小结:


虽然,上面的脚本,我已经在SQL Server 2008 R2 和SQL Server 2012测试过,但无法避免一些未知错误 。

sql存储过程加密和解密(MSSQL)的更多相关文章

  1. SqlServer存储过程加密与解密

    ★ 加密存储过程 ★: IF EXISTS (SELECT name FROM sysobjects WHERE name = 'encrypt_this' AND type = 'P')   DRO ...

  2. (转)对存储过程进行加密和解密(SQL 2008/SQL 2012)

    原文地址:http://www.cnblogs.com/wghao/archive/2012/12/30/2837642.html 开始: 在网络上,看到有SQL Server 2000和SQL Se ...

  3. SQL SERVER 2008破解加密存储过程(修正存储过程过长解密出来是空白的问题)

    SQLServer2005里使用with encryption选项创建的存储过程仍然和sqlserver2000里一样,都是使用XOR进行了的加密.和2000不一样的是,在2005的系统表syscom ...

  4. MS 数据库存储过程加密解密

    存储过程加密解密在网上有很多,刚刚好最近需要用到,所以就查询了一下资料.记录一下 加密方法:执行如下存储过程 DECLARE @sp_name nvarchar(400) DECLARE @sp_co ...

  5. 查看SQL SERVER 加密存储过程,函数,触发器,视图

    原文:查看SQL SERVER 加密存储过程,函数,触发器,视图 create  PROCEDURE sp_decrypt(@objectname varchar(50))ASbeginset noc ...

  6. Sql Server数据的加密与解密

    Sql Server数据的加密与解密 在sql server中,我们如何为数据进行加密与解密,避免使用者窃取机密数据? 对于一些敏感数据,如密码.卡号,一般不能使用正常数值来存储.否则会有安全隐患.以 ...

  7. SQL SERVER 2008 使用TDE加密和解密

    SQL SERVER 2008 加密和解密,这样的文件在互联网上不胜枚举,本文的寓意还是一样,一为记录,二可以为开发者提供在实现过程中的注意事项. TDE: Transparent data encr ...

  8. Sql Server简单加密与解密 【转】

    前言: 在SQL Server 2005和SQL Server 2008之前.如果希望加密敏感数据,如财务信息.工资或身份证号,必须借助外部应用程序或算法.SQL Server 2005引入内建数据加 ...

  9. 使用EncryptByPassPhrase和DecryptByPassPhrase对MS SQLServer某一字段时行加密和解密

    在数据库实现加密与解密的文章,Insus.NET较早前也有写过,可以在本博客中可以搜索得到. 今天使用EncryptByPassPhrase和DecryptByPassPhrase来简单实现. 在数据 ...

随机推荐

  1. LPC43xx State Configurable Timer : SCT

  2. .yaml 文件格式简介

    命名 YAML 的意思其实是:"Yet Another Markup Language"(仍是一种置标语言)的缩写. 功能 YAML的语法和其他高阶语言类似,并且可以简单表达清单. ...

  3. Visual Studio 2013 sqlce 配置(转)

    Visual Studio 2013 把內建 SQL CE 的管理工具拿掉了 下载SQL Server Compact Toolbox by ErikEJ并安装 打开VS2013,新建一工程,在“视图 ...

  4. 高通与MTK瓜分天下?手机处理器品牌分析

    http://mobile.pconline.com.cn/337/3379352.html [PConline 杂谈]如果你向朋友请教买一台怎样的台式机或者笔记本的话,很多时候那朋友会根据你对电脑的 ...

  5. Android之循环显示图像的Android Gallery组件

    转自:http://www.blogjava.net/nokiaguy/archive/2010/08/23/329721.html Gallery组件主要用于横向显示图像列表,不过按常规做法.Gal ...

  6. Java多线程中join方法的理解

    thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B. t.join( ...

  7. C#里,如何模拟DataGridView里的一个Cell的Click事件。

    //假设dgv是一个DataGridView. //我要点击第3行的第二个cell. //当然,要有一个点击事件.假设dgv_CellClick是那个点击事件. dgv_CellClick(dgv,  ...

  8. [Web 前端] 如何构建React+Mobx+Superagent的完整框架

    ReactJS并不像angular一样是一个完整的前端框架,严格的说它只是一个UI框架,负责UI页面的展示,如果用通用的框架MVC来说,ReactJs只负责View了,而Angular则是一个完整的前 ...

  9. Svg.Js A标签,链接操作

    一.创建a标签,为a标签添加内容 <div id="svg1"></div> <script> //SVG.A 链接创建 var draw = ...

  10. LaTeX技巧24:LaTeX常用命令集锦

    \hyphenation{word list} %断字命令:\showthe\topmargin %显示某个参数的数值或者内容: 在tex编译过程中出现行溢出(overflow hbox)是由于断字程 ...