如何加密数据库的所有现有存储过程

时间:2022-09-11 17:05:20

Is there any possibility to encrypt all existing stored procedures of a SQL Server 2008 database AFTER they have been created via an SQLCMD script?

是否有可能在通过SQLCMD脚本创建SQL Server 2008数据库之后加密它们的所有现有存储过程?

The reason I want to do this is the following:
I'd like to develop the stored procedures without encryption so I can easily click on "Modify" in SQL Server Management Studio to check their contents.
However, for the deployment I'd like to encrypt them so I thought that maybe I could write a script which encrypts them only after they're created. For dev systems I simply wouldn't run the script while on end-user systems the script would be run.

我想这样做的原因如下:我想开发没有加密的存储过程,所以我可以轻松点击SQL Server Management Studio中的“修改”来检查它们的内容。但是,对于部署,我想加密它们,所以我想也许我可以编写一个脚本,只有在它们被创建后加密它们。对于开发系统,我不会在最终用户系统上运行脚本,而是运行脚本。

8 个解决方案

#1


3  

I have the same problem.

我也有同样的问题。

My solution is to put "-- WITH ENCRYPTION" in all of my stored procedures. This version is used by developers and stored in source control.

我的解决方案是在所有存储过程中加上“ - WITH ENCRYPTION”。此版本由开发人员使用并存储在源代码管理中。

I then use a tool (like sed) in my build to replace "-- WITH ENCRYPTION" with "WITH ENCRYPTION" on the files before I send them to be installed.

然后我在我的构建中使用一个工具(如sed)在我发送它们之前将文件中的“WITH WITH ENCRYPTION”替换为“WITH ENCRYPTION”。

For a pure SQL solution you could use REPLACE.

对于纯SQL解决方案,您可以使用REPLACE。

#2


4  

You might want to check Encrypting all the Stored Procedures of a Database :

您可能需要检查加密数据库的所有存储过程:

If you ever decide that you need to protect your SQL Stored Procedures, and thought encrypting was a good idea, BE VERY CAREFUL!!! Encrypting Database stored procedures SHOULD NOT be done without having backup files or some sort of Source Control for the stored procedures. The reason I say this is because, once they are encrypted, there is no turning around. (Yes, there are third party tools that will decrypt your code, but Why go through that trouble.)

如果你决定需要保护你的SQL存储过程,并认为加密是一个好主意,请非常小心!加密数据库存储过程不应该在没有备份文件或存储过程的某种源代码控制的情况下完成。我说这是因为,一旦加密,就没有转机。 (是的,有第三方工具可以解密您的代码,但为什么要经历这个麻烦。)

This trick is something I developed because my company needed to host the application on a different server, and we were concerned about our code being compromised. So, to deliver the database, we decided to encrypt all out stored procedures. Having over a hundred procedures written, I didn't want to open each procedure and paste 'WITH ENCRYPTION' in each and every stored procedure. (For those of you who do not know how to encrypt, refer How Do I Protect My Stored Procedure Code[^]). So I decided to make my own little C# application that did the same.

这个技巧是我开发的,因为我的公司需要在不同的服务器上托管应用程序,我们担心我们的代码被泄露。因此,为了交付数据库,我们决定加密所有存储过程。编写了一百多个程序,我不想打开每个程序并在每个存储过程中粘贴“WITH ENCRYPTION”。 (对于那些不知道如何加密的人,请参阅如何保护我的存储过程代码[^])。所以我决定制作自己的小C#应用程序。

This application is a console application made using Visual Studio 2005 and SQL server 2005. The input parameters are database name, Server address, database username and password. Once you are able to provide these details, you are ready to have all your stored procedures encrypted.

此应用程序是使用Visual Studio 2005和SQL Server 2005创建的控制台应用程序。输入参数是数据库名称,服务器地址,数据库用户名和密码。一旦您能够提供这些详细信息,您就可以加密所有存储过程。

I have put the code of my application here as is. For this code to work, you will need to add an "Microsft.SQlserver.SMO" refrence to the application, so that the classes such as "Database" and "StoredProcedure" are accessible.

我把我的应用程序的代码放在这里。要使此代码起作用,您需要向应用程序添加“Microsft.SQlserver.SMO”参考,以便可以访问诸如“Database”和“StoredProcedure”之类的类。

BEFORE YOU DO THIS, TAKE A BACKUP!!!!!!!
//Connect to the local, default instance of SQL Server. 
string DB = "";
ServerConnection objServerCOnnection = new ServerConnection();
objServerCOnnection.LoginSecure = false;
Console.WriteLine("Enter name or IP Address of the Database Server.");
objServerCOnnection.ServerInstance = Console.ReadLine();
Console.WriteLine("Enter name of the Database");
DB = Console.ReadLine();
Console.WriteLine("Enter user id");
objServerCOnnection.Login = Console.ReadLine();
Console.WriteLine("Enter Password");
objServerCOnnection.Password = Console.ReadLine();
Console.WriteLine(" ");
Server srv = new Server();
try // Check to see if server connection details are ok.
{
   srv = new Server(objServerCOnnection);
   if (srv == null)
   {
      Console.WriteLine("Server details entered are wrong,"
         + " Please restart the application");
      Console.ReadLine();
      System.Environment.Exit(System.Environment.ExitCode);
   }
}
catch
{
   Console.WriteLine("Server details entered are wrong,"
      + " Please restart the application");
   Console.ReadLine();
   System.Environment.Exit(System.Environment.ExitCode);
}
Database db = new Database();
try // Check to see if database exists.
{
   db = srv.Databases[DB];
   if (db == null)
   {
      Console.WriteLine("Database does not exist on the current server,"
         + " Please restart the application");
      Console.ReadLine();
      System.Environment.Exit(System.Environment.ExitCode);
   }
}
catch
{
   Console.WriteLine("Database does not exist on the current server,"
      + " Please restart the application");
   Console.ReadLine();
   System.Environment.Exit(System.Environment.ExitCode);
}
string allSP = "";

