Security Features in .NET

I l @ ve RuBoard

Security architectures that predate .NET provide isolation and access control based on user accounts. One approach has been to isolate code on a per-user basis, but this doesn't always sufficiently protect one program from another if both programs are running on the same user 's behalf . Another approach has been to relegate code that is not fully trusted to a sandbox model of execution, in which code is run in an isolated environment, with no access to most services. The .NET Framework security model attempts to strike a balance between these two models of security by providing access to resources in order for useful work to be done and by requiring finer control of application security to ensure that code is identified, examined, and given an appropriate level of trust.

We'll look at the following key features of the .NET security model:

  • Role-based security

  • Web application security

  • Evidence-based security

  • Cryptography

  • Buffer overrun detection

Role-Based Security

Sometimes it is appropriate for authorization decisions to be based on an authenticated identity or on the role associated with the context of the code's execution. For example, bank tellers might be allowed to process requests up to a certain dollar amount, whereas anything larger will require the role of a supervisor. The .NET Framework provides the infrastructure that enables applications to incorporate such logic, building it around the concept of identities and principals. Role information might not necessarily be limited to the user's " group " as defined by the operating system.

For managing user identity, role-based security provides a unified model for authorization and authentication of principals based on identity and roles. ASP.NET also provides customization and functionality (such as Microsoft Passport cookie authentication and IIS-based impersonation) that are specifically targeted at Web application security requirements.

Authentication is the process of examining credentials (such as name and password) and establishing the identity of the principal. A principal might also have zero or more roles to which it belongs, representing authorizations. Application code can then learn the identity of the current principal or query it for a particular role to perform some privileged operation.

For enterprises , the Windows logon identity of users is an important form of identity for security, so the WindowsPrincipal class is provided to handle the authentication. The Windows username becomes the principal identity, and the groups the user belongs to are the names of the roles assigned.

You can define a generic principal object for applications that define their own authentication and authorization, such as by looking up passwords and a list of roles in an application-specific database. You can also define custom principals, providing further customization.

Web Application Security

ASP.NET was built with security in mind. It leverages IIS to provide strong support for common HTTP authentication schemes, including Basic, Digest, NTLM, Kerberos, and SSL/TLS client certificates. ASP.NET also supports Passport authentication and provides a convenient implementation of Forms-based (cookie) authentication. Regardless of which authentication scheme is employed, developers get a consistent programming and authorization model.

ASP.NET supports traditional methods of performing access control and also provides URL authorization, which allows administrators to provide XML configuration that allows or denies access to URLs based on the current user or role. Developers can easily code explicit authorization checks into their application or take advantage of the .NET common language runtime's support for declarative security to include control access to methods based on the calling user or role.

ASP.NET has an extensible security architecture that allows the developer to write custom authentication or authorization providers. These providers can handle authentication and authorization events in the application-level global.asax file; alternatively, a developer can write a module that can be reused across applications. In addition to built-in support for doing role-based security with Windows users and groups, ASP.NET applications can easily provide application-defined roles.

Evidence-Based Security

For all managed code on the platform, server, or client, evidence-based security applies different levels of trust to all running code and enforces security accordingly . This enables semitrusted code to be safely executed, subject to restrictions that can be controlled by the administrator. In addition to the trust of users, the trust of code with appropriate restrictions enforced on it is also critical to achieving good security in the .NET application space. Managed code running on the .NET Framework can be restricted at the interface level, which allows security to be effectively enforced on the code. As a result, large applications composed of many components can be safely deployed, with varying degrees of security enforced against the various components , all running in-process. This enables a number of possibilities not formerly available to applications:

  • Mobile code can be downloaded from unsecured sources and executed safely with restrictions.

  • Server hosts can run different site applications together in-process safely, improving performance.

  • Server applications can be extended with user-written code that is constrained to not interfere with overall server operation.

  • Programmable applications can safely run macro script associated with user documents.

Before any managed code runs, the security policy system determines what permissions to grant it based on evidence about the code assembly and what the code itself requests. Evidence can be anything known about the code, such as any valid digital signatures or the URL, site, or zone the code comes from. Security policy configured by the administrator or user specifies rules of using evidence to determine permissions to grant to code. After ensuring that the minimum permissions the code requests can be given, and excluding permissions the code does not want, the security policy system grants permissions and the code runs, limited by what the permissions allow it to do. If the policy would grant code less than the minimum it requests, the code is not run. The permission request also allows you to examine the code at deployment time to learn what permissions the developer declared it needs.

Most application code does not need to explicitly use evidence-based security, which is usually handled by the lowest levels of the standard class libraries. Nonetheless, all this application code benefits from the security being there. For example, when you run low-trust code from the Internet, you are protected against that code somehow calling into more trusted code installed on the machine and using it in a malicious way.

