- Types of .NET Security
- Using Imperative Security
- Using Declarative Security
- Advantages and Disadvantages of the Two Security Implementations
Using Declarative Security
Declarative security defines security requirements to use a resource at the assembly, class, method, property, event, and other levels. This method relies on attributes that you add to the resource in question.
For example, you can use declarative security to tell the system that the caller must meet specific minimum requirements to gain access to the program. You can also deny rights and define optional requirements for full access. Here's an example of all three kinds of declarative security, used at the assembly level. (Normally, you'd place these attributes in the AssemblyInfo.cpp file.)
// Security declarations. [assembly:PermissionSetAttribute(SecurityAction::RequestOptional, Name="FullTrust")]; [assembly:PermissionSetAttribute(SecurityAction::RequestMinimum, Name="Execution")]; [assembly:PermissionSetAttribute(SecurityAction::RequestRefuse,
Name="SkipVerification")];
These three attributes tell the system that the code must have Execute permission at a minimum. This might seem like a useless right to request, but code could have permission to execute on the local machine, but not via the Internet. The code can't request that the system use the SkipVerification permission. Skipping verification can make code load and execute faster, but it also means that the system isn't checking the code for changes. Because crackers seldom put a sign on their work saying they've made a dangerous change, skipping verification isn't a good idea. The code optionally can have the FullTrust permission, which would give it permission to perform all tasksat least in a given area.
You won't only control declarative security at the assembly level. For example, you might want to restrict access to a file for a particular method. You could use the technique shown in Listing 3 to accomplish this task.
Listing 3: Using Declarative Security to Restrict File Access
private: [System::Security::Permissions::FileIOPermissionAttribute( SecurityAction::Deny, All="C:\\Temp.txt")] System::Void btnDeny_Click(System::Object * sender, System::EventArgs * e) { Stream *FS = NULL; // A test file stream. // Try to access the file. try { FS = new FileStream("C:\\Temp.txt", FileMode::Open, FileAccess::Read); } catch(SecurityException *SE) { MessageBox::Show(SE->Message, "File IO Error", MessageBoxButtons::OK, MessageBoxIcon::Error); return; } // Display a success message. MessageBox::Show("File is open!", "File IO Success", MessageBoxButtons::OK, MessageBoxIcon::Information); // Close the file if opened. FS->Close();
}
This example accomplishes essentially the same task did the code in Listing 1. The attribute defines a SecurityAction, which is always required. The code then adds values to one or more properties for the attribute in question. The FileIOPermissionAttribute class includes an All property that defines the security for all actions. You could also use individual action properties, such as Read or Write to define specific security for those actions.
The big difference between Listing 3 and Listing 1 is that you're using declarative security to do it. Many forms of code access security have both declarative and imperative security. This duality of technique leads to the next section.