for (int i = 0; i < db.StoredProcedures.Count; i++)
{
   //Define a StoredProcedure object variable by supplying the parent database 
   //and name arguments in the constructor. 
   StoredProcedure sp;
   sp = new StoredProcedure();
   sp = db.StoredProcedures[i];
   if (!sp.IsSystemObject)// Exclude System stored procedures
   {
      if (!sp.IsEncrypted) // Exclude already encrypted stored procedures
      {
         string text = "";// = sp.TextBody;
         sp.TextMode = false;
         sp.IsEncrypted = true;
         sp.TextMode = true;
         sp.Alter();

         Console.WriteLine(sp.Name); // display name of the encrypted SP.
         sp = null;
         text = null;
      }
   }
}

#3


2  

WITH ENCRYPTION means that the code behind the proc is not stored in the SysComments table.

WITH ENCRYPTION意味着proc后面的代码不存储在SysComments表中。

You could write a script that does a exec sp_helptext 'MyProcName' and gets the contents into a VarChar (MAX) so it can hold multiline / large procedures easily and then modifiy the procedure from it's original state

您可以编写一个执行exec sp_helptext'MyProcName'的脚本并将内容放入VarChar(MAX)中,以便它可以轻松地保存多行/大型过程,然后从原始状态修改过程

CREATE MyProcName AS

SELECT SecretColumns From TopSecretTable

change CREATE to ALTER and AS surrounded by space or tab or newline (good place to use Regular Expressions) to WITH ENCRYPTION AS

将CREATE改为ALTER和AS,用空格或制表符或换行符(使用正则表达式的好地方)改为WITH ENCRYPTION AS

ALTER MyProcName WITH ENCRYPTION AS

SELECT SecretColumns From TopSecretTable

This will hide all code for the stored proc on the production server.

这将隐藏生产服务器上存储过程的所有代码。

You can put this in a LOOP or a CURSOR (not really a set based operation IMHO) for all objects of a specific type and/or naming convention that you want to encrypt, and run it every time you deploy.

对于要加密的特定类型和/或命名约定的所有对象,可以将其放在LOOP或CURSOR(实际上不是基于集合的操作IMHO)中,并在每次部署时运行它。

#4


1  

I would recommend creating the sproc in a multi-line string variable and then inserting or altering it using sp_executesql. The only annoying downside to this approach is doubling of single quotes for strings.

我建议在多行字符串变量中创建sproc,然后使用sp_executesql插入或更改它。这种方法唯一令人讨厌的缺点是字符串的单引号加倍。

DECLARE @action varchar(max);
SET @action = 'CREATE'; /* or "ALTER" */

DECLARE @withEncryption varchar(max);
SET @withEncryption = ''; /* or "WITH ENCRYPTION" */

DECLARE @sql varchar(max);
SET @sql = @action + ' PROCEDURE dbo.Something'
    (
        ....
    ) ' + @withEncryption +
    ' AS
    BEGIN
        DECLARE @bob varchar(10);
        SET @bob = ''Bob'';
        ....
    END;
    ';

EXEC sp_executesql @statement = @sql;

[Note the whitespace around the variables.]

[注意变量周围的空格。]

All of my scripts use this method, which works well once you get used to the quote doubling thing.

我的所有脚本都使用这种方法,一旦你习惯了引用加倍的东西,它就能很好地运行。

I also use a batch file to call the script, and SQLCMD-mode command line variables to select various behaviours, which makes it repeatable and easy to test.

我还使用批处理文件来调用脚本,并使用SQLCMD-mode命令行变量来选择各种行为,这使得它可重复且易于测试。

#5


0  

Use This Query which Encrypt All Procedures in database

使用此查询加密数据库中的所有过程

    CREATE TABLE #backup
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX) NOT NULL,
spname NVARCHAR(100) NOT NULL,
encrypttext NVARCHAR(MAX) NULL,
encryptstatus BIT NOT NULL
DEFAULT ( 0 )
)
DECLARE @sptexttable TABLE
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX),
spname NVARCHAR(100)
)
INSERT INTO @sptexttable ( sptext, spname )
SELECT [text],
[name]
FROM syscomments
JOIN sysobjects ON syscomments.id = sysobjects.id
AND sysobjects.xtype = 'p'
DECLARE @sptext NVARCHAR(MAX)
DECLARE @spname NVARCHAR(100)
DECLARE @counter INT
SET @counter = 1
WHILE @counter <= ( SELECT MAX(id)
FROM @sptexttable
)
BEGIN
BEGIN TRY

INSERT INTO #backup ( sptext, spname )
SELECT sptext,
spname
FROM @sptexttable
WHERE id = @counter
END TRY
BEGIN CATCH
END CATCH

IF NOT EXISTS ( SELECT [name]
FROM sysobjects
WHERE [name] = 'ce_LastIndexOf'
AND xtype = 'FN' ) 
BEGIN


EXEC
( 'CREATE FUNCTION ce_LastIndexOf
(
@strValue VARCHAR(4000),
@strChar VARCHAR(50)
)
RETURNS INT
AS BEGIN
DECLARE @index INT


SET @index = 0


WHILE CHARINDEX(@strChar, @strValue) > 0
BEGIN
SET @index = @index
+ CASE WHEN CHARINDEX(@strChar, @strValue) > 1
THEN ( LEN(@strValue) - LEN(SUBSTRING(@strValue,
CHARINDEX(@strChar, @strValue)
+ LEN(@strChar),
LEN(@strValue))) )
ELSE 1
END
SET @strValue = SUBSTRING(@strValue,
CHARINDEX(@strChar, @strValue)
+ LEN(@strChar), LEN(@strValue))
END
RETURN @index
END'
)


