December 2004 - Posts

Introduction

Maybe some of you remember the UAB (Updater Application Block) on .NET Framework v1.x that was released somewhere in 2003 in the patterns & practices space at MSDN (more info on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/updater.asp). Using this block it was possible to manage updates for .NET Framework-based software over the web. The underlying idea is relatively easy to understand: the application connects to a website on a regular basis to get data about the application version history that is kept centrally on a web server. If the application detects that a new version is available, the assemblies can be downloaded using BITS (Backgrount Intelligent Transfer Service, a service that is also used for Windows Update) and copied to the local machine. Once the download has completed, the updated application can be started (after validitation and checking). The UAB block is available via the Microsoft Downloads website on http://www.microsoft.com/downloads/details.aspx?FamilyId=C6C17F3A-D957-4B17-9B97-296FB4927C30&displaylang=en and is worth to check out if you did not play with it before.

What's going on?

Today we're seeing that these patterns & practices efforts are taken to the core of the CLR and libraries (think of Enterprise Library, see http://www.microsoft.com/resources/practices/comingsoon.mspx, which replace the application blocks we know today, see http://www.microsoft.com/resources/practices/code.mspx). ClickOnce is one of these efforts which brings the UAB to the core of .NET. You can see ClickOnce as the MSI equivalent for managed code applications. For more info on the Enterprise Library take a look at my previous post on my blog, that contains a link to the downloads of the December 2nd MSDN Event @ Brussels where Rudi and David presented EntLib.

ClickOnce introduced

