Basic kinds of identity used in scoping isolated storage are as follows (with details following):
NOTE: The terms ‘domain’ and ‘assembly’ are used to denote these specific identities in the remainder of the document.
First-time readers should not be daunted by the variety of identities used to scope data compartments. The “80%” case anticipated for all V1 isolated storage use is just going to be “user+domain”, that is: by application for a particular user. So when you use “app1” it has its store, and “app2” has its; other users of these same applications even on the same machine will get separate places for their data.
All isolated storage is contained by machine – that is, storage is not shared between machines, nor is data accessible across machines with this storage feature. (Inter-machine storage can be constructed on top of the basic functionality provided, but is not a goal of this feature itself.)
Machine containment is always implicit, by virtue of using storage facilities local to a given machine. The identity of a particular machine is never exposed by use of this feature.
Clarification: machine containment is described here in the sense that all user containment is implicitly scoped to the local machine code runs on.
For example, if Alice and Bob use an app on the same machine that app would use separate isolated stores for them. Then if Alice runs the same app on another machine she will get a different store there that is different from that on the first machine. This is the sense in which machine containment encompasses user.
<PUNT!> This spec uses the term “machine” compartment to refer to only machine containment irrespective of user, as opposed to what is actually machine+user containment which is denoted by the less cumbersome term “user”.
Isolated storage is contained by user in all but the most highly trusted level (level 3, below) of usage. User containment is important to ensure that information is never leaked from one user to another by means of this feature. The location of storage for user isolated storage is determined by the platform OS notion of user identity for the process the code is running in at the time the store is opened. Impersonation changes the notion of ‘current OS user’ dynamically.
User containment is always implicit, by virtue of using storage associated with a given user. The identity of a particular user is never exposed by use of this feature. On the Windows platform, user’s profile directory is where IsolatedStorage data is stored. (See data storage section following for details.)
On platforms that do not support different user login identities there is only one common user identity: effectively user containment is synonymous with machine containment in this case. Nevertheless, from a permission enforcement point of view this single user identity is still a user identity – in other words on these platforms, level 1 (below) isolated storage permission will allow use of this single (same as machine) user container.
Domain containment is based on evidence associated with the application domain the code is running in. As noted above, it is important to provide this IsolatedStorage containment even if based on a weak identity such as DNS name or installed location so as not to require digital signing in order to use the feature.
For web applications (a.k.a. “IE host”) hosted by a web browser, the URL determines the identity of the domain. Hosts such as IE associate URL evidence with the application domain that runs code from a web site. The domain identity for purposes of IsolatedStorage data compartmentalization is the full URL truncated at the rightmost slash. For example, if the URL evidence is “http://www.contoso.com/apps/myapp/home.htm” then the domain identity is derived as “http://www.contoso.com/apps/myapp”. Using the truncated URL rather than just the site allows a number of independent applications to coexist within a single site without conflicting storage use. While this does allow a malicious site to more easily use up storage, an intent attacker could still use different DNS site names rather easily in any case in which case there is no reliable way of knowing that it is really one entity consuming overly much storage. (To be blunt, we aren’t going to be able to deter malicious storage consumption very effectively in any case, so we should maximize benefit to real applications in the design.)
For shell hosted (a.k.a. “EXE host”) applications – typically, applications installed in a machine and launched – the domain identity is similarly derives from the application directory path. For example, if the main exe is run from the path “C:\office\winword.exe”, then truncation at the rightmost ‘\’ yields the domain identity “C:\office”.
Define app directory as: AddData(“AppDomainConfig.APPLICATION_BASE”)
The “friendly name” of the domain (AppDomain.GetFriendlyName) is associated with stores to help users identify the application that uses a certain store for purposes of administrating or clean-up of old information no longer needed. (We cannot expect users to recognize applications by their base URL.)
In addition or instead of containment by domain, signed code assemblies may also have their own data storage compartment. Assembly identity is based on cryptographic digital signature, either by strong name or by software publisher. Generally speaking, strong name identity is most flexible, allowing both compartments unique to a particular component or broader namespaces that allow a suite of components to use a common share provided all are based on the same signing key. Software publisher is a simpler model where only the key identity defines the containment.
Strong name identity (e.g. Microsoft.Office.* or Microsoft.Office.Word) is valid for code that is signed with the private key corresponding to the public key forming the root of the strong name namespace. Separate data compartments can be used based on full or partial forms of the strong name of a component. For example, a assembly signed with strong name “first.second.third.fourth” can used any or all of these IsolatedStorage compartments: “first.second.third.fourth”, “first.second.third.*”, “first.second.*”, “first.*”, or “*” – all of which are rooted to the key associated with the digital signature of the code.
Software publisher containment identity is based on the public key corresponding to the private key used to sign the code (like the publisher identity permission). Only the key is used to determine identity: the signing certificate and whether or not there is a trust relationship (a la WinVerifyTrust) established is not relevant to this feature.
If an assembly has both strong name and software publisher identity, then that composite identity is used to define assembly containment. In other words, only assemblies with the same combination of both kinds of identity can access the same store.
These basic identities enable the following types of isolation, listed in increasing level of trust (strong name and software publisher are basically same level of trust):
Level | Isolated storage data containment | Security impact |
0 | No isolated storage use allowed | None |
1 | user + domain | Data contained by domain
Potential denial-of-service |
user + domain + assembly | ||
2 | user + assembly | Potential app-to-app leakage |
3 | ALL users, domains, assemblies | Potential for total compromise |
Notes:
(1) all isolated storage containment implicitly includes “by machine” isolation
It is important to note that site identity is very weak (subject to spoofing), while cryptographically based code identities are very strong. Application code is expected to use appropriately strong identity to provide sufficient protection for the data being stored: always use strong identities for valuable or private data.
Here are a few scenario sketches to illustrate and motivate the need for these various types of storage:
This section describes the security risks associated with the varying types of usage of the IsolatedStorage feature as described. Default policy will be assigned according to the risk / utility balance of each kind of usage.
Level 0: the feature is disabled so trivially there is no associated risk.
Level 1: data containment is scoped by domain identity
Stored information is only available within the same domain, as determined by the domain identity associated with the application domain. Signed assemblies within the application still have data compartment scoped by the domain identity so can’t bridge outside of the application via this feature. The remaining risk is denial of service whereby excessive amounts of storage are consumed, preventing use of storage for other use. For V1 we don’t plan to implement any kind of protection for this sort of denial of service attack; users should be able to handle this inconvenience by reclaiming the storage via normal or possibly manual means.
Note that strong protection against this sort of attack is extremely difficult without severely limiting the utility of the basic feature. For example, web browser “cookies” attempt to prevent denial of service attacks by restricting the size of each cookie (4kb) and the number of cookies (20) a single web site can store. Unfortunately it is easy to circumvent this protection by simply using multiple web sites in one attack.
There is a potential denial-of-service attack with this level of feature usage in that malicious code could intentionally consume large quantities of storage. By using numerous domain identities (such as by using several web site addresses, all owned by the attacker) an arbitrary amount of storage can be consumed, beyond the limits set for one domain identity. The only defense against these nuisance attacks are: restrict usage of level 1 to somewhat trustworthy applications, explicit user action to clean out storage, or possibly by an administrative tool that uses some heuristic to detect maximum storage usage and delete it.
Level 2: data containment is scoped by user (and assembly identity)
Information store is scoped by the assembly identity and is independent of what domain it is used in. An application using a third party assembly that has this permission potentially risks information leaking from the application.
This is an issue of the application trusting the assembly it uses. Of course security policy must also trust the code to allow this kind of usage, but there is a separate issue of applications trusting their assemblies independent of that. Ultimately, by choice of the components they call applications implicitly make these trust decisions.
Level 3: unrestricted (any user, any store)
This level potentially allows access to any store, even another user. A high level of trust by policy and by applications, as described in the preceding paragraph, is necessary to ensure that no security weaknesses are exposed by use of this feature.
Code must have all necessary native platform OS rights to access any stores. For example on Windows 2000, user permissions to read/write the files underlying isolated storage must satisfy the Access Control List (ACL) restrictions of the file system.
Within the NGWS platform, applications may expect to always have OS rights to access isolated storage within the current user scope. However, applications that do (platform-specific) impersonation need to be responsible for ensuring that they have the proper rights in the new user identity to use storage.
Administrative code that uses the highest “Level 3” permission also needs to satisfy OS restrictions, which may require OS-dependent code or setup.