END
DECLARE @tempproc NVARCHAR(MAX)
DECLARE @procindex INT
DECLARE @beginindex INT
DECLARE @header NVARCHAR(MAX)
DECLARE @asindex INT
DECLARE @replacetext NVARCHAR(MAX)

SET @tempproc = ( SELECT sptext
FROM @sptexttable
WHERE id = @counter
)

IF ( SELECT CHARINDEX('CREATE PROC', UPPER(@tempproc))
) > 0 
BEGIN
BEGIN TRY
SELECT @procindex = CHARINDEX('PROC', UPPER(@tempproc))
PRINT @procindex
SELECT @beginindex = CHARINDEX('BEGIN', UPPER(@tempproc))
PRINT @beginindex
SELECT @header = SUBSTRING(@tempproc, @procindex,
@beginindex - @procindex)
SELECT @asindex = ( SELECT dbo.ce_lastindexof(@header, 'AS')
- 2
)
SELECT @replacetext = STUFF(@header, @asindex, 10,
CHAR(13) + 'WITH ENCRYPTION'
+ CHAR(13) + 'AS' + CHAR(13))
SET @tempproc = REPLACE(@tempproc, @header, @replacetext)

END TRY
BEGIN CATCH
END CATCH
END

UPDATE @sptexttable
SET sptext = @tempproc
WHERE id = @counter


--PLAY HERE TO M AKE SURE ALL PROCS ARE ALTERED
UPDATE @sptexttable
SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',
'ALTER PROC')
FROM @sptexttable
WHERE id = @counter
)
WHERE id = @counter
SELECT @sptext = sptext,
@spname = spname
FROM @sptexttable
WHERE id = @counter
BEGIN TRY
EXEC ( @sptext
)
UPDATE #backup
SET encrypttext = @sptext,
encryptstatus = 1
WHERE id = @counter
END TRY
BEGIN CATCH
PRINT 'the stored procedure ' + @spname
+ ' cannot be encrypted automatically'
END CATCH
SET @counter = @counter + 1
END
SELECT *
FROM #backup

#6


0  

I wrote a cursor, steps through and encrypts most objects.

我写了一个游标,逐步完成并加密大多数对象。

                            DECLARE cur_ENCRYPT_ANTHING CURSOR READ_ONLY
                            FOR
                                    SELECT  STUFF(src.definition,
                                                  CASE WHEN CHARINDEX('AS' + CHAR(13),src.definition,1) = 0
                                                       THEN CASE WHEN CHARINDEX('AS ' + CHAR(13),src.definition,1) = 0 THEN CHARINDEX('AS ',src.definition,1)
                                                                 ELSE CHARINDEX('AS ' + CHAR(13),src.definition,1)
                                                            END
                                                       ELSE CHARINDEX('AS' + CHAR(13),src.definition,1)
                                                  END,3,'WITH ENCRYPTION AS' + CHAR(13))
                                    FROM    (SELECT o.name
                                             ,      STUFF(RIGHT(sm.definition,LEN(sm.definition) - CHARINDEX('CREATE ',sm.definition,1) + 1),1,6,'ALTER') AS definition
                                             FROM   sys.sql_modules AS sm
                                                    JOIN sys.objects AS o ON sm.object_id = o.object_id
                                             WHERE  CAST(CASE WHEN sm.definition IS NULL THEN 1
                                                              ELSE 0
                                                         END AS BIT) = 0
                                                    AND type <> 'TR'
                                            ) AS src








                            DECLARE @VLS NVARCHAR(MAX)
                            OPEN cur_ENCRYPT_ANTHING

                            FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO @VLS
                            WHILE (@@fetch_status <> -1)
                                  BEGIN
                                        IF (@@fetch_status <> -2)
                                           BEGIN
                                                 BEGIN TRY
                                                       EXEC (@VLS)

                                                 END TRY
                                                 BEGIN CATCH
                                                       PRINT ERROR_MESSAGE()
                                                       PRINT ''

                                                       PRINT @VLS
                                                 END CATCH
                                           END
                                        FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO @VLS
                                  END

                            CLOSE cur_ENCRYPT_ANTHING
                            DEALLOCATE cur_ENCRYPT_ANTHING

#7


0  

1) I export Create code for SP and functions. Keep it backed up. for example D:\SP2.sql"

1)我导出为SP和函数创建代码。保持备份。例如D:\ SP2.sql“

2) this transact SQL code, generate the script to delete existing sP & Functions

2)这个transact SQL代码,生成删除现有sP&Functions的脚本

SELECT 'DROP PROCEDURE  [' + SCHEMA_NAME(p.schema_id) + '].[' + p.NAME + ']'  as A
FROM sys.procedures p
union
SELECT  'DROP FUNCTION ' + [name]  
FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0
order by a

3) This Poweshell code replace

3)此Poweshell代码替换

AS
BEGIN

by

WITH ENCRYPTION 
AS
BEGIN

The code

$File = "D:\SP2.sql"
$File2 = $File.Replace("SP2.sql","SP-WithEncrypt.sql")
$sortie=""
$SP = get-content -path $file
echo $SP.Count
For ($i = 0 ; $i -le $SP.Count)
{ if ($sp[$i] -eq "AS" -and $sp[$i+1] -eq "BEGIN")
   { $AEcrire = "`nWITH ENCRYPTION `n AS `n BEGIN"
   $i+=1 
          }
   else
   {$AEcrire =$sp[$i]
   }
   $sortie += "`n$AEcrire"

 $i+=1 
 $SP.Count-$i
}

$sortie| out-file $File2

