Distilled: The .NET Developer's Guide to Windows Security
Great Book
Keith Brown has produced a watershed book: The .NET Developer's Guide to Windows Security. Don't be fooled, this book is not just for .NET crypto-heads! Anyone who has an interest in any part of modern Windows Security (read: Windows 2000 and later) needs to read parts of this book. It is one of the clearest introduction to Windows security concepts I have seen.
There's just one problem...
As I've mentioned before, our company is working on the migration of nearly our entire application portfolio to a new architecture that uses (for the wintel stuff) Windows Server 2003 and XP SP2. While a daunting undertaking, it is also an unprecedented opportunity to begin to rationalize the applications and begin to apply coding standards. But where do you get the standards?
I've always been an advocate of starting with standard standards and going from there. That's why I asked for known security standards. However most security standards cover configuration rather than coding standards.
So why not use an authoritative book? The architect (me) supplies a bullet point and the book (author) supplies the chapter and verse, so to speak. Only problem is coming up with a succinct list of guidelines. Some authors have already done that sort of thing to great effect. (Don't forget this one, too.) Keith used a more informative approach, which I think is fine since security issues are hard enough to grasp.
Taxonomy of a Guideline
So I used more than a month's worth of train time to distill Keith's book into a list of guidelines I'll share shortly. My next step was to move the rules into a spreadsheet to categorize them along with the Corporate Security staff.

If all goes well this effort can serve as the nucleus for a clearly defined database of guidelines, best practices and standards from which we can build check lists, training courses and conformance reports, etc, for a wide range of guidance categories. Wish me luck! Without further ado here's The .NET Developer's Guide to Windows Security Distilled.
The .NET Developer's Guide to Windows Security Distilled
- Learn how to protect against malicious user input. (Item 1)
- Include detection and reaction countermeasures in your application design in addition to protection. (Item 2)
- Develop a threat model to analyze which security risks are worth mitigating. (Item 3)
- Quantify each vulnerability by potential damage and likelihood. (Item 3)
- Design and configure daemons to run with the least privileges it needs to perform it's job. (Item 4)
- Avoid running any daemon as SYSTEM. (Item 4, Item 28)
- Design desktop applications to follow the Windows Logo guidelines on resource access (files, registry, etc). (Item 4)
- Open a file or other secured resource with the permissions needed for the given session. (Item 4)
- Use the least privileged form of state management necessary for an application. For .NET desktop applications, prefer isolated storage (Item 4, Item 9).
- Close a file or other secured resource as soon as it is no longer needed. For .NET applications utilize the using C# language construct, if applicable (also available in Visual Basic 2005). (Item 4)
- Login with least privilege whenever you log in to your computer. (Item 4)
- Design and configure applications with redundant counter measures (aka "defense in depth"). (Item 5)
- Ensure that server-to-server communication is protected behind a firewall. (Item 5)
- Design your application so that failure will not create a vulnerability. (Item 5)
- Consider multifactor authentication of clients. (Item 6)
- Prefer mutual authentication (i.e. authentication of servers). (Item 6)
- Guard against luring attacks when setting up a sandbox environment. (Item 7)
- Develop applications as a nonprivileged user. (Item 8)
- Have two logins, a nonprivileged user for your interactive user and an administrative user for when you need it. (Item 9)
- On Windows Server 2003 use Terminal Services for your administrative user. (Item 9)
- On Windows XP use the Secondary Login Service for your administrative user. (Item 9)
- On Windows XP run iexplore.exe using secondary login service, and open the control panel to access administrative GUIs. (Item 9)
- On Windows XP change the iexplore.exe toolbar bitmap and title bar to distinguish when iexplore.exe is being run under the administrator user. (Item 9)
- On Windows XP create a batch file to create a command window for the administrative user and network credentials for your interactive user. (Item 9)
- Add nonprivileged interactive user to the Debugger Users and VS Developers local groups. (Item 9)
- Follow the Windows Logo requirements for data file placement including the use of the special folders ProgramFiles, CommonApplicationData, ApplicationData, LocalApplicationData, and Personal. .NET applications use the Environment.GetFolderPath method and the Environment.SpecialFolder enumeration. The Windows Logo requirements further specify placing data files in a subfolder named [company name]\[product name]\[version]. (Item 9)
- For Windows Forms applications use the Application properties, UserAppDataPath, LocalUserAppDataPath, and CommonAppDataPath. The assembly attributes AssemblyCompanyAttribute, AssemblyProductAttribute, and AssemblyVersion attribute must be assigned correctly for this to work. (Item 9)
- For .NET applications use Isolated Storage for per user settings on Windows Forms Applications. (Item 9)
- Do not create per-user settings during installation, rather on first execution of an application. (Item 9)
- Test your application by installing under one user and executing under another. (Item 9)
- Prefer to install applications in this order: Click-Once (for .NET applications), Isolated Applications (xcopy), Power Users group privileges, Administrators group (for Windows Services, Installation in the GAC, etc. (Item 9)
- Enable auditing of logon and access failures for all lab and production machines. (Item 10)
- Use inherited ACLs when adding auditing entries. (Item 11)
- In code, refer to well know principals by SID rather than by name. (Item 13)
- Server documentation should define exactly what privileges, roles, and permissions it needs. (Item 14)
- In .NET applications, prefer using WindowsIdentity as the IIdentity implementation even if you create your own IPrinicipal implementation for custom authorization. (Item 15)
- Prefer to use application defined roles for authorization decisions in your code rather than Windows groups, as the latter include the domain name which is implementation specific. (Item 15)
- In .NET applications, Include the current windows user name in any application logging by using WindowsIdentity.GetCurrent. (Item 16)
- Have a process on the machine providing a secured resource provide Windows token access checks for that resource. (Item 16)
- Avoid executing through the command line interpreter programs that take user input. In C++ use CreateProcess. In .NET use System.Diagnostics.Process.Start. (Item 17)
- Avoid displaying dialog boxes from libraries that may be used by daemons. (Item 18)
- Do filter carefully data stored under the All Users profile, such as Enviroment.SpecialFolder.CommonApplicationData in .NET. (Item 19)
- Do not use User Profile files, registry entries, or resources from daemons or libraries likely to be used by daemons. Use machine-level functionality where appropriate, for example, for certificate stores and DPAPI. (Item 19)
- When running a server under a custom account, use at least a 20 character randomly generated password. (Item 20, Item 27, Item 28)
- Use a password manager program to store long passwords. (Item 20)
- Enable and disable a privilege immediately before and after you use it. This is less of an issue with .NET code. (Item 21)
- In .NET, follow specific guidelines for creating a WindowsPrincipal from a user token. The built-in behavior is in error. (Item 25)
- Never hardcode passwords into your programs. (Item 26)
- Prefer Windows Server 2003 when you need to get a user token, since you do not need a password to get a user token. (Item 26)
- Prefer Network Login when using LogonUser in Windows XP to get a user token. (Item 26)
- Use specific guidelines in Windows 2000 to get a user token without high-privileges using SSPI. (Item 26)
- Do not grant a daemon user account the “Log on locally” right. (Item 27)
- Prefer login accounts for daemons in this order: Local Service, Network Service, custom account. (Item 28)
- Change custom daemon user account passwords periodically as you would interactive user passwords. (Item 28)
- If using a daemon user account from IIS6, include the user in the IIS_WPG group. Be sure to restart the application pool after doing so. (Item 28)
- Consider factoring a process into two processes, one for functions that require high-privilege and one for functions that do not. To communicate between the two processes use a secure IPC channel, such as COM, and use an authorization scheme so that only the low-privileged server has access to the high-privileged process. (Item 28, Item 22)
- Never place a daemon in the WinSta0 windows station, such as running a Windows Service with the “Allow service to interact with the desktop” privilege. Factor the user interface to run as a separate process under the user’s control. (Item 29)
- Close kernel handles (secured resources) aggressively when impersonating. (Item 31, Item 4)
- Call WindowsImpersonationContext.Undo in a finally block when impersonating in .NET applications. (Item 32)
- Limit the use of impersonation. (Item 32)
- Use specific guidelines to temporarily revert to self when impersonating in .NET applications. (Item 32)
- Avoid placing PrincipalPermissionAttribute on a class that has a static constructor in .NET applications. (Item 34)
- Consider that multiple PrincipalPermissionAttribute attributes implies a logical-or behavior in .NET Applictions. (Item 34)
- Disable the Guest account. (Item 36)
- Use ANONYMOUS LOGON user SID rather than the Everyone group if you must grant access to anonymous users. (Item 37)
- Use specific instructions to get a null session token. In .NET applications, avoid using WindowsIdentity.GetAnonymous, since the implementation is incorrect. (Item 37)
- Avoid granting users the “Take Ownership” permission by giving them Full Control. (Item 41)
- Use deny access control entries (ACEs) to limit a subset of a larger set of users. (Item 42)
- Consider testing the result of ACLs that include deny ACEs. (Item 43)
- Avoid the low level Win32 DACL functions as the do not auto-propagate inherited ACEs. For .NET applications use the .NET 2.0 classes without concern. (Item 45)
- Avoid using cacls.exe as it uses the low level Win32 DACL functions and does not auto-propagate inherited ACEs. (Item 45)
- Consider blocking inheritance at any node in a hierarchy where ownership changes (e.g.: user profiles). (Item 45)
- Use inheritance blocking sparingly. (Item 45)
- Consider recursively taking ownership of objects in a node before forcing inherited ACLs. (Item 45)
- For an installation package, prefer storing an ACL created by an administrator graphically and applying it later to creating the ACL programmatically at the point of use. (Item 48)
- Consider using Authorization Manager for role based security. (Item 49)
- Use PRIVACY COM authentication level. Only, when you need to look at the payload during debugging, use INTEGRITY. (Item 50)
- Avoid giving the Everyone group access to COM objects. Require at least Authenticated Users, even for callbacks, events, etc. (Item 50)
- When using COM impersonation, use only the IMPERSONATE or DELEGATE levels. (Item 51)
- Always initialize COM security. Settings include: (Item 52)
- Authentication level
- Impersonation level
- Access permissions
- Restrict the use of custom marshallers
- Enable cloaking
- Disable As Activator Activation
- Utilize the COM security features that separate local and remote Execute and Launch permissions in Windows XP SP2. Use the new local and remote Activation permission. (Item 52)
- For .NET applications, follow specific instructions to establish COM security settings. (Item 53)
- For COM+ library applications, leave the “Enable Authentication” setting checked. (Item 54)
- Use specific instructions for IIS6 to set COM security settings using the registry for ASP.NET applications on development machines. (Item 55)
- Use specific instructions to implement COM+ role-based security support in .NET applications. Needed attributes include: (Item 56)
- ApplicationAccessControlAttribute
- ComponentAccessControlAttribute
- SecureMethodAttribute
- SecurityRoleAttribute
- Run OLE automation servers as launching user. Other servers prefer as specific deamon account with minimal security privileges as a non-interactive user. (Item 57)
- Assign daemon accounts a service principle name (SPN) to avoid user-to-user authentication and to enable mutual authentication. (Item 59, Item 60)
- Consider splitting server functionality into two groups, low- privileged functions that can take advantage of performance advantages of not delegating, such as pooled connections, and high-privileged functions that can take advantage of the security advantages of delegation. (Item 62)
- For web services, consider passing along both client and second-tier server credentials to the third tier. (Item 62)
- Utilize the ability to specify services on specific machines that may receive delegated credentials (constrained delegation). (Item 62)
- Prefer using Protocol Transition features of Windows Server 2003 to storing client passwords. (Item 63)
- Utilize constrained delegation when using Protocol Transition in Windows Server 2003. (Item 63)
- Mark high-privileged accounts as “sensitive and cannot be delegated”. (Item 64, Item 62)
- Follow specific guidelines, when using NegotiateStream in .NET 2.0 applications: (Item 66)
- Use only TokenImpersonationLevel Impersonation or Delegation
- Client should specify a service principle name (SPN)
- Use SecurityLevel.EncryptAndSign for production machines
- Use SecurityLevel.Sign in debugging when you need to view the payload.
- For .NET 1.1 applications, use SSL or IPSEC to secure a .NET Remoting channel. (Item 67)
- Follow specific instructions to secure a .NET 2.0 remoting channel (Item 67)
- Server authenticationLevel should be IdentifyCallers or ImpersonateCallers
- Client impersonationLevel should be either Impersonate or Delegate
- Client should specify spn for server
- Set encryption to EncryptAndSign
- Follow specific guidelines when configuring IPSEC: (Item 69)
- Include only the ESP security method using 3DES with HMAC-SHA1 whenever possible
- Enable PFS
- Use integrated security where possible in applications that allow it such as SQL Server. (Item 70)
- Do not store sensitive files in a web server virtual directory. (Item 70)
- Consider protecting secrets using DPAPI. (Item 70)
- Use machine credentials, when using DPAPI from a daemon. (Item 70, Item 19)
- Use aspnet_setreg to store secrets in a web.config file. (Item 70)
- Never echo passwords. (Item 71)
- For GUI applications, use the password setting for text entry fields that accept passwords: (Item 71)
- TextMode=Password in ASP.NET
- PasswardChar in Windows Forms
- Never write a password to a password entry field from a data store; use a dummy character sequence such as spaces. (Item 71)
- Disable ENABLE_ECHO_INPUT to enter passwords for console applications. (Item 71)
- Use CredUIPromptForCredentials API to enter passwords for GUI applications. (Item 71)
- Use the CredUIOptions.DoNotPersist to disable option to store password in user’s DPAPI store. (Item 71)
- Use LockWorkStation API to show the Welcome screen (authentication timeout). (Item 72)