The one thing that many such applications will want to do with security is to include a permission request. This ensures that your code will run only if it gets the permissions it expects it will have, and no more. Other situations in which evidence-based security can help you include the following:

  • Limited access public API

    You can decorate a type or method with an attribute identifying it as requiring specific permissions or evidence in order to call or subclass it. For example, you can use this technique to create a public API that only other code from your Web site can call or only code signed with a certain key can use.

  • Resource protection

    When you define a class library that exposes a resource that needs protection, you can define a permission (as shown in a later example) that acts as a gatekeeper to the resource and use the security policy system to restrict access.

Cryptography

Cryptography is the art and science of keeping messages secure. It involves converting a plain-text message into a secret/ ciphertext ( otherwise known as encrypting ) and converting that secret/ciphertext back into the original plain text (this process is called decryption). In addition to providing confidentiality, cryptography is used in authentication, integrity and nonrepudiation. For more information, see Applied Cryptography by Bruce Schneier (John Wiley and Sons, 1996).

Cryptographic Algorithms

A cryptographic algorithm (also called a cipher ) is the mathematical function used for encryption and decryption. Cryptographic keys are used by the cipher to perform the encryption and decryption operations.

A symmetric cipher is an algorithm based on a single encryption key. Symmetric ciphers are designed to be efficient algorithms and are intended to encrypt large amounts of data. Examples are the Data Encryption Standard (DES), International Data Encryption Algorithm (IDEA), and Rivest Cipher 4 (RC4).

Asymmetric ciphers (public-key algorithms) are designed so that the key used for encryption is different from the key used for decryption ”a stranger can use the encryption key (public key) to encrypt a message, but only a person with the corresponding decryption key (private key) can decrypt the message. Asymmetric ciphers are more suited to key management and protocol security. Examples are RSA, Diffie-Hellman, and DSA.

Security protocols use a hybrid of symmetric/asymmetric algorithms. The session key (symmetric) is set up using an asymmetric cipher in which the public key (contained in a certificate) bootstraps the secure communication.

A hash function is a cryptographic algorithm that produces a compressed unique output (or message digest) for each blob of data supplied to it. The MD5 algorithm creates a 128-bit digest, and SHA-1 creates a 160-bit digest. Cryptographic operations rely on hashing for a couple of reasons ”to work on a smaller set of representative data (for efficiency, typically to verify signed data) and because it is computationally infeasible to use hashing to determine the original data given the message digest. (This raises the security bar when storing secrets ”for example, when the hash of a password is stored and compared rather than the password itself.) When a cryptographic hash is used to render secrets into a digest (as in the latter case described above, to avoid storing clear-text passwords), another technique can be used: "salting" the hash so a random number is stored unencrypted with the hash. This eliminate the risks associated with dictionary attacks (whereby an attacker tries every possible secret key to decrypt the encrypted data). As much as possible, secrets should not be stored ”instead, get the secret each time from the user. Writing Secure Code has more information on how to use Data Protection API (DPAPI) when storing a secret is unavoidable. Note that you can use Win32 DPAPIs (such as CryptProtectData/CryptUnprotectData) via PInvoke to store and retrieve secrets.

Random Number Generation

Random numbers are used in cryptographic operations ”for example, to generate keys. Clearly, if this process is predictable, encryption and the math behind are both rendered useless. Hence, you should avoid using rand() or any such na ve generator and instead use a cryptographically strong random number generator. In particular, you should use the RNGCryptoServiceProvider class via the GetBytes() method.

Validating data

Data must be validated as it crosses the boundary between untrusted and trusted environments because data can be purposely crafted to fault your application. Many server vulnerabilities are due to poor validation ”all input is suspect until proven otherwise ”so you should use the RegularExpressionValidator control.

The RegularExpressionValidator control confirms that the entry matches a pattern defined by a regular expression. This type of validation allows you to check for predictable sequences of characters , such as those in social security numbers, e-mail addresses, telephone numbers, postal codes, and so on, and it lets you eliminate invalid input that might be intentionally malicious to exploit a software flaw.

RegularExpressionValidator uses two key properties to perform its validation: ControlToValidate , which contains the value to validate, and ValidationExpression , which contains the regular expression to match.

Digital Signatures

To verify that a message originating from a particular sender has not been tampered with, digital signatures are used. Signatures can also be chained (with the data being encapsulated) to verify intermediate originators.