Would be faster with a .replace( ,), but problem with End of lines...

使用.replace(,)会更快,但行结束的问题......

4) run the SP-WithEncrypt.sql in SSMS

4)在SSMS中运行SP-WithEncrypt.sql

#8


0  

I have made an update to one of the above answers by removing the dependency on the initial Begin Tag. I had a situation where not all my stored procedures had BEGIN and END.

我通过删除对初始Begin标记的依赖来更新上述答案之一。我遇到的情况是我的所有存储过程都没有BEGIN和END。

I used the AS clause instead and also used a case sensitive version of the charindex (by adding a collation)

我使用了AS子句,并使用了一个区分大小写的charindex(通过添加排序规则)

Its not a perfect solution but helped in getting more of my stored procedures encrypted.

它不是一个完美的解决方案,但帮助我加密了更多的存储过程。

Here is my updated code:

这是我更新的代码:

            IF OBJECT_ID('tempdb..#backup', 'U') IS NOT NULL 

             BEGIN

             DROP TABLE #backup

             END

            CREATE TABLE #backup

             (

             id BIGINT IDENTITY(1, 1),

             sptext NVARCHAR(MAX) NOT NULL,

             spname NVARCHAR(100) NOT NULL,

             encrypttext NVARCHAR(MAX) NULL,

             encryptstatus BIT NOT NULL

             DEFAULT ( 0 )

             )

            DECLARE @sptexttable TABLE

             (

             id BIGINT IDENTITY(1, 1),

             sptext NVARCHAR(MAX),

             spname NVARCHAR(100)

             )

            INSERT INTO @sptexttable ( sptext, spname )

             SELECT [text],

             [name]

             FROM syscomments

             JOIN sysobjects ON syscomments.id = sysobjects.id

             AND sysobjects.xtype = 'p'

            DECLARE @sptext NVARCHAR(MAX)

            DECLARE @spname NVARCHAR(100)

            DECLARE @counter INT

            SET @counter = 1

            WHILE @counter <= ( SELECT MAX(id)

             FROM @sptexttable

             )

             BEGIN





             BEGIN TRY





             INSERT INTO #backup ( sptext, spname )

             SELECT sptext,

             spname

             FROM @sptexttable

             WHERE id = @counter

             END TRY

             BEGIN CATCH

             END CATCH

              IF NOT EXISTS ( SELECT [name]

             FROM sysobjects

             WHERE [name] = 'CaseSensitiveIndex'

             AND xtype = 'FN' ) 

             BEGIN
                

             EXEC (
             'CREATE FUNCTION dbo.CaseSensitiveIndex(@source nvarchar(max), @pattern VARCHAR(50))
            RETURNS int
            BEGIN  
                return   CHARINDEX(@pattern COLLATE Latin1_General_CS_AS, @source COLLATE Latin1_General_CS_AS) 
            END; '
            )
            end


             IF NOT EXISTS ( SELECT [name]

             FROM sysobjects

             WHERE [name] = 'ce_LastIndexOf'

             AND xtype = 'FN' ) 

             BEGIN

                

             EXEC

             ( 'CREATE FUNCTION ce_LastIndexOf 

                (@strValue VARCHAR(max),

                @strChar VARCHAR(50)) 

            RETURNS INT

            AS

            BEGIN

            DECLARE @index INT

                

            SET @index = 0



            WHILE CHARINDEX(@strChar, @strValue) > 0

                BEGIN

                    SET @index = @index + CASE WHEN CHARINDEX(@strChar, @strValue) > 1 

                                 THEN 

                                    (LEN(@strValue) - LEN(SUBSTRING(@strValue,CHARINDEX(@strChar, @strValue) + LEN(@strChar),LEN(@strValue)))) 

                                 ELSE 

                                    1 

                                 END

                    SET @strValue = SUBSTRING(@strValue,CHARINDEX(@strChar, @strValue) + len(@strChar),LEN(@strValue))    

                END



                RETURN @index 

            END'

             )



             END 

             DECLARE @tempproc NVARCHAR(MAX) 

             DECLARE @procindex INT

             DECLARE @beginindex INT

             DECLARE @header NVARCHAR(MAX)

             DECLARE @asindex INT

             DECLARE @replacetext NVARCHAR(MAX)



             SET @tempproc = ( SELECT sptext

             FROM @sptexttable

             WHERE id = @counter

             )



             IF ( SELECT CHARINDEX('CREATE PROC', UPPER(@tempproc))

             ) > 0 

             BEGIN

             BEGIN TRY

             SELECT @procindex = CHARINDEX('PROC', UPPER(@tempproc))

             PRINT @procindex

             SELECT @beginindex=(select dbo.CaseSensitiveIndex(@tempproc, 'AS'))


             if(@beginindex=0) begin set @beginindex=( SELECT dbo.ce_lastindexof(@tempproc, 'AS'))end
             SELECT @header = SUBSTRING(@tempproc, @procindex,

             @beginindex )

             SELECT @asindex = ( SELECT dbo.ce_lastindexof(@header, 'AS')

             - 2

             )

             SELECT @replacetext = STUFF(@header, @asindex, 3,

             CHAR(13) + 'WITH ENCRYPTION'

             + CHAR(13) + 'AS' + CHAR(13))

             SET @tempproc = REPLACE(@tempproc, @header, @replacetext)



                                



             END TRY

             BEGIN CATCH

             END CATCH



                

             END



             UPDATE @sptexttable

             SET sptext = @tempproc

             WHERE id = @counter 



            --PLAY HERE TO MAKE SURE ALL PROCS ARE ALTERED

             UPDATE @sptexttable

             SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',

             'ALTER PROC')

             FROM @sptexttable

             WHERE id = @counter

             )

             WHERE id = @counter 



             SELECT @sptext = sptext,

             @spname = spname

             FROM @sptexttable

             WHERE id = @counter


             BEGIN TRY


             EXEC ( @sptext)

             UPDATE #backup

             SET encrypttext = @sptext,

             encryptstatus = 1

             WHERE id = @counter

             END TRY

             BEGIN CATCH

             PRINT 'the stored procedure ' + @spname

             + ' cannot be encrypted automatically'

             END CATCH





             SET @counter = @counter + 1

             END

            SELECT *

            FROM #backup where encryptstatus =0

