Showing posts with label basically. Show all posts
Showing posts with label basically. Show all posts

Monday, March 12, 2012

Key Maintenance and Stored Procedures

Basically I would like to ask whether parameters can be used to pass the value of the 'symmetric key id', 'certificate' and optionally 'password' to a stored procedure that uses encryption functions.

The reason this is appealing is that when encryption keys etc change over time (we have a requirement to decrypt data, destroy and create new keys, then encrypt data every time we lose a staff - don't ask), as we would be passing the value of keys, passwords and certificates as parameters to a standard stored procedure.

Hardcoded Example (Working)

USE PSS

GO

CREATE PROC insert_payer_ba

-- define parameters

@.param_rec_id NVARCHAR(MAX),

@.param_bsb NVARCHAR(MAX),

@.param_account NVARCHAR(MAX),

@.param_account_name NVARCHAR(MAX)

AS

BEGIN

OPEN SYMMETRIC KEY bartlett_sym

DECRYPTION BY CERTIFICATE bartlett_cert

WITH PASSWORD = 'Bartlett12_3';

DECLARE @.en_rec_id varbinary(max);

SELECT @.en_rec_id = EncryptByKey(Key_GUID('bartlett_sym'),@.param_rec_id);

DECLARE @.en_bsb varbinary(max);

SELECT @.en_bsb = EncryptByKey(Key_GUID('bartlett_sym'),@.param_bsb);

DECLARE @.en_account varbinary(max);

SELECT @.en_account = EncryptByKey(Key_GUID('bartlett_sym'),@.param_account);

DECLARE @.en_account_name varbinary(max);

SELECT @.en_account_name = EncryptByKey(Key_GUID('bartlett_sym'),@.param_account_name);

INSERT INTO [PSS].[dbo].[payer_ba_sym]

(rec_id, bsb, account, account_name)

VALUES (

@.en_rec_id,

@.en_bsb,

@.en_account,

@.en_account_name

);

CLOSE SYMMETRIC KEY bartlett_sym;

END

GO

PROPOSED USAGE (WHICH DOESN'T WORK)

USE PSS

GO

CREATE PROC insert_payer_ba

-- define parameters

@.param_symkeyguid NVARCHAR(MAX), --(tried VARBINARY as well)

@.param_cert NVARCHAR(MAX),

@.param_certpass VARBINARY(MAX),

@.param_rec_id NVARCHAR(MAX),

@.param_bsb NVARCHAR(MAX),

@.param_account NVARCHAR(MAX),

@.param_account_name NVARCHAR(MAX)

AS

BEGIN

OPEN SYMMETRIC KEY @.param_symkeyguid

DECRYPTION BY CERTIFICATE @.param_cert

WITH PASSWORD = @.param_certpass;

end

DECLARE @.en_rec_id varbinary(max);

SELECT @.en_rec_id = EncryptByKey(Key_GUID(@.param_symkeyguid),@.param_rec_id);

DECLARE @.en_bsb varbinary(max);

SELECT @.en_bsb = EncryptByKey(Key_GUID(@.param_symkeyguid),@.param_bsb);

DECLARE @.en_account varbinary(max);

SELECT @.en_account = EncryptByKey(Key_GUID(@.param_symkeyguid),@.param_account);

DECLARE @.en_account_name varbinary(max);

SELECT @.en_account_name = EncryptByKey(Key_GUID(@.param_symkeyguid),@.param_account_name);

INSERT INTO payer_ba_sym

(rec_id, bsb, account, account_name)

VALUES (

@.en_rec_id,

@.en_bsb,

@.en_account,

@.en_account_name

);

CLOSE SYMMETRIC KEY @.param_symkeyguid;

END

GO

Any assistance in correcting this syntax (if indeed these functions accept parameters would be greatly appreciated).

- Andrew

You can do this if you use dynamic SQL. That is build the SQL query as a string, then pass to the "EXEC" statement. For example:

DECLARE @.sqlstring NVARCHAR(60);

SET @.sqlstring = 'OPEN SYMMETRIC KEY ' + @.param_symkeyguid + ' DECRYPTION BY CERTIFICATE ' + @.param_cert;

EXEC (@.sqlstring);

Note that this procedure is a bit vulnerable especially because you are passing in a password as a parameter. You could make this somewhat more secure by having the certificate be encrypted by the database master key encrypted by the service master key. This will avoid the password issue.

In general, I would hesitate to pass sensitive information in as parameters (this includes the symmetric key and certificate ids). You should be sure that the proc checks the parameters very careful and that the permission on the procedure and the underlying objects are tightly controlled.

Please let me know if you would like further info.

Thanks,

Sung

|||

Also note that the other reason you need to check parameters and monitor permissions very closely is that this sort of parsing is VERY vulnerable to SQL injection attacks.

Sung

|||

Thanks Sung,

You are right about passing paswords as variables. In fact I will only pass the certifcate and key names as vars.

The syntax seems to work, I shall do some more testing, thanks mate.

- Andrew

|||

Hey Andrew,

I would still be careful about possible SQL injection attacks. One way you can minimize this is by doing a simple parameter check such as

if (cert_id(@.cert_name) is not null) ... <your code here>

else ... <your error code here>

This should be done for each type on all names passed in. This, at a minimum, checks to make sure that people are actually passing in a valid object names.

Hope this helps,

Sung

|||

I am including a couple of links for SQL injection articles that may be helpful. I highly recommend reading the second link even if you are already familiar with SQL injection.

· SQL Injection http://msdn2.microsoft.com/en-us/library/ms161953.aspx

· New SQL Truncation Attacks And How To Avoid Them http://msdn.microsoft.com/msdnmag/issues/06/11/SQLSecurity/default.aspx

Thanks,

-Raul Garcia

SDE/T

SQL Server Engine

|||

Hello Sung,

My old syntax prior to passing parameters for the certificate and key was this:

DECLARE @.en_rec_id varbinary(max);

SELECT @.en_rec_id = EncryptByKey(Key_GUID(bartlett_sym),@.param_rec_id); it worked but values for key etc were hardcoded

If I apply your method to the encryption statements:

DECLARE $sqlstring NVARCHAR(MAX);

SET @.sqlstring = 'EncryptByKey(Key_GUID(' + "'" @.param_bartlett_sym + "'" + '),' + @.param_rec_id + ')';

DECLARE @.en_rec_id varbinary(max);

SELECT @.en_rec_id = EXEC(@.sqlstring); -- when I run the code it bombs here near EXEC, so I need some help with this line

Any assistance appreciated.

- Andrew

|||

Hey Andrew,

It's actually a little easier than that. Only DDL and perhaps a few other statement types don't support dynamic SQL. Built-ins should already support dynamic SQL so you could simply directly call:

SELECT @.en_rec_id = EncryptByKey(Key_GUID(@.param_bartlett_sym),@.param_rec_id)

Also, Laurentiu suggested another website to check:

http://www.sommarskog.se/dynamic_sql.html

You can also look into the "sp_executesql" and "quotename" functions as they might help you.

Sung

|||

Thanks Sung,

Sorry about the delayed reply. Actually passing the sym key in the manner described eg

SELECT @.en_rec_id = EncryptByKey(Key_GUID(@.param_bartlett_sym),@.param_rec_id)

results in null.

So I'm not sure how to get a result...

This doesn't work (might be on the right track thought).

DECLARE @.en_rec_id varbinary(max);

DECLARE @.str_cert NVARCHAR(MAX);

SET @.str_cert = 'SELECT @.en_rec_id = EncryptByKey(Key_GUID(' + "'" + @.param_cert + "'" + '),' + @.param_rec_id + ')';

EXECUTE sp_executesql @.str_cert, N'@.en_rec_id VARBINARY OUTPUT', @.en_rec_id OUTPUT;

Basically I wish to run the dynamic query and have it pass the value of @.en_rec_id as output for later use in an insert statement in the same stored procedure.

See original post above.

Any help greatly appreciated.

- Andrew

|||

Hey Andrew,

Sorry for the late response.

I did a quick test and it seems to work for me. Quick question, where do you open the key? You can verify the key is actually open by checking the sys.open_keys catalog view. You will need to have the key open prior to encrypting with it.

Thanks,

Sung

Wednesday, March 7, 2012

Keeping 2 DBs in synch

Hi all, here are my goals: Have the same DB on two different stand-alone computers, and keep them up-to-date from each other.

Basically a user would input to a DB for a week. Then every week or two, update the other stand alone DB with the new input. The DB would be exactly the same.

What are my options for this? I'd like it as easy as possible! Are there any software packages that deal with this type of transfer, etc.? Thank you!Replication but this can get complicated depending on your scenario.

Is there any data entry going on with the second server or is it just standby or back up?

If the data entry is only happening on one server you can set up a simple snapshot replication scheme or you can push the data over using data transformation services and there is a somewhat flexible wizard for this.

Again, you are only doing data entry at one end you can always run a backup from one DB and restore to another.

If however you are doing data entry on both ends, merge replication is the way to go.

And finally in the SQL Server 2005 beta there is something called database mirroring which keeps two SQL Servers in sync by taking a snapshot and applying the trans log from one to the other and the copy monitors the production server and if it goes down your mirrored server picks right up where the production server left off.

many options. much to ponder.|||Thank you for your insight.

Yes, only one DB would be used for entry, the other for 'backup' and viewing. Maybe what would be best, is what would be easiest for a advanced end user to operate? (As in, running/backing and transferring the data atleast to us)

... or if I could automate some of these tasks in vb.net 03 ?...|||Replication you can make run automatically and forever by setting the subscription to never expire. No one would have to do anything until something changed.

Data Tansformation Services you can also schedule as a job to run automatically and this may be easier to set up and trouble shoot than replication.

Don't do the backup and restore. Requires certain rights an end user should'nt have and I would let an end user do any of this stuff.

If you do not want to make it automatic I have some VB6 code that fires off DTS without using the command shell. Sorry I do not have the .Net for it. STill stuck in the stone ages.|||An automated backup and restore is probably easiest to implement and manage, considering your limited requirements.|||Thanks again for the information.

Are there some good examples, guides, etc. to get me started on an automated backup and restore method? I'm not sure where to begin!!!

Keep Together Function Not Working

These 3 posts all address same problem: Basically, have some data, either in
a group of text boxes or in a table and they are ending up on two pages of
the report, when they should only be on one.
Has anyone found a solution?
http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=47aa22ae-f3a2-41bd-9b5b-a233914f7c7d&sloc=en-us
http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=12c7fbc6-1aca-4e3a-9b2f-e15917fb7c22&sloc=en-us
http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=76f3399b-06f1-4438-bd6a-d468578e6e20&sloc=en-usI HAVE FOUND A "DIRTY" WAY TO GET THE GROUPINGS WORKING.
THE TRICK IS TO CREATE NESTED GROUPING TABLES.
For example,
I have a query output with Agent name , client name and client details.
In order to keep them grouped, I create a table with one group, the Agent
(header, no details).
In that group, I create a table with one group, the Client (same as above).
And in that I group I create another table with the Client Details.
I only use details at the lower lever (the client details).
That works.
I don't like it because it makes the report complicated but it works.
"msflinx" wrote:
> These 3 posts all address same problem: Basically, have some data, either in
> a group of text boxes or in a table and they are ending up on two pages of
> the report, when they should only be on one.
> Has anyone found a solution?
> http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=47aa22ae-f3a2-41bd-9b5b-a233914f7c7d&sloc=en-us
> http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=12c7fbc6-1aca-4e3a-9b2f-e15917fb7c22&sloc=en-us
> http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=76f3399b-06f1-4438-bd6a-d468578e6e20&sloc=en-us
>|||Very interesting approach. Should work though and since most of my reports
are only three levels deep, I might try it.
Thanks for you assistance.
"Kyriakos" wrote:
> I HAVE FOUND A "DIRTY" WAY TO GET THE GROUPINGS WORKING.
> THE TRICK IS TO CREATE NESTED GROUPING TABLES.
> For example,
> I have a query output with Agent name , client name and client details.
> In order to keep them grouped, I create a table with one group, the Agent
> (header, no details).
> In that group, I create a table with one group, the Client (same as above).
> And in that I group I create another table with the Client Details.
> I only use details at the lower lever (the client details).
> That works.
> I don't like it because it makes the report complicated but it works.
> "msflinx" wrote:
> > These 3 posts all address same problem: Basically, have some data, either in
> > a group of text boxes or in a table and they are ending up on two pages of
> > the report, when they should only be on one.
> >
> > Has anyone found a solution?
> >
> > http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=47aa22ae-f3a2-41bd-9b5b-a233914f7c7d&sloc=en-us
> >
> > http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=12c7fbc6-1aca-4e3a-9b2f-e15917fb7c22&sloc=en-us
> >
> > http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.reportingsvcs&mid=76f3399b-06f1-4438-bd6a-d468578e6e20&sloc=en-us
> >
> >