A digital signature verifies that a message has not been tampered with. The sender encrypts a hash of the message (which is more performant than encrypting the whole message) with his secret key and sends it with the message (M, Pr(h(M)) . The receiver can compute the hash of the message using h(M) and M and apply the sender's public key to the hash, thus decrypting the hashed message Pu(Pr(h(M))) and yielding h(M) . If the h(M) s computed in the two ways are the same, the message has not been tampered with. Such a conclusion can be reached because it is not possible to create two messages with the same hash (hence the term one-way function for h() ).

Digital Signatures and XML

The XML Digital Signature specification (XMLDSIG), which is currently under development by the IETF and the W3C, provides an easy way for application programmers to sign XML documents and fragments . Signed (and, in the future, encrypted) XML will become increasingly important as a means for securely sending messages over the Internet. XrML is also gaining popularity as a standard for expressing security policies.

Cryptography and Visual Basic .NET

The .NET Framework provides classes that implement a variety of cryptographic functions for encryption, digital signatures, hashing, and random number generation. Supported algorithms include asymmetric encryption (RSA and DSA), symmetric encryption (DES, TripleDES, RC2), and hashes (MD5, SHA1). The implementation uses a stream-based model ”for example, a stream of data from a file can be routed into an encryption object and the resulting stream will be sent over the network. A new managed library of cryptography functions is provided; it includes direct support for XML digital signatures.

Here's an example of using a block cipher to encrypt/decrypt a file stream using DES. This is a symmetric cipher.

 PrivateSubEncryptOrDecryptFile(ByValsInputFileAsString,_ ByValsOutputFileAsString,_ ByValbyteDESKey()AsByte,_ ByValbyteDESIV()AsByte,_ ByValDirectionAsCryptoAction) 'Createthefilestreamstohandletheinputandoutputfiles. DimfsInputAsNewFileStream(sInputFile,_ FileMode.Open,FileAccess.Read) DimfsOutputAsNewFileStream(sOutputFile,_ FileMode.OpenOrCreate,FileAccess.Write) fsOutput.SetLength(0) 'Variablesneededduringencrypt/decryptprocess DimbyteBuffer(4096)AsByte'holdsablockofbytesforprocessing DimnBytesProcessedAsLong=0'runningcountofbytesencrypted DimnFileLengthAsLong=fsInput.Length DimiBytesInCurrentBlockAsInteger DimdesProviderAsNewDESCryptoServiceProvider() DimcsMyCryptoStreamAsCryptoStream DimsDirectionAsString 'Setupforencryptionordecryption SelectCaseDirection CaseCryptoAction.actionEncrypt csMyCryptoStream=NewCryptoStream(fsOutput,_ desProvider.CreateEncryptor(byteDESKey,byteDESIV),_ CryptoStreamMode.Write) sDirection= "Encryption" CaseCryptoAction.actionDecrypt csMyCryptoStream=NewCryptoStream(fsOutput,_ desProvider.CreateDecryptor(byteDESKey,byteDESIV),_ CryptoStreamMode.Write) sDirection= "Decryption" EndSelect sbEncryptionStatus.Text=sDirection+ " starting..." 'Readfromtheinputfile,thenencryptordecrypt 'andwritetotheoutputfile. WhilenBytesProcessed<nFileLength iBytesInCurrentBlock=fsInput.Read(byteBuffer,0,4096) csMyCryptoStream.Write(byteBuffer,0,iBytesInCurrentBlock) nBytesProcessed=nBytesProcessed+CLng(iBytesInCurrentBlock) sbEncryptionStatus.Text=sDirection+_  " inprocess-Bytesprocessed- " +_ nBytesProcessed.ToString EndWhile sbEncryptionStatus.Text= "Finished " +sDirection+_  ".Totalbytesprocessed- " +nBytesProcessed.ToString csMyCryptoStream.Close() fsInput.Close() fsOutput.Close() EndSub 

Buffer Overrun Detection

Buffer overruns occur when a buffer (a stack or a heap) is overwritten because data larger than the buffer is copied into the buffer location. Variables declared on the stack are located next to the return address for the function's caller, and in the case of a stack overrun, this return address for the function gets overwritten by an address chosen by the attacker. Malicious code can then be executed. Typically, attackers supply malicious input that the program consumes unintentionally ”the malicious code runs under an intentionally privileged context. Heap overruns are similar, but they are trickier to exploit.

Microsoft intermediate language (MSIL) is a CPU-independent machine language that you can think of as an object-oriented machine language. However, to execute a method, the intermediate language is first converted to native CPU instructions by the CLR's Just-In-Time (JIT) compiler. During JIT compilation, the CLR verifies code to ensure memory type safety. This minimizes the risk of code unexpectedly circumventing security checks. A new compile-time option (the /GS option) adds special data called a canary into the stack between local data and the return address of functions. The canary value is random and is determined in the startup code for a binary. During code execution, when the function returns, the canary is checked ”if it has changed, a special error handler is called that halts program execution. You can customize the default security error handler by calling _set_security_error_handler with a pointer to the custom handler.

I l @ ve RuBoard


Designing Enterprise Applications with Microsoft Visual Basic .NET
Designing Enterprise Applications with Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 073561721X
EAN: 2147483647
Year: 2002
Pages: 103

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