#1


3  

I have the same problem.

我也有同样的问题。

My solution is to put "-- WITH ENCRYPTION" in all of my stored procedures. This version is used by developers and stored in source control.

我的解决方案是在所有存储过程中加上“ - WITH ENCRYPTION”。此版本由开发人员使用并存储在源代码管理中。

I then use a tool (like sed) in my build to replace "-- WITH ENCRYPTION" with "WITH ENCRYPTION" on the files before I send them to be installed.

然后我在我的构建中使用一个工具(如sed)在我发送它们之前将文件中的“WITH WITH ENCRYPTION”替换为“WITH ENCRYPTION”。

For a pure SQL solution you could use REPLACE.

对于纯SQL解决方案,您可以使用REPLACE。

#2


4  

You might want to check Encrypting all the Stored Procedures of a Database :

您可能需要检查加密数据库的所有存储过程:

If you ever decide that you need to protect your SQL Stored Procedures, and thought encrypting was a good idea, BE VERY CAREFUL!!! Encrypting Database stored procedures SHOULD NOT be done without having backup files or some sort of Source Control for the stored procedures. The reason I say this is because, once they are encrypted, there is no turning around. (Yes, there are third party tools that will decrypt your code, but Why go through that trouble.)

如果你决定需要保护你的SQL存储过程,并认为加密是一个好主意,请非常小心!加密数据库存储过程不应该在没有备份文件或存储过程的某种源代码控制的情况下完成。我说这是因为,一旦加密,就没有转机。 (是的,有第三方工具可以解密您的代码,但为什么要经历这个麻烦。)

This trick is something I developed because my company needed to host the application on a different server, and we were concerned about our code being compromised. So, to deliver the database, we decided to encrypt all out stored procedures. Having over a hundred procedures written, I didn't want to open each procedure and paste 'WITH ENCRYPTION' in each and every stored procedure. (For those of you who do not know how to encrypt, refer How Do I Protect My Stored Procedure Code[^]). So I decided to make my own little C# application that did the same.

这个技巧是我开发的,因为我的公司需要在不同的服务器上托管应用程序,我们担心我们的代码被泄露。因此,为了交付数据库,我们决定加密所有存储过程。编写了一百多个程序,我不想打开每个程序并在每个存储过程中粘贴“WITH ENCRYPTION”。 (对于那些不知道如何加密的人,请参阅如何保护我的存储过程代码[^])。所以我决定制作自己的小C#应用程序。

This application is a console application made using Visual Studio 2005 and SQL server 2005. The input parameters are database name, Server address, database username and password. Once you are able to provide these details, you are ready to have all your stored procedures encrypted.

此应用程序是使用Visual Studio 2005和SQL Server 2005创建的控制台应用程序。输入参数是数据库名称,服务器地址,数据库用户名和密码。一旦您能够提供这些详细信息,您就可以加密所有存储过程。

I have put the code of my application here as is. For this code to work, you will need to add an "Microsft.SQlserver.SMO" refrence to the application, so that the classes such as "Database" and "StoredProcedure" are accessible.

我把我的应用程序的代码放在这里。要使此代码起作用,您需要向应用程序添加“Microsft.SQlserver.SMO”参考,以便可以访问诸如“Database”和“StoredProcedure”之类的类。

BEFORE YOU DO THIS, TAKE A BACKUP!!!!!!!
//Connect to the local, default instance of SQL Server. 
string DB = "";
ServerConnection objServerCOnnection = new ServerConnection();
objServerCOnnection.LoginSecure = false;
Console.WriteLine("Enter name or IP Address of the Database Server.");
objServerCOnnection.ServerInstance = Console.ReadLine();
Console.WriteLine("Enter name of the Database");
DB = Console.ReadLine();
Console.WriteLine("Enter user id");
objServerCOnnection.Login = Console.ReadLine();
Console.WriteLine("Enter Password");
objServerCOnnection.Password = Console.ReadLine();
Console.WriteLine(" ");
Server srv = new Server();
try // Check to see if server connection details are ok.
{
   srv = new Server(objServerCOnnection);
   if (srv == null)
   {
      Console.WriteLine("Server details entered are wrong,"
         + " Please restart the application");
      Console.ReadLine();
      System.Environment.Exit(System.Environment.ExitCode);
   }
}
catch
{
   Console.WriteLine("Server details entered are wrong,"
      + " Please restart the application");
   Console.ReadLine();
   System.Environment.Exit(System.Environment.ExitCode);
}
Database db = new Database();
try // Check to see if database exists.
{
   db = srv.Databases[DB];
   if (db == null)
   {
      Console.WriteLine("Database does not exist on the current server,"
         + " Please restart the application");
      Console.ReadLine();
      System.Environment.Exit(System.Environment.ExitCode);
   }
}
catch
{
   Console.WriteLine("Database does not exist on the current server,"
      + " Please restart the application");
   Console.ReadLine();
   System.Environment.Exit(System.Environment.ExitCode);
}
string allSP = "";

