1. Using Traditional NT Security
You can't access the root directory for direct
file manipulation any longer (unless you pull some interesting tricks).
Applications must create subdirectories now, which are easier to
control from a security perspective. Most applications created today
don't even fully implement this basic level of security. It's important
that you give users only the rights they actually need. When users only
have to read files, then giving them write rights is a security
violation, even if it does make writing your application easier.
2. Using New NT Security Features
Many applications fail to work on Windows 7 because
they don't implement new NT security features. For example,
applications commonly place files in the \Windows or \Windows\System32
directories, even when they don't need to do so. Always verify that the
user has rights to directories other than those in the user's own \Users\ UserName directory. In addition, use the \Users\ UserName directory whenever possible to store user files.
Rely on shared folders next. Only use system
directories when absolutely required (which is almost never with the
Windows 7 setup). Rather than store application-wide information in the
\Program Files\ ApplicationName directory, store it in the \Users\All Users\ ApplicationName directory. When using the \Users\All Users\ ApplicationName directory, you must set security appropriate for your application because the security inherited from the \Users\All Users
won't actually allow the user to do anything. This added security
ensures that users can access application-wide data but can't create
anything in the \Users\All Users directory itself.
For years now, developers have abused common storage
areas such as the registry. Using the registry presents many problems,
not the least of which is that the registry is hard to back up and
prone to failure at the worst possible times. It's far better to use
the \Users\ Username \AppData\Roaming directory to store individual application settings as serialized XML. You can also store serialized XML settings in the \Users\All Users\ ApplicationName directory as needed.
NOTE
XML serialization is a powerful data storage
technique that's incredibly easy to implement, flexible, and less prone
to errors than many other ways of storing data. In addition, it's easy
to store both group and individual settings using XML serialization in
a way that makes it less likely the group or individuals will lose
their settings. You can read more about this technique at http://www.devsource.com/c/a/Techniques/XML-Serialization-Better-than-the-Registry/.
It's important to remember that the User Account
Control (UAC) severely limits the acquisition of certain information.
For example, the UAC specifically limits the amount of information you
can obtain from Windows Management Instrumentation (WMI). If your
application counts on the availability of certain types of restricted
WMI information, your application could fail, despite not having any
issue that your debugger can easily detect. Look for these sorts of
issues as you debug applications that suddenly stop working on Windows
7 (see http://msdn.microsoft.com/library/aa826699.aspx for details). On the other hand, Windows 7 also provides access to a number of new WMI features, as described at http://msdn.microsoft.com/library/aa394053.aspx.
3. Working with Zones
The concept of security zones originated with
Internet Explorer, and you can still see this concept at work in the
Internet Options applet shown in Figure 1.
In this case, selecting a particular zone for an Internet location
changes the security for that site. Likewise, you can change the zone
in which an application is operating to modify the privileges that the
application (and by extension the user) enjoys. Zone-based security
makes sense because you can preconfigure several scenarios and then
select the scenario that matches the user's current location. For
example, you can use one zone when the user works in a coffee shop and
another when the user is at the office. The concept of a zone is also
relatively easy to understand, so explaining the different security
setups to end users is easier.
Modern software requires the use of zones. You can't
be sure where a user is going to work. Users often work at a coffee
shop, the library, the beach, or other unsecure locations. The .NET
Framework currently recognizes six zones (in order of trustworthiness).
MyComputer:
This is the local computer. The code isn't accessing anything outside
the local computer, so it receives the highest trust level.
LocalIntranet:
This is the local network. The code is using a local server or other
source for data and code. Because the risk of contamination is slightly
higher, the code receives fewer permissions to perform tasks
automatically.
Trusted:
This is an override zone that enables the developer to create a special
configuration for trusted locations outside the local computer. Use
this zone with care because it can cause untold woe when the code
performs tasks that end up infecting the local computer, damaging data,
or compromising the system in other ways.
Internet:
This is the external network. The Internet zone can include the actual
Internet or simply locations outside the local network. You use the
Internet zone to strictly control access to data and code, but not to
cut it off completely.
Untrusted:
This is an external location that the code must access, but that you
don't trust. The code can still execute, but with significant
restrictions. In some cases, the code may not actually execute because
it can't access most local resources. You use this zone when you must
access something externally, but you can't validate the external access
to meet company standards.
NoZone:
The default state of all .NET code that doesn't specify a zone. If you
don't specify a zone, the code can do anything anywhere. In short, you
should never use this zone.
Zones
are part of Code Access Security (CAS). In fact, they form part of the
evidence you receive about an assembly, and you can use this
information to determine how to react to the code. Code can come from
anywhere today, so knowing the code's origin and security features is
important. You might normally execute a piece of code when it comes
from the local drive, but not execute precisely the same piece of code
when it originates on the Internet. Here's a listing of the evidence
presented as part of CAS for an assembly:
Application directory:
The location of the code. You might decide that a local assembly is
acceptable, but an assembly originating on a network drive isn't.
Hash: The cryptographic hash used to encrypt the assembly. Some hashes are easy to compromise, while others aren't.
Publisher:
This is the signature of the publisher who created the assembly. You
may decide that you'll accept assemblies signed by ABC Corporation but
not those signed by XYZ Company.
Site: The domain of origin for the code. For example, this evidence might be www.abc_corporation.com. You won't see both a site and an application directory presented as evidence.
Strong name:
The signed name of the assembly. This is the full identifier for the
assembly and includes the public key used to sign the assembly, version
number, and simple assembly name (among other items).
URL:
The actual download location for the code. In most cases, you'll see
the site and URL used together. For example, this entry might be http://www.abc_corporation.com/mydownload/simplestuff.dll.
Zone:
The zone of origin for the code. For example, if the application
obtains the code from the Internet, you'll see Internet in this
category.
4. Adding Security Roles
Role-Based Security (RBS) is the counterpart to CAS.
While CAS strives to control security by controlling the tasks that
code can perform (regardless of what the user can do), RBS places the
user in a specific role to control what the application presents as
functionality. A user can have several roles, depending on need,
location, and task. For example, a user can easily be in the manager
role when creating new accounts, but the standard user role when adding
data to a database. The idea is to control what the user does based on
the user's specific need. A user can also fill the roles of local user
and remote user based on location. When the user works from a coffee
shop, the application can place the user in the remote user role to
help prevent possible data corruption. In addition, the remote user
role may help prevent an outsider from eavesdropping on sensitive
information. In short, RBS controls the user, while CAS controls the
code. This two-pronged approach provides considerable flexibility.
RBS roles are completely free-form. You can create
as many roles as needed to define an application completely (unlike
zones, where the zones are predefined). The methods used to manage RBS
appear in the Principal and PrincipalPermission classes. You use methods such as IsInRole()
to determine the current user's role and configure the application
appropriately. It's also possible to use RBS in several ways:
Imperative security: As part of an in-code Demand()
Declarative security: As part of an attribute-based Demand()
Directly: Using code to examine the evidence presented by the Principal object