Some keywords and a little light meal exploration:

  • ClickOnce = UAB+; it contains all the features of the UAB but it's better integrated, positioned and it will be supported.
  • Integrated with Visual Studio 2005 through the "Project Properties", tab "Publish". The wizard-driven developers interface makes ClickOnce a really sweet experience.
  • Does not require the CLR on the client side; it contains a bootstrapper based on Win32 that can even deploy the .NET Framework Redist (and other redist packages such as J#, SQL 2005 Express, MDAC, etc).
  • ClickOnce has a rich API to control the download process and to provide offline support. There's also cryptography support for the manifests that are required on the server.
  • Whereas the UAB did not provide CAS (Code Access Security) preservation, the ClickOnce technology does. UAB runs in a fully trusted local app context, therefore ignoring CAS :-(.
  • Integrated support to launch the application online or offline (through the Start menu).

How to use?

In order to use it, you need the beta release or CTP release of Visual Studio 2005 (MSDN Subscribers have access to these releases, for more info check out the MSDN lab on http://lab.msdn.microsoft.com/). The basic steps are these:

  1. In Visual Studio, create an application.
  2. Go to the properties of the project in the Solution Explorer and locate the Publish tab. Please note that this properties view is a huuuuuuuuuge improvement in VS2005, e.g. to strong-name assemblies without swapping to the command-line to run sn.exe.
  3. Specify the publishing/installation location and configure the settings (e.g. redist packages, and update configuration). It allows you to specify for example when the app should check for updates (at startup or while the app is running) and whether the user is in control to make the decision to install or deny the update.
  4. Also set the version of the software package (supports auto-increment) and if needed, other Publish Options.
  5. Next, start the Publish Wizard via Build, Publish or on the properties sheet.
  6. For deployment security and tamper resistance of your applications you need to sign the application. The wizard will guide you with creating or reusing a strong-name key.
  7. Finally, the app will be deployed to the specified location (webserver typically) and the system will guide you to the publication page. Users just need to click the link on this page to download and install the software. Client-side the system will pop up a warning about the publisher of the software etc.
  8. When you want to change the software, just go ahead and make the appropriate changes. Then republish the software with a new version number and deploy. Depending on the configuration, the update will be downloaded when the app is running or when the app is restarted.

Behind the scenes, a new MIME type for the extension .application (Windows Container File) will be registered. This is used to launch the bootstrapper and to check the security evidence of the application concerning the publisher etc. The file is an XML file that is checked by the application to detect whether updates are available or not. Updates are stored in subfolders of the deployment folder with the name %APPNAME%_%VERSION%, e.g. ClickOnceDemo_1.0.0.0. A sample .application file:

Update: due to problems with the display of the XML code in the browser, I removed the sample file; you can still find it here

Enjoy!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

If you were not able to attend the MSDN event "Unleashing the Potential of the Microsoft Platform" on December 2nd, you can download the presentations now on http://www.microsoft.com/belux/nl/msdn/events/presentations.mspx including my PPT on SQL-NS. If you have any questions, remarks, tomatoes, just shoot! I'd like to hear from you.Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

How to store passwords?

A pretty well-known scenario: you're implementing a great website with forms authentication and you need to store the users' passwords somehow. But how? In this post I'll show you common techniques to do this in a secure way.

First solution - don't store passwords

Might sound ridiculous but in some scenarios it definitely makes sense. If you can avoid it, do it. Possible ways to implement this strategy are to use Windows authentication (intranet, extranet scenario), to use .NET PassPort or some other authentication system that does the work for you (some directory service that you can try to bind to, e.g. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod16.asp).

Okay, the first solution wasn't fair, we need a database

Nice, so you need to store the user credentials in a database. I'll not ask any questions on the security of your database right now (will be covered in future episodes on securing the DAL), let's just focus on how to keep the passwords secure inside the database. The keyword here is encryption. As you probably know, there are some different encryption categories. First of all we can consider the encryption algorithms that encrypt data in an irreversible way (hashing). Secondly, there is encryption that allows you to decrypt again. In this category you'll find symmetric and asymmetric encryption. A discussion...

Do you need to be able to retrieve the password later?

This is the number one question you should ask yourself. I hope the answer is definitely: "No". Maybe you think it is yes now, but in most cases you can avoid it. If you thought the answer for you was yes, you were likely thinking of the "Forgot password" link on your login page. A user forgets his password an you need to send the password back to the user's mail address for recovery. That's fine, but there are several other ways to recover a lost password without requiring the original password:

  • Use a secret question. Right... But how to keep the answer really secure? The answer is you can hash the answer to the secret question (see further for hashing) but this makes the answer case-sensitive if you don't look out (consider to lower case before hashing, which will make this more user friendly - but less secure). The security of this technique has to do with the fact that the user will be redirected to a page where the password can be reset (without requiring the original question), eventually using an extra step by using e-mail to send the link to the resetpassword page. There is quite some plumbing involved in here to maintain the user profile's state in the database but if you try to think about it in a logical manner, it should not be "mission impossible". If you're not using e-mail as an intermediate step, the secret question possibly becomes the weakest link in your security implementation (when the answer is correct, the user can reset the password). In this case, make sure the answer that the user provides is long enough (passphrase characteristics). But if you can, consider another roundtrip to the user by e-mail since only the real user should be able to receive the e-mail to click the "resetpassword link". Typically that link contains a parameter with the user's ID and a generated random value that has to match a field in the database that is stored in the user's row (e.g. resetpassword.aspx?user=12345&resetcode=13G2IUE91AE209PS49D). An overview of the ideal situation:
    • Click on "Forget password".
    • Ask the user for his username or password to retrieve the user's secret question. Show the question to the user and ask for the answer.
    • Check the answer by comparing hashes (of the lower-cased value, trim for spaces in the begin and at the end), i.e. the hash of the entered answer and the stored hash value in the database.
    • If the comparison succeeds:
      • Set the profile state to "Resetting" by modifiying some field in the database. This allows to provide resubmit reset password link functionality etc.
      • Generate a random value (see further on how to do this) and store it in the database on the user's row in some ResetCode field. Ideally, you store the time of the code generation as well, so that you can expire the reset code.
      • Compose an e-mail with the link in the aformentioned format containing the user ID and the resetcode and submit.
      • Notify the user about the fact that an e-mail was sent.
    • The user comes back to the site on the resetpassword page. Over there, retrieve the user's reset code based on the user ID parameter and compare it with the resetcode parameter in the URL. Also check if the user's account is in the "Resetting" state. If this is right:
      • Ask for a new password twice and perform the typical comparison and complexity checks.
      • Hash the password and store it in the database, reset the user's profile state to "Normal" and drop the reset code from the database.
      • Redirect to the logon page or perform automatic login
  • An alternative is to send a mail to the user with a reset password link without using a secret question first. This is in fact the same as the technique above, but less complex. It also relies on a resetcode and all the associated plumbing.

If you still need to be able to retrieve the password later on, you'll have to rely on a reversible encryption algorithm, typically a symmetric one such as 3DES. As the matter in fact, this moves the problem to another level, i.e. where to store the key used to encrypt/decrypt the user's password? I won't go into detail on this (in this post I assume you go for hashing) but I'll cover this later. The answer is DPAPI. But remember, you use DPAPI to store the key, not the passwords (this is because DPAPI relies on a machine secret, so in case of a machine crash the information can't be retrieved again or when using a server farm, encryption/decryption across multiple machines will fail). A common scenario where to use symmetric key encryption with DPAPI is to store credit card numbers and other sensitive data that you need to be able to retrieve again later on.

So, we go for hashing

I hope everybody who reads this blog knows about hashing. To summarize, hashing is a one-way function that converts an input value to an output value in a way that it is computationally impossible to retrieve the original input value back when you have the resulting output value. Two different inputs should be converted to a different output value as well and a little change to the input should have a big impact on the output. Hashing algorithms are fairly complex mathematical stuff in order to have a good distribution in the function domain and to comply to the criteria I mentioned. Two famous hashing algorithms are MD5 (Message Digest 5, the version after MD4, by Ron Rivest - on of the RSA guys) and SHA1 (Secure Hash Algorithm). Let's show how we can use hashing to store passwords in a secure way (first attempt):

  • Set a user's password (registration or profile update page):
    • Ask for the password with all the checking involved (complexity, ask it twice, mask passwords, don't forget server-side checking, etc).
    • Take the password an hash it using System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(string, string). I like this method name :-). The first parameter takes the password string, the second one "MD5" or "SHA1" depending on the algorithm you want to use.
    • Save the hash instead of the clear text password.
  • Login page:
    • Ask the user for his user name and password.
    • Retrieve the password hash from the database based on the user's name (because it's hashed the on-the-wire attack surface between the web server, application server and database server is minimized, i.e. no clear text password sniffing possible). Don't send the password to the database to compare it over there (can be sniffed on the network).
    • Hash the password that the user entered and compare it with the retrieved hash value.
    • Authentication passes when the comparison succeeds and fails otherwise.

This seems to be great, isn't it? Well, it is indeed safer than the storing the clear text password in the database. However, it can (and should) be better, read on.

Buy a dictionary

As I mentioned earlier, a hash is a one-way encryption system. So, when you have the hash value, you can't get back to the original value. Unfortunately this is only theory. We all know that users choose passwords that are quite predictable (English - or any other language - words, names, simple letter combinations). Now, what about creating a dictionary based on a long list of words mapped on their MD5 and/or SHA1 values? Put an index on the hash values and you're ready to go. When you have found the hash values of a bunch of users (e.g. by hacking into the database server or by stealing the database or just because you are the DBA on a hosting network and you're a bad guy) it's easy to join the dictionary with the user table to map users on their clear-text passwords if these are known. How to solve this problem? The answer is salting...

Salt-n-pepper

Well, drop the pepper. We only require salt. Salt is a random chunk of data that can be used to mitigate the risk of a dictionary attack. The general idea is not that difficult:

  • Set a user's password (registration or profile update page):
    • Ask for the password with all the checking involved (complexity, ask it twice, mask passwords, don't forget server-side checking, etc).
    • Generate a hash value (see further) and concatenate it with the user's password.
    • Take the password an hash it using System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(string, string). I like this method name :-). The first parameter takes the password string concatenation of the password and the salt,  the second one "MD5" or "SHA1" depending on the algorithm you want to use.
    • Save the hash instead of the clear text password, together with the salt (thus you need two fields, one for the hash and one for the salt).
  • Login page:
    • Ask the user for his user name and password.
    • Retrieve the password hash from the database based on the user's name (because it's hashed the on-the-wire attack surface between the web server, application server and database server is minimized, i.e. no clear text password sniffing possible). Don't send the password to the database to compare it over there (can be sniffed on the network).
    • Retrieve the salt from the database based on the user's name.
    • Hash the concatenation of the retrieved salt and the password that the user entered and compare it with the retrieved hash value.
    • Authentication passes when the comparison succeeds and fails otherwise.

An attacker who steals the database now has more difficulties to perform a dictionary attack. Now we need to take all words from a dictionary, concatenate the words with the salt (on a user-per-user basis), hash them and compare. The longer the salt, the more time it will take to calculate the hash. Another problem for the attacker is to get to know how the concatenation of the hash and salt is done (in front of the password, at the end of it, ...). A dictionary attack is still possible but not with a static dictionary, therefore eliminating the real risk.

How to generate the salt?

A hash should be cryptographically strong. Because of this, you should never use System.Random to create the salt (not strong enough). Instead, use the System.Security.Cryptography.RNGCryptoServiceProvider class as follows:

   RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
   byte[] buf = new byte[size]; //size is length of the salt
   rng.GetBytes(buf);
   string salt = Convert.ToBase64String(buf);

Sample

Take a look at http://www.bartdesmet.net/download/hash.aspx for a sample of the techniques described in this post. The code is listed on the page as well.

MD5 or SHA1?

Nice discussion... MD5 hashes are shorter than SHA1 but MD5 is faster than SHA1. Now, if security should be as high as possible, MD5 even with hashing should not be your choice. Consider to use SHA1 instead. MD5 is considered to be unsafe since August 2004 (publication of article by Wang, Feng, Lay and Yu) because of the discovery of collisions. For more information about this, take a look at http://eprint.iacr.org/2004/199.pdf.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Role-based security unleashed

Every .NET developer should (at least) have heard about role-based security. In this fourth episode of my "Personal Security Push" I'll talk about what role-based security is all about, how it works and how to empower it in your applications.

What is it?

Roles should build the bridge between the security built in in your code and the physical company structure (think of HR). It tells the code who can perform what action. In real life, your organization likely has various "roles", such as management, consultants, clerks, etc. These people all have different rights and therefore they need different access rules when performing actions in your application. The .NET Framework supports this by means of "role-based security", in which people are associated to their role. and security is applied based on that role. Typically you'll find roles useful to enforce business rules.

About authentication and authorization

In order to use an application, a user needs to do (either implicitly or explicitly) several things to get started. The first action is typically authentication. Authentication is a mechanism for the user to prove that he/she is really who he/she pretends to be (think of passwords, smartcards, fingerprints, eyescans, RFID identification, etc). In order to make this possible, the user and the system need to share a secret in order to be able to validate the user. When authentication succeeds, the system can examine the users database (whatever format it has, Active Directory, SAM, SQL Server, etc) possibly in combination with other repositories (AD/AM, AzMan, SQL Server, etc) to determine the roles for the user. As an example, Windows authentication uses the SAM or Active Directory to associate the groups with a user on logon (combined with privileges this results in the user token that can be queried via the whoami command). On the authentication phase has completed, authorization comes into play throughout the lifetime of the user's session, to determine whether the user has the appropriate rights (based on the user's identity and/or the roles of the user) to perform certain actions (e.g. access the filesystem, make changes to a database, or on a higher level, to perform certain business actions).

IPrincipal and IIdentity

The .NET Framework supports role-based security via the System.Security namespace in general. More specifically, there are two protagonists in the System.Security.Principal namespace that are crucial in the whole story:

  • System.Security.Principal.IPrincipal: once the user has been authenticated, a principal for the user is created, which contains the user identity (IIdentity in property Identity) and the roles (method IsInRole) that the user belongs to; depending on the authentication type, a certain implementation of this interface is used (e.g. WindowsPrincipal for Windows authentication, GenericPrincipal for custom authentication)
  • System.Security.Principal.IIdentity: the principal also contains information about the user himself/herself, i.e. the user's name and flags about the authentication type and a boolean indicating whether the user was authenticated or not (to detect anonymous users in an application, see Episode 3 on null sessions)

If it helps you, you can take a look at the principal as it were the managed equivalent of a user token, but it contains less information.

Assign the roles to a user

When using Windows authentication, the roles assignment for a user is performed automatically, based on the Windows groups the user belongs to. When accessing the WindowsPrincipal object you can query the roles of the users via the IsInRole method. When using forms authentication, you can use the GenericPrincipal object to represent the user:

FormsIdentity id = ...; //retrieve the identity in some way, e.g. by using FormsAuthentication.Decrypt on the authentication cookie
GenericPrincipal gp = new GenericPrincipal(id, roles); //roles is a string array with the roles
Context.User = gp;

Typically, you'll execute this kind of code after authentication or on Application_AuthenticateRequest event handler in global.asax. As complete example can be found on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT04.asp.

Use the roles in ASP.NET

Once the roles are present, you can use these roles to make decisions about the user rights. In ASP.NET as possible way to do this is by using the web.config file:

<authorization>
   <allow roles="role1" />
   <allow roles="role2" />
   <deny users="*" />
</authorization>

Combined with the location tag, you can grant only specific roles access to certain parts of the website:

<location path="/admin">
   <authorization>
      <allow roles="admin" />
      <deny users="*" />
   </authorization>
</location>

However, this is only the tip of the iceberg. In any kind of application, you can use the role-based security on the code level as well.

Declarative Security versus Imperative Security

Both on the class level and the member level (method, property, delegates, etc) you can apply declarative security. Declarative security is attribute-based (defined in System.Security.Permissions) and fairly straightforward:

[PrincipalPermission(SecurityAction.Demand, Role="SomeRole")]
public class MyClass
//...

or on the member level:

public class SomeClass
{
   //...
   [PrincipalPermission(SecurityAction.Demand, Role="SomeRole")]
   public void SomeMethod()
   //...

For Windows authentication, you'll use an attribute like this:

[PrincipalPermission(SecurityAction.Demand, Role=@"MYDOMAIN\TheGroup")]

Applying this attribute performs checking at runtime and if the current user's principal does not comply to the requirements in the attribute declaration, a SecurityException will be thrown.

An altnerative is imperative security. Using this mechanism, you write code to check the user's roles and take the right action based on the result. In fact there are two kinds of checks that can be performed at runtime. The first one is to "demand" security, just like we've done with declarative security. This will throw a SecurityException if the Demand call does not succeed. Another one is checking the role in a more flexible way using the IsInRole method. Let's show:

//Pure imperative security
new PrincipalPermission(null, "SomeRole").Demand();

//Manual role membership check
WindowsPrincipal wp = ...; //retrieve it principal in some way, in ASP.NET by using HttpContext.Current.User for example
if (wp.IsInRole("SomeRole"))
   //do it
else
   //throw an exception or take another action to tell the user that he/she is not allowed to perform this action

What mechanism to use?

Declarative security has the following (dis)advantages:

  • Can be attached on the class level so that it applies to all members of the class. Imperative security is less flexible on this point.
  • A security demand implemented through an attribute is executed before all the other code in the method, thus the code in the method has no chance to execute if the security demand fails. With imperative security, you have to do the work yourself and make sure it's right.
  • You can query the security demands when doing deployment by using tools like permview.exe:

    permview.exe /decl MyApp.exe

    Microsoft (R) .NET Framework Permission Request Viewer.  Version 1.1.4322.573
    Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

    Class Test Demand permission set:
    <PermissionSet class="System.Security.PermissionSet" version="1"/>

    Class Test NonCasDemand permission set:
    <PermissionSet class="System.Security.PermissionSet" version="1">
       <Permission class="System.Security.Permissions.PrincipalPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1">
          <Identity Authenticated="true" Role="test"/>
       </Permission>
    </PermissionSet>

    Method Test::Do() Demand permission set:
    <PermissionSet class="System.Security.PermissionSet" version="1"/>

    Method Test::Do() NonCasDemand permission set:
    <PermissionSet class="System.Security.PermissionSet" version="1">
       <Permission class="System.Security.Permissions.PrincipalPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1">
          <Identity Authenticated="true" Role="test"/>
       </Permission>
    </PermissionSet>

    In IL (using ildasm.exe), you'll find the security permissionset demands in the beforefieldinit section of the class (or if applied on member level on top of the IL code):

    .class private auto ansi beforefieldinit Test
           extends [mscorlib]System.Object
    {
      .permissionset demand = (3C 00 50 00 65 00 72 00 6D 00 69 00 73 00 73 00   // <.P.e.r.m.i.s.s.
                               ...
      .permissionset noncasdemand = (3C 00 50 00 65 00 72 00 6D 00 69 00 73 00 73 00   // <.P.e.r.m.i.s.s.
                                     ...

    .method private hidebysig static void  Do(int32 a,
                                              int32 b) cil managed
    {
      .permissionset demand = (3C 00 50 00 65 00 72 00 6D 00 69 00 73 00 73 00   // <.P.e.r.m.i.s.s.
                               ...
      .permissionset noncasdemand = (3C 00 50 00 65 00 72 00 6D 00 69 00 73 00 73 00   // <.P.e.r.m.i.s.s.
                                     ...
  • Performance is better than with imperative security because it's evaluated only once when loading. This kind of optimization cannot be applied when the code is embedded inside your own code blocks.
  • One of the drawbacks is that the security is embedded in the assembly and not configurable (which can also be an advantage). Be sure to look at the pitfalls section further in this post, since this can be a showstopper for declarative security.

Imperative security (dis)advantages:

  • Based on variables (see pitfalls for more info on why this is great), can be configured using any mechanism you want to support.
  • Your code is in charge of security, by means of condiational logic etc.
  • Generally spoken, more flexible but less general and negative performance impacts.

More about System.Security.Permissions

I'll cover other attributes in this namespace in a later post. There are over 20 permission types in this namespace that can be used throughout your code to implement a real tight security in depth strategy. Check out next episodes on CAS (code access security) for more information about this.

Pitfalls

Be careful when using roles such as BUILTIN\Administrators. In localized versions of Windows, this name can be different (e.g. BUILTIN\Administradores or BUILTIN\Administrateurs). Make this configurable!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Everyone = "including the bad guys"

Everyone should know the Everyone group in Windows. There's a problem however related to this group (otherwise I won't blog about it). Read on...

Anonymous users

Applications exposed to the entire globe typically need to be open for everyone without prior authentication. Anyone can connect to the application to find out information about certain things, to perform certain actions, etc. The internet is the number one example. Okay, that's great, but how can we control what anonymous unauthenticated users can do and what they can't do? As always, the answer should have to do with user rights, thus with ACLs. Great answer, isn't it? Not at all, how can we grant certain rights to an unknown user or how can we impersonate as a tokenless client? The solution is pretty simple however, there is a user called ANONYMOUS TOKEN (SID S-1-5-7). When an anymous user connects to the system, a special kind of session is created, called a null session. The anonymous user has very low privileges but it includes the Everyone group in its token. This explanation should be enough to understand the problem. For developers, when you need to impersonate as an anonymous user, you can use the Win32 ImpersonateAnonymousToken function but after reading this post, you might be thinking about running anonymous users with a fixed identity that you can control (which would make sense for sure).

What's in a name?

The word "Everyone" just tells us everything we need to know. It's really everyone, including anonymous users. Luckily, there's another group called Authenticated Users, which contains everyone but the ANONYMOUS LOGON. That is, the people we know since they have authenticated on the system. When ACLing, use Authenticated Users instead of Everyone.

Secure by default

Windows XP and Windows Server 2003 give an answer to these problems however by means of a local security policy called "Network access: Let Everyone permissions apply to anonymous users". When disabled (the default), this removes the Everyone group SID from the token of a null session, therefore denying access to resources available for Everyone. You should ook at this policy as a redefinition of the word Everyone. By default it's disabled and that's great. So, why bother about this at all. The answer is that this is still configurable, and when enabling it, your network might be open for attack. Authenticated Users still is a must to avoid this kind of problems.

Another great thing is that the LANManServer service used by Windows filesharing has some registry settings to control the behavior of null sessions. NullSessionShares and NullSessionsPipes tell the service to deny access to these resources by the anonymous user. By default, the parameters are configured to deny null sessions.

IIS = different

IIS does not use null sessions for anonymous access however. Instead, IIS impersonates anonymous users as the IUSR_%COMPUTERNAME% account, which is in fact not a bad idea at all, since it requires you to grant this account access explicitly to the files you want to expose to the web in an anonymous way. Nevertheless, IIS is a complex thing, which I'll be blogging about later when talking about application pools, ASP.NET usage, impersonation, and more.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Debugging is a privilege (sometimes)

Still a bunch of people run as Administrator (see first episode for countermeasures) because of one reason: "I need to debug applications". However, this argument doesn't make sense at all. Let's explain why.

What do we want to debug?

You can debug two types of applications in fact:

  • Processes that were started by yourself.
  • Processes that run in another logon session such as services started by the SCM or worker processes as the ASP.NET aspnet_wp.exe processes.

Depending on what we want to debug, we have different requirements.

Processes that were started by yourself

No tricks involved for this one. You launch the process, you own it. Period. Since you can do whatever you want with things you own (discard it, keep it alive, tease it, etc; just look at daily life samples of what you can do with what you own), you can debug it too. So, you don't need anything special to debug this type of processes (typically done when pressing F5 in Visual Studio).

Processes that run in another logon session

This is a more tricky one. In order to be able to do this, you need to be granted the SeDebugPrivilege privilege. What this does is that it allows you to obtain a handle to any process on the machine (thus also the processes that you don't own) so that you're capable to debug these processes. By default only Administrators have this privilege. Therefore, when you need to debug another process (i.e. attach to a Service or attach to an IIS worker process or an ASP.NET worker process) you need to be in the (to be scared about) Administrators group or you need to have the privilege enabled for your account too (refer to the local security policies - secpol.msc, Local Policies, User Rights Assignment -  to enable this "Debug programs" privilege). There are other ways to get it to work as well: runas (see Episode 1) as Administrator when running Visual Studio .NET or configure services or worker processes to run with the same account as the one you're using to debug (however, this will require the "Log on as a service" privilege on your account, which is in my opinion a showstopper for this approach). However, this privilege's use should be mimized as much as possible since it can affect any process running on the box (e.g. running WinDbg as an Administrator, try to attach to WinLogon.exe and then to stop/detach the debugger from it; it will BSoD your system!). Notice that the system is secure by default, that is nobody except the Administrators group has this right and nobody needs the right (except when you're developing Windows Services or ASP.NET apps). The latter one (ASP.NET apps) won't require this in the future, since VS2005 will rely on a built-in web server (based on Cassini) that runs as the local user, thus you're the owner of it.

Visual Studio debugging

Don't get tricked by the "Debugger Users" group. This group is does not on the OS level, it just tells Visual Studio that you're eligible to run the debugger tools of Visual Studio. Thus, when you're using another debugger like WinDbg (great one btw, will be blogging about it some time), the Debugger Users groups makes no sense at all.

More information

"Developing Software in Visual Studio .NET with Non-Administrative Privileges", the title tells it all. Check out this great article: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/tchdevelopingsoftwareinvisualstudionetwithnon-administrativeprivileges.asp.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Secondary logon, runas.exe, "Run as..." or CreateProcessWithLogonW - you should know at least one of these

It doesn't matter what you're doing on your machine, always run under the context of a low privileged account. Thus, the user "Administrator" and the group "Administrators" are evil things for day-to-day usage, just as "Power Users" are. Instead, run as a simple user (member of the Users group). That sounds great, but what about development-related things that need elevated privileges (see a further episode about "Debugging is a privilege") or installation-related tasks? The answer is the "Secondary logon service". An overview...

What is it?

The Secondary Logon service (seclogon) is a service on Windows NT based systems (XP, 2003 especially) that allows users to run a certain application in the context of another account. Or, as the service description in the SCM MMC (services.msc) tells us: "Enables starting processes under alternate credentials.". This is useful in quite some scenarios. To elevate your privileges by running a process under a higher privileged identity, or to strip down your rights and privileges to test whether an app runs under lower credentials or to check ACLs on system objects under the context of that particular user. I use it in both situations. Also, to test for installation compliance, you can use this service (a good installer should run with "Power User" - these guys have write access to the Program Files folder - rights or less).

Where is it?

In the MMC of the Service Control Manager (SCM) which is available through Administrative Tools, Services or by running services.msc, locate the Secondary Logon service. It should be enabled by default and has the name "seclogon". Thus, to start/stop/query it you can use things such as net start seclogon, net stop seclogon, sc seclogon. Although the service runs as SYSTEM, it's capable of creating processes with another security context and make these available on the user's session (WinSta0 or a Terminal Services session).

How to use it?

  1. Windows Explorer
    Locate an executable or a shortcut or an .msc file, right click it, and choose "Run as". The displayed dialog allows you to specify another user (second option) to be used when running the process. If authentication succeeds, you'll start the executable in a process "living in a sandbox" under the specified credentials (that is, with the token of that user). When creating a shortcut you can specify to use runas as well (Advanced..., Run with different credentials).
  2. Command-line
    My favorite one. Go to the command prompt and use the runas.exe command to do the same as mentioned above. I'll give an overview of runas further in this post.
  3. Programmatically
    Usable for testing or in a real application to launch a trusted subprocess or a lower privileged subprocess. The Win32 API function is called CreateProcessWithLogonW and more info can be found on MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocesswithlogonw.asp). An alternative is CreateProcessAsUser but this one requires the user of LogonUser (therefore loading the user's profile) first to authenticate the user. Another reason not to use this in production is the need to store the password somewhere, which can be a hard task to keep it secure (DPAPI needs to be used in order to keep it as secure as possible). Of course, the better alternative is to ask the user to specify the password and not to store it.

About runas.exe

The basic usage is straightforward. To run application "app.exe" under user "someuser", use this command:

runas /user:someuser app.exe

The system will prompt for the user's password (you can pipe in the password using a tool called Sanur) and if authentication succeeds, the process will be started with the specified user's rights and privileges. Simple hey? However, there's a lot more under the hood of runas.exe. An overview:

  • /noprofile: By default, the system will load the user's profile (which is residing in the "Documents And Settings\SomeUser" folder), which means that the HKCU registry hive will be mounted to the user's registry hive living in the ntuser.dat file. This can take some time. To run an application that doesn't make use of the profile (i.e. doesn't use the user's profile folders such as Favorites, Application Data, etc directly; doesn't use the HKCU registry hive; doesn't use "Isolated Storage") you can use this switch to disable the profile loading when performing the secondary logon. Applications like winword.exe that use the user's profile will likely fail when using this switch.
  • /profile: The opposite of /noprofile. No, tell me it isn't true? Yes, it is :-)
  • /env: The current environment is used when launching the application with different credentials.
  • /netonly: Use this one to use the specified credentials not to run the process but to access network resources with. The command will run under the context of the current user instead. This is useful when developing and checking ACLs etc.
  • /savedcreds: First of all, the /? help and the Windows Help are inconsistent for what the syntax is concerned. It seems to be the case that /savedcred, /savedcreds, /savecred and /savecreds all work (as well as /s, /sa, etc). Now, why did I strikethrough this parameter? Well, don't use it. It's insecure. What is does it pretty simple: it allows to save the entered credentials so that you don't have to type them again later on. The worst point is that these credentials are cached for the entire lifespan of the user's session, so any application that can run a process can run the runas.exe command with the parameter /savedcreds. If the password was entered earlier using runas with this switch, the new process can do all it wants without asking the user for the password (e.g. an ActiveX control, any downloaded - trusted - application, etc). The moral of the story: don't use this parameter.
  • /smartcard: Credentials are read from the smartcard instead of asking the user's password.
  • For more info, refer to http://www.microsoft.com/resources/documentation/WindowsServ/2003/standard/proddocs/en-us/Default.asp?url=/resources/documentation/WindowsServ/2003/standard/proddocs/en-us/runas.asp.

Note that the runas command help (runas /?) is incomplete (there are two other switches called /showtrustlevels and /trustlevel that can be used to query and specify the trustlevel to run the app with) and that the Windows Help (checked on Windows Server 2003) for runas is inconsistent with the real use (e.g. /savedcred versus /savecred switch, which are both valid).

Using Windows Explorer

In Windows Explorer, the use of the secondary logon service is really simple. It's available through the context menu when selecting a file (.msc, .exe, .lnk). In the dialog displayed there are two options:

  • Current user (DOMAIN\User): This option does exactly the same as simply starting the app. So, why does it make sense? That's because of the second checkbox option: "Run this program with restricted access" (W2K3 SP1 RC1) or "Protect my computer and data from unauthorized program activity" (XP). Hmm, weird. Two different texts on W2K3 versus XP. Also the explanation is different:
    • XP: This option can prevent computer viruses from harming your computer or personal data, but selecting it might cause the program to function improperly.
    • W2K3: This option helps prevent programs from using administrator privileges to harm your computer. If you select this option, and the program relies on these privileges, it might behave improperly.
    • So, what's up?
      • The W2K3 description is more technical, so that makes much more sense than the "house, garden and kitchen XP user" message. Runing as administrator (so you need to log off now and log on as an administrator to see the effect - I assume you're not running as Administrator now), create a shortcut to cmd.exe. Run it with "Run as..." and enable the checkbox. In the command-prompt, take a look at whoami /priv which shows the privileges of the user. You'll see that only the SeChangeNotifyPrivilege (which is known as "Bypass Traverse Checking", what's in a name? :-)) is present (which btw is normal since this is used multiple times when performing file I/O for example, and is really meant to be enabled). Runas the shortcut again, but now uncheck the checkbox and you should have about 22 (in my case, since I'm running on a domain and the privilege "Add a user to the domain" aka SeEnableDelegationPrivilege is there as well, I have 22 privileges; the number on your machine might be different).
      • Do the same (runas with resp without checking the checkbox) and take a look at the output of whoami /groups. At first sight, you should see no difference (there's quite a lot of output). However, with the checkbox disabled there should be this:

        BUILTIN\Administrators                     Alias            S-1-5-32-544                        Mandatory group, Enabled by default, Enabled group, Group owner

        whileas with the checkbox enabled you should see

        BUILTIN\Administrators                     Alias            S-1-5-32-544                        Mandatory group, Group owner, Group used for deny only

        Thus, the token of the caller is duplicated but the BUILTIN\Administrators group is locked down for the user and is only used by the system for deny purposes which results in higher security. In the restricted command prompt, try to navigate to %HOMEPATH% (cd %HOMEPATH%) and you should see a nice and cute "Access is denied." message. That's great!
      • To wrap up this discussion, the checkbox is all about locking down the usage of the current account when running another process (notice that for example the SeImpersonatePrivilige is also disabled, therefore causing the failure of apps which use impersonation). Use it to test your application when locked down without Administrator rights and privileges. However, when running under a low privileged account as a best practice this charmy option should be of little value to you when doing this kind of tests. Nevertheless, some day it can become useful to you so you better know how it works and what it does. To summarize: the option allows to demote yourself to a normal user while you're still running with the same profile.
  • The following user: Exactly what you want to use, as described earlier in the runas.exe exploration. It's exactly the same as the runas.exe command with no extra switches.

More tricks

There are also other tips and tricks to run with elevated privileges when needed:

  • Connect to your own machine (or another machine on which you can perform the tasks) using Terminal Services (mstsc) and log in with another account with higher privileges. This only works only on Windows 2000 Server or Windows Server 2003 since XP does not allow multiple users to be logged on interactively on the same machine at a time. It's a possibility but it has some drawbacks: memory requirement (secondary profile loaded with the default shell), difficult switching between the remote session and the local one (I'm avoiding the use of a mouse as much as possible, so try to ALT-TAB in a TS session and to break out the TS session to ALT-TAB to a local session's window, you'll find that this is a difficult riddle) and last but not least, it's easy to forget that you're running remotely with higher privileges (especially when running full screen).
  • Use the scheduling command at.exe to plan the command prompt (cmd.exe) at some time in the future (e.g. 1 minute later). Since the Task Scheduler is running as SYSTEM, you'll get a child process of the svchost process with the security token/context of SYSTEM, the highest privileged user on the system. Also a possibility but I don't like it much too. There should be a reason why this service is disabled by default on my W2K3 SP1 RC1 box (guess what?). If you want to use it (please don't) you should enable the Task Scheduler service (service name "Scheduler") before you can use at.exe. Note that there is a much more safe variant of at.exe, which is called schtasks and available from Windows XP on and allows you to specify the user account to use to run the task (using impersonation kind of techniques behind the scenes when creating the child process). When enabling the "Scheduler" service, put it on Manual instead of Automatically.
  • If you have others, I'd like to hear them from you.

Happy Christmas and "runassing"...

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

It's the holiday season of Christmas and New Year, so first let me wish everyone who reads my blog (and the others too of course) a great 2005, the year of SQL Server 2005, VIsual Studio 2005, .NET Framework v2.0, Windows Server 2003 SP1, ASP.NET v2.0, Longhorn beta, BizTalk 2006 beta, WUS, ... Do I need to continue to convince you that 2005 will be a great year? Check out Chris Anderson's (aka Mr Avalon) and Don Box's (aka Mr Indigo) MSDNTV episode on http://msdn.microsoft.com/msdntv as well, covering Avalon and XAML. In 2005, you'll see me blogging about these topics (WinFX, Avalon, Indigo, XAML) more and more.

However, for the upcoming weeks I'm planning a little PSP (Personal Security Push) tips, that I learned an evangelized this year to people out there in the community and which I'd like to share with the blogosphere. There's a new blog category on my site now: "Security" which will contain all this stuff.

Cheers,
Bart

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Going to bed now after a crazy night full of WinFX, XAML and Avalon using the CTP of November 2004 running on both Windows Server 2003 and Windows XP SP2. It's oh so cool that I couldn't even stop this night. Starting with plain vanilla XAML (eXtensible Application Markup Language) for UI definition in Avalon over to custom XAML on my own classes. All this with .NET Framework v2.0 beta (new number to remember: v2.0.40607) and Visual Studio 2005 beta 1. Unfortunately, the VS2005 December 2004 CTP seems to be incompatible with the Avalon CTP (version number of the .NET Framework with the new VS CTP is v2.0.41202), so I had to install, remove and install again but luckily the system wasn't screwed by this (everything still runs fine). Seems that the MSIs are already of an excellent quality.

Other problems you want to avoid:

  • Don't run with a theme on Windows Server 2003, except for the Blue one (the silver and green ones are not supported in this Avalon CTP). I was running the silver theme, which results in a nice black box being displayed when you try to open a XAML file via IE or after compilation to BAML etc in VS2005 (pretty nice, zammel and bammel).
  • Don't try audio or video with the Unable to find an entry point named 'MILFactoryCreateMediaPlayer' in DLL
    'milcore.dll'.
    ")
  • The screen may flicker a bit when launching the first XAML.
  • A new service, "FontCacheService.exe" appears (SCM name "FontCacheDownLevel") which is residing in the GAC.

I'm now running:

  • Windows Server 2003 SP1 RC1 + Visual Studio 2005 beta 1 + SQL 2005 beta 2 + Avalon CTP 2004
    (Note: I managed to install the MSN Desktop Search Toolbar on W2K3 as well as MSN 7 to stay hip-n-cool :-)).
  • VPC with Windows XP SP1 + Avalon CTP 2004 (no flashy editors over there, just the one and only "notepad")
    (I had to struggle with my base image of XP SP2 since I forgot the password :-(. Another pain in the *** during my exploration tonight)
  • VPC with Longhorn 4074 (WinHEC release) which has an older Avalon build but with media support and my cool "rotating Nicole & Hugo" XAML demo :-).
    (VPC + LH4074 = slooooooow but it works after all)

If I run another night XAML session, I'll let you know through my blog and I'll post some samples of both Avalon and Indigo with and without XAML. Good night.

PS: Don't forget to watch the Holiday Episode II of MSDN TV with Don Box and Chris Anderson on Avalon Layout Basics.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

I've been asked for this recently and a little search on the internet resulted in this link: http://www.microsoft.com/windowsserver2003/evaluation/overview/roadmap.mspx. In the first half of 2005 expect to see Windows Server 2003 SP1, x64 and WUS. Later on (second half of 2005) we can expect the R2 release which will incorporate existing updates together with "feature packs" that are available as stand-alone downloads right now. The next major release of the Windows Server OS is planned for 2007 (Longhorn Server) covering things such as IIS 7, Indigo, improved role-based server configuration and new hardware support.

There's a nice section with links to Feature Packs on the page too.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

More Posts Next page »