for (int i = 0; i < db.StoredProcedures.Count; i++)
{
   //Define a StoredProcedure object variable by supplying the parent database 
   //and name arguments in the constructor. 
   StoredProcedure sp;
   sp = new StoredProcedure();
   sp = db.StoredProcedures[i];
   if (!sp.IsSystemObject)// Exclude System stored procedures
   {
      if (!sp.IsEncrypted) // Exclude already encrypted stored procedures
      {
         string text = "";// = sp.TextBody;
         sp.TextMode = false;
         sp.IsEncrypted = true;
         sp.TextMode = true;
         sp.Alter();

         Console.WriteLine(sp.Name); // display name of the encrypted SP.
         sp = null;
         text = null;
      }
   }
}

#3


2  

WITH ENCRYPTION means that the code behind the proc is not stored in the SysComments table.

WITH ENCRYPTION意味着proc后面的代码不存储在SysComments表中。

You could write a script that does a exec sp_helptext 'MyProcName' and gets the contents into a VarChar (MAX) so it can hold multiline / large procedures easily and then modifiy the procedure from it's original state

您可以编写一个执行exec sp_helptext'MyProcName'的脚本并将内容放入VarChar(MAX)中,以便它可以轻松地保存多行/大型过程,然后从原始状态修改过程

CREATE MyProcName AS

SELECT SecretColumns From TopSecretTable

change CREATE to ALTER and AS surrounded by space or tab or newline (good place to use Regular Expressions) to WITH ENCRYPTION AS

将CREATE改为ALTER和AS,用空格或制表符或换行符(使用正则表达式的好地方)改为WITH ENCRYPTION AS

ALTER MyProcName WITH ENCRYPTION AS

SELECT SecretColumns From TopSecretTable

This will hide all code for the stored proc on the production server.

这将隐藏生产服务器上存储过程的所有代码。

You can put this in a LOOP or a CURSOR (not really a set based operation IMHO) for all objects of a specific type and/or naming convention that you want to encrypt, and run it every time you deploy.

对于要加密的特定类型和/或命名约定的所有对象,可以将其放在LOOP或CURSOR(实际上不是基于集合的操作IMHO)中,并在每次部署时运行它。

#4


1  

I would recommend creating the sproc in a multi-line string variable and then inserting or altering it using sp_executesql. The only annoying downside to this approach is doubling of single quotes for strings.

我建议在多行字符串变量中创建sproc,然后使用sp_executesql插入或更改它。这种方法唯一令人讨厌的缺点是字符串的单引号加倍。

DECLARE @action varchar(max);
SET @action = 'CREATE'; /* or "ALTER" */

DECLARE @withEncryption varchar(max);
SET @withEncryption = ''; /* or "WITH ENCRYPTION" */

DECLARE @sql varchar(max);
SET @sql = @action + ' PROCEDURE dbo.Something'
    (
        ....
    ) ' + @withEncryption +
    ' AS
    BEGIN
        DECLARE @bob varchar(10);
        SET @bob = ''Bob'';
        ....
    END;
    ';

EXEC sp_executesql @statement = @sql;

[Note the whitespace around the variables.]

[注意变量周围的空格。]

All of my scripts use this method, which works well once you get used to the quote doubling thing.

我的所有脚本都使用这种方法,一旦你习惯了引用加倍的东西,它就能很好地运行。

I also use a batch file to call the script, and SQLCMD-mode command line variables to select various behaviours, which makes it repeatable and easy to test.

我还使用批处理文件来调用脚本,并使用SQLCMD-mode命令行变量来选择各种行为,这使得它可重复且易于测试。

#5


0  

Use This Query which Encrypt All Procedures in database

使用此查询加密数据库中的所有过程

    CREATE TABLE #backup
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX) NOT NULL,
spname NVARCHAR(100) NOT NULL,
encrypttext NVARCHAR(MAX) NULL,
encryptstatus BIT NOT NULL
DEFAULT ( 0 )
)
DECLARE @sptexttable TABLE
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX),
spname NVARCHAR(100)
)
INSERT INTO @sptexttable ( sptext, spname )
SELECT [text],
[name]
FROM syscomments
JOIN sysobjects ON syscomments.id = sysobjects.id
AND sysobjects.xtype = 'p'
DECLARE @sptext NVARCHAR(MAX)
DECLARE @spname NVARCHAR(100)
DECLARE @counter INT
SET @counter = 1
WHILE @counter <= ( SELECT MAX(id)
FROM @sptexttable
)
BEGIN
BEGIN TRY

INSERT INTO #backup ( sptext, spname )
SELECT sptext,
spname
FROM @sptexttable
WHERE id = @counter
END TRY
BEGIN CATCH
END CATCH

IF NOT EXISTS ( SELECT [name]
FROM sysobjects
WHERE [name] = 'ce_LastIndexOf'
AND xtype = 'FN' ) 
BEGIN


EXEC
( 'CREATE FUNCTION ce_LastIndexOf
(
@strValue VARCHAR(4000),
@strChar VARCHAR(50)
)
RETURNS INT
AS BEGIN
DECLARE @index INT


SET @index = 0


WHILE CHARINDEX(@strChar, @strValue) > 0
BEGIN
SET @index = @index
+ CASE WHEN CHARINDEX(@strChar, @strValue) > 1
THEN ( LEN(@strValue) - LEN(SUBSTRING(@strValue,
CHARINDEX(@strChar, @strValue)
+ LEN(@strChar),
LEN(@strValue))) )
ELSE 1
END
SET @strValue = SUBSTRING(@strValue,
CHARINDEX(@strChar, @strValue)
+ LEN(@strChar), LEN(@strValue))
END
RETURN @index
END'
)


END
DECLARE @tempproc NVARCHAR(MAX)
DECLARE @procindex INT
DECLARE @beginindex INT
DECLARE @header NVARCHAR(MAX)
DECLARE @asindex INT
DECLARE @replacetext NVARCHAR(MAX)

SET @tempproc = ( SELECT sptext
FROM @sptexttable
WHERE id = @counter
)

