Hacking the Code ASP.NET Web Application Security [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Hacking the Code ASP.NET Web Application Security [Electronic resources] - نسخه متنی

James C. Foster, Mark M. Burnett

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








Working with .NET Encryption Features




Now that you understand the basics of .NET encryption, we need to examine some topics related to using these features. In this section, we will cover:





Creating random numbers





Keeping memory clean





Protecting secrets





Protecting communications with SSL






Creating Random Numbers














Summary:




Random numbers are a key part of cryptography, but it is nearly impossible for a computer to be completely random on its own




Threats:




Information leakage, data corruption, man-in-the-middle attacks, brute-force attacks




Random numbers are a key element of most forms of cryptography. At some point, the strength of the system is based on the ability to produce a random, unpredictable number. Without this randomness, an attacker might be able to predict the cryptographic calculations. For example, Netscape’s SSL encryption was cracked in 1995 because it used a weak random-number generator.


Because computers have difficulty with true randomness, they use what are called pseudorandom-number generators (PRNGs). To be used with cryptography, a PRNG should have good entropy. Entropy is the measure of randomness that refers to the unpredictability and the uniform distribution of a random number. A strong random-number generator is one that, given a list of numbers already generated, could not predict the next number in the sequence.


The .NET Framework uses the RNGCryptoServiceProvider to generate random numbers, which is a wrapper for the CryptGenRandom function in CrytpoAPI. This PRNG is considered random enough for all but the most extreme security requirements. If you want to implement even stronger random-number generators, check out www.schneier.com/yarrowl and www.irisa.fr/caps/projects/hipsor/HAVEGEl. Note that CryptoAPI gets its entropy from a surprisingly large number of system factors, but if you want to add further entropy, you can pass a string or byte array of entropy when creating the class.






Warning


When you’re using random numbers for cryptographic purposes, always use RNGCryptoServiceProvider, not the System.Random class. System.Random is based on a predictable function and is not considered a strong random-number generator.




Security Policy





Use only RNGCryptoServiceProvider to generate strong random numbers; avoid using System.Random.





Use external sources of entropy to further increase randomness of the PRNG.






Keeping Memory Clean














Summary:




You must carefully plan your code to prevent leaving secrets exposed in memory




Threats:




Information leakage




When working with sensitive data, you should always make sure you clean up after yourself; you don’t want unencrypted data left around in memory. To limit the possibility of leaving sensitive data in memory, you should use as few variables as possible, avoid caching plaintext, and explicitly clean up after cryptographic operations.


Normally the .NET Framework garbage collector will take care of reclaiming objects no longer used. But it is not predictable when garbage collection will occur, and when it does, the system does not actually clear the memory; it just marks it as available for reuse. Because that memory may contain important information, it is important to always clean up any cryptographic objects and variables. To do this, the .NET Framework provides a Clear() method for all cryptographic objects.


When you are finished with any cryptography-related variables, you should clear their contents. This includes not only ciphertext and plaintext variables but also crypto objects, keys, salt, and IV variables. Figures 4.21 and 4.22 show examples of how to do this.








private void cleaningExample()
{
// Setup
byte[] buffer = ASCIIEncoding.ASCII.GetBytes(_
"This is a secret for cleaningExample");
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.GenerateKey();
rijndael.GenerateIV();

  // Perform encryption
string encryptedString = Convert.ToBase64String(
rijndael.CreateEncryptor().TransformFinalBlock(
buffer, 0, buffer.Length));

  // Perform decryption
buffer = Convert.FromBase64String(encryptedString);
string decryptedString = ASCIIEncoding.ASCII.GetString(
rijndael.CreateDecryptor().TransformFinalBlock(
buffer, 0, buffer.Length));

  // Clean up
rijndael.Clear();
encryptedString = decryptedString = String.Empty;
buffer = null;
}







Figure 4.21: Clearing Crypto-Related Objects: C#










Private Sub cleaningExample()
' Setup
Dim buffer() As Byte = ASCIIEncoding.ASCII.GetBytes( _
"This is a secret for cleaningExample")
Dim rijndael As RijndaelManaged = New RijndaelManaged
rijndael.GenerateKey()
rijndael.GenerateIV()

  ' Perform encryption
Dim encryptedString As String = Convert.ToBase64String( _
rijndael.CreateEncryptor().TransformFinalBlock( _
buffer, 0, buffer.Length))

  ' Perform decryption
buffer = Convert.FromBase64String(encryptedString)
Dim decryptedString As String = ASCIIEncoding.ASCII.GetString( _
rijndael.CreateDecryptor().TransformFinalBlock( _
buffer, 0, buffer.Length))

  ' Clean up
rijndael.Clear()
encryptedString = decryptedString = String.Empty
buffer = Nothing

End Sub







Figure 4.22: Clearing Crypto-Related Objects: VB.NET


Note that some variables do not have Clear() methods, so we explicitly zero those out. Be sure to watch all subroutines you call to clear any variables used in those.


Security Policies





Clear out all variables used with cryptographic operations, including those for plaintext, ciphertext, keys, salts, IVs, and random numbers.





Use the Clear() method to clear out any sensitive data.





Use the Dispose() method to immediately free memory resources.





Explicitly zero out any variables that do not provide a Clear() method.






Protecting Secrets














Summary:




Secrets are a key part of a security system, but it is very difficult to completely protect all secrets




Threats:




Information leakage, data corruption, man-in-the-middle attacks, brute-force attacks




One of the most difficult aspects of secure programming is the process of keeping secrets, even if the code itself is compromised. It’s easy to store a secret in server-side code, but you cannot always be sure that your code is safe. Many ASP developers have been burned by storing database passwords in the Global.asa file, which should be secure, but a history of IIS exploits has left it and the passwords exposed. Even the best solutions we have for protecting secret data are not perfect and are still vulnerable if someone gains full access to the Web server.


You might use encryption to protect your data, but at some point your application must store the key used to encrypt that data. You want your application to have access to that key, but you must protect it so that others do not have access. Ultimately, it is impossible to protect this data from misuse, because an attacker could use the application itself to gain access. The best we can accomplish is to limit the ability to access these secrets. In addition to encryption keys, other important secrets to protect are:





Passwords to access other systems





Database connection strings





IP addresses of private servers





File paths to sensitive data files





There are many ways to gain unauthorized access to a Web server, some giving the attacker full control over the server and others giving only partial access. Here are some examples of the type of access attackers have gained in the past through various Windows, IIS, and other application exploits:





The ability to view a directory listing of the Web content directories





The ability to view the contents of any file within the Web content directories





The ability to view any file on the same partition as the Web content directories





The ability to write files to the Web content directory





The ability to execute any program on the same partition as the Web content directories





The ability to run a command prompt under the context of the anonymous user





The ability to run a command prompt under the context of the SYSTEM account





The ability to run commands and access the registry under the context of the SQL Server or other database account





The ability to view unencrypted traffic as it crosses the network





The important lesson here is that Web content is not always safe. On the other hand, the attacker might not always have full access to your server. The key to protecting secrets is to use a variety of protection techniques so that your application will be more resilient to an attacker who has partial access.


Some of the methods you can use to protect secrets are:





Storing secret data in a file





Storing secret data in the registry





Storing secret data in a database





Using the Data Protection API (DPAPI) to access the operating system’s protected store





Storing Secrets in a File



When using the file system to store secrets, be sure to use a file located outside the Web root and preferably on a separate partition. Use strict file permissions to limit read and write access to this file. Rather than hard-coding the file path, refer to it using environment variables. Although “security through obscurity” is not the best way to protect a file, you should avoid giving the file an overly obvious name such as passwords.txt.


The .NET Framework provides a storage system called isolated storage that provides a simple method for storing secrets to a file. The benefits of isolated storage are that you can restrict access to the store by user, assembly, or application domain and that the .NET Framework handles the details of managing file access. To the application, the isolated storage works like a file system. The storage appears as a root container to the application and where it can create files and directories. But the isolated storage system prevents the application from stepping outside the bounds of this storage container. Isolated storage works particularly well when you have multiple semitrusted applications on the same server. Although isolated storage does provide some mechanisms to secure the data, it was not designed to protect secrets, so you should not rely on it alone. Figures 4.23 and 4.24 show examples of how to store and retrieve data from isolated storage.








private void isolatedStorageExample() 
{
// using System.IO.IsolatedStorage;
string data = "dataForIsolatedStorage";
// prepare isolated storage for writing
IsolatedStorageFileStream isolatedStorage =
new IsolatedStorageFileStream("isolatedStorageExample.txt",
FileMode.OpenOrCreate, FileAccess.Write);
// write to isolated storage
StreamWriter sw = new StreamWriter(isolatedStorage);
sw.WriteLine(data);
sw.Close();
isolatedStorage.Close();

  // prepare isolated storage for reading
isolatedStorage =
new IsolatedStorageFileStream("isolatedStorageExample.txt",
FileMode.Open, FileAccess.Read);

  // read from isolated storage
StreamReader sr = new StreamReader(isolatedStorage);
Response.Write("Read from isolated storage: " +
sr.ReadLine() + "<br>");
sr.Close();
}







Figure 4.23: Storing and Retrieving Data from Isolated Storage: C#










Private Sub isolatedStorageExample()
' using System.IO.IsolatedStorage;
Dim data As String = "dataForIsolatedStorage"

  ' prepare isolated storage for writing
Dim isolatedStorage As IsolatedStorageFileStream = _
New IsolatedStorageFileStream("isolatedStorageExample.txt", _
FileMode.OpenOrCreate, FileAccess.Write)

  ' write to isolated storage
Dim sw As StreamWriter = New StreamWriter(isolatedStorage)
sw.WriteLine(data)
sw.Close()
isolatedStorage.Close()

  ' prepare isolated storage for reading
isolatedStorage = New IsolatedStorageFileStream( _
"isolatedStorageExample.txt", FileMode.Open, FileAccess.Read)

  ' read from isolated storage
Dim sr As StreamReader = New StreamReader(isolatedStorage)
Response.Write("Read from isolated storage: " + _
sr.ReadLine() + "<br>")

  sr.Close()
End Sub







Figure 4.24: Storing and Retrieving Data from Isolated Storage: VB.NET


Storing Secrets in the Registry



The registry has traditionally been a better mechanism for storing secrets in a Web application, because an attacker usually needs a higher level of access to be able to read the registry than one would ascertain from an anonymous account. For example, an attacker might be able to access the file system through FTP or a file share, but to read the registry usually requires running some code on the server. When storing secrets in the registry, be sure to set strict ACLs on the appropriate registry keys to limit access to those keys. Just as with files, obscurity is not full protection, but you should avoid using overly obvious key names.


Storing Secrets in the Database



Storing secrets in the database can be a good method, especially if you use a trusted connection to your database. Of course, the database connection string itself is a secret, so there are limits to this strategy. One benefit of using the database is that you can easily share the secrets across multiple servers in a Web farm.


Storing Secrets Using DPAPI



DPAPI is probably the most secure method for storing data using the operating system to manage encryption keys, but it does have some limitations. First, there are two choices where to store the data: the machine store and the user store. The machine store is less secure because it is accessible by anyone on the server, but a user store requires a loaded profile that ASP.NET does not provide. User stores can also get more complicated when impersonating multiple users in your Web application. The easiest method is to use the machine store but using extra entropy to help protect the data from others. Of course, you must store this entropy somewhere that your Web application can access.


To use DPAPI, you must wrap the P/Invoke calls to Crypt32.dll. For an example of using DPAPI, see http://msdn.microsoft.com/architecture/application/default.aspx? pull=/library/en-us/dnnetsec/html/SecNetHT08.asp.


Ultimately, the best strategy for storing secrets is to use a combination of the previously described techniques. For example, you could use a registry key to store the entropy for DPAPI access and store the DPAPI encrypted data using isolated storage. The actual techniques you use depend on how you prioritize security and performance and on the rights you have available on the hosting server.


In the end, you still will not have perfect protection of secrets, and your only real protection is to follow security best practices to keep your server secure.


Security Policies





Avoid storing secrets in code, even if it is compiled.





Never store any secret in plaintext.





Use a combination of file, registry, database, or DPAPI to store secrets.





Use obscurity, but only sparingly as an additional layer of protection in addition to proper encryption and access control.





/ 96