Have you ever managed Have you logged on to the system as a member and accidentally downloaded or ran a trojan? virus? Did your software accidentally access sensitive resources by referencing third-party components? Although the system provides complete role management and permission control, disguised malicious programs are executed again and again. The reason is that the depth and granularity of permission control by traditional security mechanisms are insufficient. Most common security mechanisms grant user permissions based on user login creden (usually passwords) and restrict the resources (usually directories and files) that can be accessed by users ). However, this method does not solve the following problems: Users obtain code from many sources, some of which may be unreliable; the Code may contain bugs or vulnerabilities, it may be exploited by malicious code. The Code sometimes performs some operations, but the user does not know that it will perform these operations. As a result, when a cautious and trusted user runs malware or contains the wrong software, the computer system may be damaged and private data may be leaked. Most operating system security mechanisms require that each piece of code be fully trusted (except for Web page scripts) before it can run. Therefore, a security mechanism that can be widely used is still needed, even if there is no trust between two computer systems, this mechanism also allows the code generated on one computer system to be safely executed on another system. Fortunately, the. NET platform provides code access security mechanisms in addition to role access security.
1. Introduction to CAS (code access security)
The CAS (Code Access Security/Code Access Security) mechanism provided by the. NET Framework is a more fine-grained Security mechanism, code access security allows the code to obtain different levels of reliability based on its location and other aspects of the Code identity. Code access security also implements different levels of trust in the Code, thus minimizing the number of codes that must be fully trusted before they can run. Using code access security can reduce the possibility of abuse of your code by malicious code or code containing errors. It can reduce your liability, because you can specify a group of operations that should allow code execution, and you can also specify a group of operations that will never allow code execution. Code access security also helps minimize the damage caused by security vulnerabilities in the code.
Code access security is a mechanism that helps restrict the access permissions of codes to protected resources and operations. In. NET Framework, code access security performs the following functions:
Define permissions and permission sets, which indicate the permissions to access various system resources.
Allows administrators to configure security policies by associating a permission set with a code group.
Allows the code to request the required permissions for running and other useful permissions, and specify the permissions that the Code absolutely cannot possess.
Grant permissions to each program to be loaded Based on the permissions requested by the Code and the operations permitted by the security policy.
This allows the code to require its caller to have specific permissions.
Allows the code to require its caller to have a digital signature so that only the caller of a specific organization or site can call the protected code.
By comparing the permissions granted by each caller on the call stack with the required permissions of the caller, the runtime code restrictions are enhanced.
To determine whether the code has been authorized to access resources or perform operations, the runtime security system traverses the call stack and compares the permissions granted by each caller with the currently required permissions. If no caller in the call Stack has the required permissions, a security exception is thrown and access is denied. The stack step is designed to prevent attacks. In such attacks, highly trusted code is called by less trusted code and unauthorized operations are performed using highly trusted code. All callers are required to have permissions at runtime, which may affect performance. However, this is critical to help protect the Code against code flooding attacks with a low level of trust. To optimize the performance, you can execute fewer stack steps in the Code. However, you must ensure that security defects are not exposed at any time.
2. CAS (code access security) Class Library
. NET Framework provides a set of code access permission classes to help protect a specific set of resources and operations.
The built-in code access permission class is mainly included in three namespaces:
System. Security;
System. Security. Permissions;
System. Security. Principal;
1. IPermission Interface
The IPermission interface defines how to implement various permission types.
Method Name
Description
IPermission Copy ()
Create and return a copy of the current permission
Void Demand ()
Permission verification. If the security requirements are not met, a SecurityException exception is thrown.
IPermission Intersect(IPermission target)
Create and return the intersection of current and specified permissions
Bool IsSubsetOf (IPermission target)
Determines whether the current permission is a subset of the specified permission.
IPermission Union (IPermission target)
Create and return the Union permission of the current permission and the specified permission
2. CodeAccessPermission class
The CodeAccessPermission abstract base class defines the infrastructure for all code access permissions .. Net Framework has many built-in permission objects inherited from this class for security control over access to various resources:
Name
Description
Data. Odbc. OdbcPermission
Permission to use ADO. net odbc Provider
Data. OleDb. OleDbPermission
Permission to use ADO. net ole db Provider
Data. SqlClient. SqlClientPermission
Permission to use ADO. net SQL Client Provider
Data. OracleClient. OraclePermission
Permission to use ADO. NET Oracle Provider
Drawing. Printing. PrintingPermission
Permission control of the print function
Messaging. MessageQueuePermission
MSMQ permission Control
Net. DnsPermission
Access DNS permission Control
Net. SocketPermission
Use Socket permission Control
Net. WebPermission
WEB access permission Control
Security. Permissions. EnvironmentPermission
Change the permission control of system environment variables
Security. Permissions. FileDialogPermission
Permission control in the file dialog box
Security. Permissions. FileIOPermission
File Operation permission Control
Security. Permissions. IsolatedStoragePermission
Permission Control for independent storage
Security. Permissions. ReflectionPermission
Reflected permission Control
Security. Permissions. RegistryPermission
Permission Control for Registry Access
Diagnostics. EventLogPermission
Event Log permission Control
Diagnostics. PerformanceCounterPermission
Access performance calculator permission Control
DirectoryServices. DirectoryServicesPermission
Access Permissions Of Activate Directory
ServiceProcess. ServiceControllerPermission
Service Control Permissions
Security. Permissions. SecurityPermission
General security permissions, such as Reflection and Unmanaged Code
Security. Permissions. UIPermission
UI permission Control
Web. AspNetHostingPermission
ASPNET host permission
PrincipalPermission
Role-based permission Control
Of course, we can also implement the IPermission interface or inherit from CodeAccessPermission to customize permission objects for more precise and flexible security control. This will be detailed in subsequent articles
Iii. Demonstration of CAS (code access security)
1. Request permissions programmatically
L implicit Permissions
When granting permissions, some implicit statements can grant other permissions. For example, if you grant FileIOPermission to access C:, you can also implicitly access the sub-directory of C: (this is permitted by Windows Account Security ). If you want to check whether other permissions are implicitly granted as a subset when granting permissions, you can use the following code:
Code CodeAccessPermission permissionA = new FileIOPermission (FileIOPermissionAccess. AllAccess, @ C :);
CodeAccessPermission permissionB = new FileIOPermission (FileIOPermissionAccess. Read, @ C: temp );
If (permissionB. IsSubsetOf (permissionA ))
{
Console. WriteLine (PermissionB is a subset of PermissionA );
}
Else
{
Console. WriteLine (PermissionB is NOT a subset of PermissionA );
}
The code execution result is as follows: PermissionB is a subset of PermissionA
L verify Permissions
The following code verifies the file access permission before accessing F: textfile.txt. If the file does not meet the security requirements, print: no rights to access this file.
Try
{
CodeAccessPermission permission = new FileIOPermission (FileIOPermissionAccess. AllAccess, @ F: textfile.txt );
Permission. Demand ();
// The code is used to access the F: textfile.txt file.
}
Catch (SecurityException)
{
Console. WriteLine (no rights to access this file );
}
L permission denied
The following code demonstrates that the access permission to the file directory is denied before the untrusted code is called, so as to prevent unauthorized access to the file by untrusted code. After the untrusted code is called, the previous permission is denied through CodeAccessPermission. RevertDeny.
CodeAccessPermission permission = new FileIOPermission (FileIOPermissionAccess. AllAccess, @ F :);
// Deny the access permission to directory F: to prevent future code calls from accessing directory F:
Permission. Deny ();
// Untrusted code,
Method ();
// Cancel rejection
CodeAccessPermission. RevertDeny ();
Public void Method (){
Try
{
FileStream din = File. OpenWrite (@ F: textfile.txt );
}
Catch
{
Console. WriteLine (Failed to open file );
}
}
The following code demonstrates granting only the read-only permission of Untrusted code to the directory to prevent untrusted code from non-read access to the file. After the untrusted code is called, the previous read-only control is removed through CodeAccessPermission. RevertPermitOnly.
CodeAccessPermission permission = new FileIOPermission (FileIOPermissionAccess. Read, @ F :);
// Only allow read permission on directory F: to avoid non-read access to the Directory F: directory by calling code later
Permission. PermitOnly ();
// Untrusted code,
Method ();
// Lift the limit
CodeAccessPermission. RevertPermitOnly ();
Public void Method (){
Try
{
FileStream din = File. OpenWrite (@ F: textfile.txt );
}
Catch
{
Console. WriteLine (Failed to open file );
}
}
L asserted permission
Assert allows the caller to execute permissions that the caller does not have. The following code demonstrates that the caller asserted his or her permission to access the file, thus avoiding the caller's rejection of the access permission to the file.
Try
{
CodeAccessPermission permission = new FileIOPermission (FileIOPermissionAccess. AllAccess, @ F :);
Permission. Deny ();
Test. Method ();
CodeAccessPermission. RevertDeny ();
}
Catch (SecurityException)
{
Console. WriteLine (no rights to access this file );
}
Class Test
{
Public static void Method ()
{
Try
{
CodeAccessPermission permission = new FileIOPermission (FileIOPermissionAccess. AllAccess, @ F :);
Permission. Assert ();
FileStream din = File. OpenWrite (@ F: textfile.txt );
CodeAccessPermission. RevertAssert ();
}
Catch
{
Console. WriteLine (Failed to open file );
}
}
}
It is very dangerous to use assertion at will. The method to block assertion is to declare in the caller's program to prohibit assertion:
[assembly: SecurityPermission(SecurityAction.RequestRefuse, Assertion = true)]
2. Request permissions in declarative form
In addition to the required code-based permissions, you can use attributes to request permissions. Attributes can be associated only when a class or a single method is used.
[FileIOPermission (SecurityAction. Deny, Write = @ F: textfile.txt)]
Public void Method ()
{
Try
{
FileStream din = File. OpenWrite (@ F: textfile.txt );
}
Catch
{
Console. WriteLine (Failed to open file );
}
}
If a permission is customized, a corresponding Attribute class should be defined to issue declarative requirements for your custom permissions. The declared Security Attribute must be derived directly or indirectly from SecurityAttribute. If the permission is for code access, the attribute class is derived from CodeAccessSecurityAttribute, and the latter is derived from SecurityAttribute. The Security Attribute Class must implement the CreatePermission method, which creates an instance of the permission object based on the associated custom permissions. Note that the associated custom permission class must be marked with SerializableAttribute to be serialized into metadata by the compiler. In addition, the property version of the custom permission must be defined in a set of programs that do not reference it. Custom permissions should also be defined in this set. This is required for declarative security because this attribute is executed during assembly loading and may not be created when a reference to this attribute is encountered. If you try to use this permission in a program that defines declarative permissions, TypeLoadException is thrown. Custom permission limits and their declared attributes will be elaborated in subsequent articles.