IF ( SELECT CHARINDEX('CREATE PROC', UPPER(@tempproc))
) > 0 
BEGIN
BEGIN TRY
SELECT @procindex = CHARINDEX('PROC', UPPER(@tempproc))
PRINT @procindex
SELECT @beginindex = CHARINDEX('BEGIN', UPPER(@tempproc))
PRINT @beginindex
SELECT @header = SUBSTRING(@tempproc, @procindex,
@beginindex - @procindex)
SELECT @asindex = ( SELECT dbo.ce_lastindexof(@header, 'AS')
- 2
)
SELECT @replacetext = STUFF(@header, @asindex, 10,
CHAR(13) + 'WITH ENCRYPTION'
+ CHAR(13) + 'AS' + CHAR(13))
SET @tempproc = REPLACE(@tempproc, @header, @replacetext)

END TRY
BEGIN CATCH
END CATCH
END

UPDATE @sptexttable
SET sptext = @tempproc
WHERE id = @counter


--PLAY HERE TO M AKE SURE ALL PROCS ARE ALTERED
UPDATE @sptexttable
SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',
'ALTER PROC')
FROM @sptexttable
WHERE id = @counter
)
WHERE id = @counter
SELECT @sptext = sptext,
@spname = spname
FROM @sptexttable
WHERE id = @counter
BEGIN TRY
EXEC ( @sptext
)
UPDATE #backup
SET encrypttext = @sptext,
encryptstatus = 1
WHERE id = @counter
END TRY
BEGIN CATCH
PRINT 'the stored procedure ' + @spname
+ ' cannot be encrypted automatically'
END CATCH
SET @counter = @counter + 1
END
SELECT *
FROM #backup

#6


0  

I wrote a cursor, steps through and encrypts most objects.

我写了一个游标,逐步完成并加密大多数对象。

                            DECLARE cur_ENCRYPT_ANTHING CURSOR READ_ONLY
                            FOR
                                    SELECT  STUFF(src.definition,
                                                  CASE WHEN CHARINDEX('AS' + CHAR(13),src.definition,1) = 0
                                                       THEN CASE WHEN CHARINDEX('AS ' + CHAR(13),src.definition,1) = 0 THEN CHARINDEX('AS ',src.definition,1)
                                                                 ELSE CHARINDEX('AS ' + CHAR(13),src.definition,1)
                                                            END
                                                       ELSE CHARINDEX('AS' + CHAR(13),src.definition,1)
                                                  END,3,'WITH ENCRYPTION AS' + CHAR(13))
                                    FROM    (SELECT o.name
                                             ,      STUFF(RIGHT(sm.definition,LEN(sm.definition) - CHARINDEX('CREATE ',sm.definition,1) + 1),1,6,'ALTER') AS definition
                                             FROM   sys.sql_modules AS sm
                                                    JOIN sys.objects AS o ON sm.object_id = o.object_id
                                             WHERE  CAST(CASE WHEN sm.definition IS NULL THEN 1
                                                              ELSE 0
                                                         END AS BIT) = 0
                                                    AND type <> 'TR'
                                            ) AS src








                            DECLARE @VLS NVARCHAR(MAX)
                            OPEN cur_ENCRYPT_ANTHING

                            FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO @VLS
                            WHILE (@@fetch_status <> -1)
                                  BEGIN
                                        IF (@@fetch_status <> -2)
                                           BEGIN
                                                 BEGIN TRY
                                                       EXEC (@VLS)

                                                 END TRY
                                                 BEGIN CATCH
                                                       PRINT ERROR_MESSAGE()
                                                       PRINT ''

                                                       PRINT @VLS
                                                 END CATCH
                                           END
                                        FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO @VLS
                                  END

                            CLOSE cur_ENCRYPT_ANTHING
                            DEALLOCATE cur_ENCRYPT_ANTHING

#7


0  

1) I export Create code for SP and functions. Keep it backed up. for example D:\SP2.sql"

1)我导出为SP和函数创建代码。保持备份。例如D:\ SP2.sql“

2) this transact SQL code, generate the script to delete existing sP & Functions

2)这个transact SQL代码,生成删除现有sP&Functions的脚本

SELECT 'DROP PROCEDURE  [' + SCHEMA_NAME(p.schema_id) + '].[' + p.NAME + ']'  as A
FROM sys.procedures p
union
SELECT  'DROP FUNCTION ' + [name]  
FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0
order by a

3) This Poweshell code replace

3)此Poweshell代码替换

AS
BEGIN

by

WITH ENCRYPTION 
AS
BEGIN

The code

$File = "D:\SP2.sql"
$File2 = $File.Replace("SP2.sql","SP-WithEncrypt.sql")
$sortie=""
$SP = get-content -path $file
echo $SP.Count
For ($i = 0 ; $i -le $SP.Count)
{ if ($sp[$i] -eq "AS" -and $sp[$i+1] -eq "BEGIN")
   { $AEcrire = "`nWITH ENCRYPTION `n AS `n BEGIN"
   $i+=1 
          }
   else
   {$AEcrire =$sp[$i]
   }
   $sortie += "`n$AEcrire"

 $i+=1 
 $SP.Count-$i
}

$sortie| out-file $File2

Would be faster with a .replace( ,), but problem with End of lines...

使用.replace(,)会更快,但行结束的问题......

4) run the SP-WithEncrypt.sql in SSMS

4)在SSMS中运行SP-WithEncrypt.sql

#8


0  

I have made an update to one of the above answers by removing the dependency on the initial Begin Tag. I had a situation where not all my stored procedures had BEGIN and END.

我通过删除对初始Begin标记的依赖来更新上述答案之一。我遇到的情况是我的所有存储过程都没有BEGIN和END。

