solated storage represents a subset of the file system that partially trusted applications can access to perform their private I/O operations. Introduced to preserve the integrity and the functionality of the whole operating system, isolated storage exploits the principle of the sandbox?isolate to prevent damage and malicious code. A set of stream-based classes let you work with such a storage system in an extremely simple and immediate way.
In .NET, not all applications run with the same set of security permissions. Security permissions represent the key to access critical system resources such as the file system, the registry, the clipboard, and the printer. Applications that attempt to access these resources without a valid authorization simply run into an exception. The mechanism behind security permissions is called Code Access Security (CAS) and represents the .NET answer to the growing demand for software security. CAS works by granting permissions to each assembly that is loaded in the CLR. The permission set for an assembly stems from the evidence that the assembly itself provides. The evidence defines the set of information that constitutes input for security decisions. This information includes any digital signatures the assembly may have and the location from which the assembly is accessed.
Just the location of download is a critical factor for applications. The set of permissions granted, in fact, changes considerably if the assembly is accessed locally or maybe remotely from a Web site. As you can guess, location dependent permissions pose a number of issues to developers that are going to write network-deployable classes. In this article, after a brief introduction to fully and partially trusted applications, I’ll focus on isolated storage?namely, a feature of the .NET Framework that elegantly works around the file system limitations for network-based applications, including ASP.NET applications.
While loading a managed assembly on behalf of a running application, the CLR is called to determine the set of permissions associated with that assembly. The CLR bases any decision both on the privileges of the currently logged user and the location from which the assembly is going to be downloaded. As a result, the permissions allowed to a certain assembly may prevent the code to perform certain necessary but potentially harmful operations such as writing files or accessing the registry. Applications automatically limited in their functionality for security reasons are said to be partially trusted applications.
When applications attempt to perform an operation not allowed by the ongoing security policy, the event is signaled with an exception of type SecurityException. The CLR prompts the user with a dialog box like the one shown in Figure 1.
|The Case of ASP.NET Applications
Just a few weeks before releasing version 1.0 of the .NET Framework, Microsoft decided to change the default account for the ASP.NET runtime process. Unlike ASP, ASP.NET does not run applications within the context of the LOCALSYSTEM account. ASP.NET applications are considered partially trusted applications and, subsequently, pages accessing the file system explicitly need to be granted write permissions to operate safely and effectively. How can you work around this I/O limitation? (See Sidebar: Security Zones)
One thing you can do is change the security permissions on the folder that contains the ASP.NET application. You must do this once during the setup of the application. Here’s a step-by-step guide.
Normally an ASP.NET application needs to create local files to park some data or to persist some settings. If the name of the file is known, not subject to change, and a default copy of the file is provided at setup time, you could also apply the algorithm above to the individual file rather than to the whole folder.
In other situations ASP.NET applications need to create temporary files that don’t survive the session or even the single request. In this case you can consider employing a simpler trick?using in-memory streams.
The MemoryStream class works in much the same way that a disk file stream does. The key difference is that MemoryStream creates a stream whose backing store is memory rather than a disk file. Let’s compare the code necessary to save a file to a file stream and to a memory stream.
The MemoryStream class encapsulates its data into an array of bytes and makes it available only in that form. You can write strings to a MemoryStream object only after you convert them to an array of unsigned characters. Unfortunately no method on the String class provides that capability. To do this job you must resort to the GetBuffer method of the Encoding class.
It is also easy to read back strings from a MemoryStream object. In this case you use the GetString method of the Encoding class, as shown below.
While the previously discussed trick?changing the permissions on a file or a folder?is just a hack, memory streams represents an interesting option because they can reduce the need for temporary buffers and files in an application.
Let’s make a more general consideration about partially trusted applications. The CAS infrastructure prohibits them from accessing the file system to avoid the risk that they could perform malicious code. However, one thing is getting a full access to the file system and all another one is persisting some user-defined bytes to disk. The second option still requires that the application accesses the file system, but?that’s the point?not necessarily the whole file system. This rather straightforward observation is at the root of the CAS feature called isolated storage.
(See Sidebar: When You Shouldn’t Use Isolated Storage)
What’s Isolated Storage, Anyway?