Securing the Registry


The registry is the central storage area for all kinds of information for the local machine, the user, and applications. Consequently, keeping the registry secure is an important issue. Fortunately, the .NET Framework makes working with the registry a lot easier. These new ease of use features include added functionality for setting registry permissions. The following sections describe how you can keep the settings for your application secure.

Using the RegistryPermission Class

The RegistryPermission class provides code access security for the registry as long as you implement it correctly. The operative words are code access and correctly. The “A Word about Registry Security” section points out serious flaws in the implementation of the RegistryPermission class. The most serious issue is that it doesn’t actually affect the registry. You can still use any unmanaged application such as the Registry Editor to access the keys and their values. The second problem is that you must implement the security correctly, which leaves a lot of room for error. Listing 4.5 shows the code for this example. (The listing for this example contains only the essential information. You can find the full listing for this code in the \Chapter 04\C#\RegSecure or \Chapter 04\VB\RegSecure folder of the source code located on the Sybex Web site.)

Listing 4.5 Implementing Code Access Security for the Registry

start example
class AccessReg {    // Some global variables used to make registry access easier.    private RegistryKey        HKey;    // HKEY_CURRENT_USER reference.    private RegistryKey        CKey;    // Company key reference.    private RegistryKey        AppKey;  // Application key reference.    private RegistryPermission RegPerm; // Registry permission object.    private Boolean            RegStat; // Registry lock status.    public AccessReg()    {       // Permission for the company registry setting.       RegPerm =          new RegistryPermission(RegistryPermissionAccess.AllAccess,             @"HKEY_CURRENT_USER\Software\" + Application.CompanyName);       // Permission for the application registry setting.       RegPerm.AddPathList(RegistryPermissionAccess.AllAccess,          @"HKEY_CURRENT_USER\Software\" + Application.CompanyName +          @"\" + Application.ProductName + @"\0");       // Ensure access initially.       RegPerm.Demand();       // Get the HKEY_CURRENT_USER key.       HKey = Registry.CurrentUser.OpenSubKey("Software", true);       // Verify the company key exists.       CKey = HKey.OpenSubKey(Application.CompanyName, true);       if (CKey == null)          CKey = HKey.CreateSubKey(Application.CompanyName);       // Verify the application key exists.       AppKey = CKey.OpenSubKey(Application.ProductName, true);       if (AppKey == null)          AppKey = CKey.CreateSubKey(Application.ProductName);    }    public void Finalize()    {       // Close the keys.       AppKey.Close();       CKey.Close();       HKey.Close();       // Clear the references.       AppKey = null;       CKey = null;       HKey = null;    }    public void WriteData(String Value, String Data)    {       // Check the registry lock status.       if (RegStat)          RegPerm.Deny();       else          RegPerm.Assert();       try       {          // Write data to the registry.          AppKey.SetValue(Value, Data);       }       catch (SecurityException SE)       {          // Display an error message.          MessageBox.Show("Write Access Denied", "Security Error",             MessageBoxButtons.OK, MessageBoxIcon.Error);       }    }    public String ReadData(String Value)    {       // Check the registry lock status.       if (RegStat)          RegPerm.Deny();       else          RegPerm.Assert();       try       {          // Read data from the registry.          return (String)AppKey.GetValue(Value);       }       catch (SecurityException SE)       {          // Display an error message.          MessageBox.Show("Read Access Denied", "Security Error",             MessageBoxButtons.OK, MessageBoxIcon.Error);          // Return an error string.          return "Key Access Error!";       }    }    public void LockRegKey()    {       // Lock the registry key.       RegStat = true;    }    public void UnlockRegKey()    {       // Release any registry key lock.       RegStat = false;    } }
end example

The AccessReg class shows a number of tasks you can perform using the Microsoft.Win32 .RegistryKey and System.Security.Permissions.RegistryPermission classes. Yes, for whatever odd reason, Microsoft decided to place the two registry classes you need to use together in completely separate locations.

The code begins by creating RegPerm, the registry permission for the key used to store registry data for this program. The RegistryPermission constructor call creates a path to the company registry key. The code uses the AddPathList() method to add the application key to the list. You must include both paths to provide an adequate level of security. Otherwise, a caller could access the company key first, and then use that key to access the application key. The AccessReg() constructor uses the RegPerm.Demand() call to ensure the caller has the proper registry rights.

This portion of the code ends by opening three registry keys using the OpenSubKey() method. The first key accesses HKEY_CURRENT_USER\Software\, which is always available. The second key accesses the company key. If the company key is unavailable, then the code uses the CreateSubKey() method to create it. The third key is the application subkey. Like the company key, the code creates this key if it isn’t available.

The code includes a Finalize() method. All that this method does is ensure that the registry keys are closed and the global variables cleared. Otherwise, strange things can happen when you try to access the registry. One common error is that the key becomes unavailable, even though you know it’s in the registry.

The WriteData() and ReadData() methods are essentially the same. Both methods begin by inspecting a local variable, RegStat. This value determines when the registry is locked or opened to the current application. If the registry is locked, the code executes RegPerm.Deny(), which blocks access to both the company and application keys. Otherwise, the code uses RegPerm.Assert() to ensure the code can access the registry values. The code then uses the SetValue() method to write information to the registry or GetValue() to read information from the registry.

A Word about Registry Security

Securing the registry is important because it contains entries crucial to your machine’s functionality. Registry security in the Win32 API world depends on the RegSetKeySecurity() and RegGetKeySecurity() functions. The Win32 API also requires use of functions such as RegOpenKeyEx() and RegSetValueEx() to interact with the registry. You can find a list of these functions at http://msdn.microsoft.com/library/en-us/sysinfo/base/registry_functions.asp .

The Microsoft.Win32.RegistryKey class provides access to the registry without relying on Win32 API or Platform Invoke (PInvoke) calls. You can learn more about this class at http://msdn.microsoft.com/library/en-us/cpref/html/frlrfMicrosoftWin32RegistryKeyMembersTopic.asp . The System.Security.Permissions.RegistryPermission class provides code access security for your .NET application. However, the security measures leave the registry wide open to attack from any unmanaged application that happens along because this class doesn’t actually lock the registry.

To actually lock a registry key from prying eyes, you’d need an equivalent for the RegSetKeySecurity() and RegGetKeySecurity() functions. Consequently, if you really want to protect the registry, you need to use PInvoke calls. The “Using the RegGetKeySecurity() and RegSetKeySecurity() Functions” section of Chapter 15 demonstrates use of these two calls in securing the registry.

The massive holes in registry security aren’t limited to problems with physical locking and code access only security. If you don’t lock every path for a particular registry entry, it’s possible to use the RegistryKey class to access the value even though your code supposedly locked it. Read the “Canonicalization Problems Using Deny” write-up on the Deny() method at ms-help://MS.MSDNQTR.2003FEB.1033/cpguide/html/cpcondeny.htm for a fuller explanation of the problem. (This topic doesn’t appear online, so you need a local copy of MSDN to see it.) In short, you have to be very careful when relying on the .NET Framework to secure the registry. Microsoft may fix this problem sometime in the future.




.Net Development Security Solutions
.NET Development Security Solutions
ISBN: 0782142664
EAN: 2147483647
Year: 2003
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net