I used the AS clause instead and also used a case sensitive version of the charindex (by adding a collation)

我使用了AS子句,并使用了一个区分大小写的charindex(通过添加排序规则)

Its not a perfect solution but helped in getting more of my stored procedures encrypted.

它不是一个完美的解决方案,但帮助我加密了更多的存储过程。

Here is my updated code:

这是我更新的代码:

            IF OBJECT_ID('tempdb..#backup', 'U') IS NOT NULL 

             BEGIN

             DROP TABLE #backup

             END

            CREATE TABLE #backup

             (

             id BIGINT IDENTITY(1, 1),

             sptext NVARCHAR(MAX) NOT NULL,

             spname NVARCHAR(100) NOT NULL,

             encrypttext NVARCHAR(MAX) NULL,

             encryptstatus BIT NOT NULL

             DEFAULT ( 0 )

             )

            DECLARE @sptexttable TABLE

             (

             id BIGINT IDENTITY(1, 1),

             sptext NVARCHAR(MAX),

             spname NVARCHAR(100)

             )

            INSERT INTO @sptexttable ( sptext, spname )

             SELECT [text],

             [name]

             FROM syscomments

             JOIN sysobjects ON syscomments.id = sysobjects.id

             AND sysobjects.xtype = 'p'

            DECLARE @sptext NVARCHAR(MAX)

            DECLARE @spname NVARCHAR(100)

            DECLARE @counter INT

            SET @counter = 1

            WHILE @counter <= ( SELECT MAX(id)

             FROM @sptexttable

             )

             BEGIN





             BEGIN TRY





             INSERT INTO #backup ( sptext, spname )

             SELECT sptext,

             spname

             FROM @sptexttable

             WHERE id = @counter

             END TRY

             BEGIN CATCH

             END CATCH

              IF NOT EXISTS ( SELECT [name]

             FROM sysobjects

             WHERE [name] = 'CaseSensitiveIndex'

             AND xtype = 'FN' ) 

             BEGIN
                

             EXEC (
             'CREATE FUNCTION dbo.CaseSensitiveIndex(@source nvarchar(max), @pattern VARCHAR(50))
            RETURNS int
            BEGIN  
                return   CHARINDEX(@pattern COLLATE Latin1_General_CS_AS, @source COLLATE Latin1_General_CS_AS) 
            END; '
            )
            end


             IF NOT EXISTS ( SELECT [name]

             FROM sysobjects

             WHERE [name] = 'ce_LastIndexOf'

             AND xtype = 'FN' ) 

             BEGIN

                

             EXEC

             ( 'CREATE FUNCTION ce_LastIndexOf 

                (@strValue VARCHAR(max),

                @strChar VARCHAR(50)) 

            RETURNS INT

            AS

            BEGIN

            DECLARE @index INT

                

            SET @index = 0



            WHILE CHARINDEX(@strChar, @strValue) > 0

                BEGIN

                    SET @index = @index + CASE WHEN CHARINDEX(@strChar, @strValue) > 1 

                                 THEN 

                                    (LEN(@strValue) - LEN(SUBSTRING(@strValue,CHARINDEX(@strChar, @strValue) + LEN(@strChar),LEN(@strValue)))) 

                                 ELSE 

                                    1 

                                 END

                    SET @strValue = SUBSTRING(@strValue,CHARINDEX(@strChar, @strValue) + len(@strChar),LEN(@strValue))    

                END



                RETURN @index 

            END'

             )



             END 

             DECLARE @tempproc NVARCHAR(MAX) 

             DECLARE @procindex INT

             DECLARE @beginindex INT

             DECLARE @header NVARCHAR(MAX)

             DECLARE @asindex INT

             DECLARE @replacetext NVARCHAR(MAX)



             SET @tempproc = ( SELECT sptext

             FROM @sptexttable

             WHERE id = @counter

             )



             IF ( SELECT CHARINDEX('CREATE PROC', UPPER(@tempproc))

             ) > 0 

             BEGIN

             BEGIN TRY

             SELECT @procindex = CHARINDEX('PROC', UPPER(@tempproc))

             PRINT @procindex

             SELECT @beginindex=(select dbo.CaseSensitiveIndex(@tempproc, 'AS'))


             if(@beginindex=0) begin set @beginindex=( SELECT dbo.ce_lastindexof(@tempproc, 'AS'))end
             SELECT @header = SUBSTRING(@tempproc, @procindex,

             @beginindex )

             SELECT @asindex = ( SELECT dbo.ce_lastindexof(@header, 'AS')

             - 2

             )

             SELECT @replacetext = STUFF(@header, @asindex, 3,

             CHAR(13) + 'WITH ENCRYPTION'

             + CHAR(13) + 'AS' + CHAR(13))

             SET @tempproc = REPLACE(@tempproc, @header, @replacetext)



                                



             END TRY

             BEGIN CATCH

             END CATCH



                

             END



             UPDATE @sptexttable

             SET sptext = @tempproc

             WHERE id = @counter 



            --PLAY HERE TO MAKE SURE ALL PROCS ARE ALTERED

             UPDATE @sptexttable

             SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',

             'ALTER PROC')

             FROM @sptexttable

             WHERE id = @counter

             )

             WHERE id = @counter 



             SELECT @sptext = sptext,

             @spname = spname

             FROM @sptexttable

             WHERE id = @counter


             BEGIN TRY


             EXEC ( @sptext)

             UPDATE #backup

             SET encrypttext = @sptext,

             encryptstatus = 1

             WHERE id = @counter

             END TRY

             BEGIN CATCH

             PRINT 'the stored procedure ' + @spname

             + ' cannot be encrypted automatically'

             END CATCH





             SET @counter = @counter + 1

             END

            SELECT *

            FROM #backup where encryptstatus =0