Return to HomePage



Protect Data in the Registry Using Key Permissions (C#)


Applies to

* .NET Framework 2.0
* C#


Summary

The purpose of this code snippet is to illustrate how to secure data stored in the Windows registry through the use of registry access control list (ACL) permissions. By using these permissions, a user
can programmatically control who can and cannot access data stored in the registry.


Objectives

* Creating an applying a registry kep security context to control which users can access data from the registry

Scenarios

* Application comprised of multiple components that to access the same key material for secret encryption keys
* Application needs to store data configuration data to be retrieved on startup, such as database connection strings
* Application consists of a client tier that needs to store runtime credentials to connect to other application tiers


Solution Example

static void ControlledRegistryStore(string keyName, string valueName, string data)
{
		    		// Create a security context for a new key that we will use to store our data.
		    		// The security context will restrict access to only our user.
		   		 string user = [Environment.UserDomainName] + "\\" + [Environment.UserName;]
		    		[RegistrySecurity] security = new [RegistrySecurity();]
		    		[RegistryAccessRule] rule = new [RegistryAccessRule(user,]
		                    	[RegistryRights.FullControl,]
		                    	[InheritanceFlags.ContainerInherit,]
		                    	[PropagationFlags.None,]
		                    	[AccessControlType.Allow);]
		   		 [security.AddAccessRule(rule);]
	

		    		// Actually create the new registry key and apply the security context we just came up with.
		    		[RegistryKey] key = [Registry.CurrentUser.CreateSubKey(keyName,]
		                        [RegistryKeyPermissionCheck.ReadWriteSubTree,]
		                        security);
	

		    		// Write the data into the registry
		    		[key.SetValue(valueName,] data);
	
}


Problem Example

// Write an unprotected key and value into the registry. Default
// permissions allow all other users to access this key

RegistryKey key = Registry.CurrentUser.CreateSubKey(keyName);
key.SetValue(valueName, data);

* Any other user on the system can access this key because no security context has been applied


Test Case

The following classes must be included in any project making use of the sample code provided above:

using System.Security;
using System.Security.AccessControl;
using Microsoft.Win32;

Furthermore, two distinct users must be defined on the test system. These users will be referred to in the following example as User A and User B.

This test cases illustrates how a registry key secured using access
control permissions by one user cannot be access by another user in
the following 3 steps:

1) Store a key as "User A" (in this example, "User A" = Administrator)
		   		using the following code:
	

static void Main(string[] args)
{
		    		string keyName = "AdminSecuredKey";
		    		string valueName = "AdminSecuredValue";
	

		    		[ControlledRegistryStore(keyName,] valueName, "sensitive data");
	
}

static void ControlledRegistryStore(string keyName, string valueName, string data)
{
		    		// Create a security context for a new key that we will use to store our data.
		    		// The security context will restrict access to only our user.
		    		string user = [Environment.UserDomainName] + "\\" + [Environment.UserName;]
		    		[RegistrySecurity] security = new [RegistrySecurity();]
		    		[RegistryAccessRule] rule = new [RegistryAccessRule(user,]
		                    	[RegistryRights.FullControl,]
		                    	[InheritanceFlags.ContainerInherit,]
		                    	[PropagationFlags.None,]
		                    	[AccessControlType.Allow);]
		   		 [security.AddAccessRule(rule);]
	

		    		// Actually create the new registry key and apply the security context we just came up with.
		    		[RegistryKey] key = [Registry.CurrentUser.CreateSubKey(keyName,]
		                        	[RegistryKeyPermissionCheck.ReadWriteSubTree,]
		                        	security);
	

		    		// Write the data into the registry
		    		[key.SetValue(valueName,] data);
	
}

2) Attempt to retrieve the previously stored key as User A using the following code:

static void Main(string[] args)
{
		    		string keyName = "AdminSecuredKey";
		    		string valueName = "AdminSecuredValue";
	

		    		string data = [RegistryRetrieve(Registry.Users,] "\\" + keyName, valueName);
		    		if (data != null)
		        			[Console.WriteLine(data);]
		    		else
		        			Console.WriteLine("*** Inaccessible key ***");
	
}

static string RegistryRetrieve(RegistryKey parent, string keyName, string valueName)
{
		    		// Recursively search through each subkey of a parent key
		    		// checking to see if a match for the keyname exist and if
		    		// the data can be obtained from that key. Returns data upon
		    		// match and an error message otherwise. 
		    		foreach (string childName in [parent.GetSubKeyNames())]
		    		{
		        		try
		        		{
		            		[RegistryKey] child = [parent.OpenSubKey(childName);]
		            		string data = null;
		            		if [(child.Name.EndsWith(keyName))]
		            		{
		                			// We found the name, try to pull out key data
		                			data = [child.GetValue(valueName)] as string;
		            		}
		            	else
		            	{
		                		// No luck finding the name, try a depth-first recursive search
		                		data = [RegistryRetrieve(child,] keyName, valueName);
		            	}
		            	if (data != null) return data;
		        		}
		        		catch (Exception ex)
		        		{
		            		// Print out a message whenever we come across a 
		            		// key we don't have permissions to open
		            		[Console.WriteLine(childName] + ": " + ex.Message);
		        		}
		    		}
	

		    		return null;
	
}

3) Repeat Step 2 while logged in as User B. Compare results.


Expected Result

--------------------------------
"User A" (Administrator) output:
--------------------------------
C:\temp>whoami
vm-win2003\administrator

C:\temp>RegistrySnippet.exe
S-1-5-21-2537879503-2075122368-204042655-1006: Requested registry access is not
allowed.
sensitive data

---------------------------
"User B" (Joe User) output:
---------------------------
C:\temp>whoami
vm-win2003\joeuser

C:\temp>RegistrySnippet.exe
NetDDE: Requested registry access is not allowed.
S-1-5-19: Requested registry access is not allowed.
S-1-5-19_Classes: Requested registry access is not allowed.
S-1-5-20: Requested registry access is not allowed.
S-1-5-20_Classes: Requested registry access is not allowed.
S-1-5-21-2537879503-2075122368-204042655-1006: Requested registry access is not
allowed.
S-1-5-21-2537879503-2075122368-204042655-500: Requested registry access is not a
llowed.
S-1-5-21-2537879503-2075122368-204042655-500_Classes: Requested registry access
is not allowed.
NetDDE: Requested registry access is not allowed.
*** Inaccessible key ***


More Information

* Developers should not rely alone or registry permissions to control access to highly sensitive data. Consider encrypting certain data using the Data Protection API (DPAPI) in conjunction with registry access controls to add additional safeguards to more sensitive data stored in the registry. See Additional Resources section for links to encrypting data with the


Additional Resources

* Registry Security Guidelines (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_registry
* Working with Permissions (.NET): http://blogs.msdn.com/asanto/archive/2006/01/22/516009.aspx


Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Registry
* Author: Jonathan Bailey




Return to HomePage
Microsoft Communities