Establishing End to End Trust!

Valuable Intellisense & Modern Business Services
Home     Products & Services     Discussion & Solutions     Post Here     About Us     Useful Links     Site Map      
Hardware     Software     Question & Answers      
Defend Your Code with Top Ten Security Tips Every Developer Must Know


This article assumes you're familiar with C++, C#, and SQL

SUMMARY

There are many ways to get into trouble when it comes to security. You can trust all code that runs on your network, give any user access to important files, and never bother to check that code on your machine has not changed. You can run without virus protection software, not build security into your own code, and give too many privileges to too many accounts. You can even use a number of built-in functions carelessly enough to allow break-ins, and you can leave server ports open and unmonitored. Obviously, the list continues to grow. What are some of the really important issues, the biggest mistakes you should watch out for right now so that you don't compromise your data or your system? Security experts Michael Howard and Keith Brown present 10 tips to keep you out of hot water.

Security is a multidimensional issue. Security risks can come from anywhere. You could write bad error handling code or be too generous with permissions. You could forget what services are running on your server. You could accept all user input. And the list goes on. To give you a head start on protecting your machines, your network, and your code, here are 10 tips to follow for a safer network strategy.

1. Trust User Input at Your Own Peril

Even if you don't read the rest of this article, remember one thing, "don't trust user input." If you always assume that data is well formed and good, then your troubles are about to begin. Most security vulnerabilities revolve around the attacker providing malformed data to the server machine.

Trusting that input is well formed can lead to buffer overruns, cross-site scripting attacks, SQL injection attacks, and more.

Let's look at each of these potential attacks in more detail.

2. Protect Against Buffer Overruns

A buffer overrun occurs when the data provided by the attacker is bigger than what the application expects, and overflows into internal memory space. Buffer overruns are primarily a C/C++ issue. They're a menace, but generally easy to fix. We've seen only two buffer overruns which were not obvious and were hard to fix. The developer did not anticipate externally provided data that was larger than the internal buffer. The overflow causes corruption of other data structures in memory, and this corruption can often lead to the attacker running malicious code. There are also buffer underflows and buffer overruns caused by array indexing mistakes, but they are less common.

Take a look at the following C++ code snippet:

void DoSomething(char *cBuffSrc, DWORD cbBuffSrc) { char cBuffDest[32]; memcpy(cBuffDest,cBuffSrc,cbBuffSrc);}What's wrong with it? Actually, there's nothing wrong with this code if cBuffSrc and cbBuffSrc come from a trusted source, such as code that did not trust the data and so validated it to be well formed and of the correct size. However, if the data comes from an untrusted source and has not been validated, then the attacker (the untrusted source) could easily make cBuffSrc larger than cBuffDest, and also set cbBuffSrc to be larger than cBuffDest. When memcpy copies the data into cBuffDest, the return address from DoSomething is clobbered because cBuffDest is next to the return address on the function's stack frame, and the attacker makes the code perform malicious operations.

The way to fix this is to distrust user input and not to believe any data held in cBuffSrc and cbBuffSrc:

void DoSomething(char *cBuffSrc, DWORD cbBuffSrc) { const DWORD cbBuffDest = 32; char cBuffDest[cbBuffDest];#ifdef _DEBUG memset(cBuffDest, 0x33, cbBuffSrc);#endif memcpy(cBuffDest, cBuffSrc, min(cbBuffDest, cbBuffSrc));}This function exhibits three properties of a well-written function which mitigates buffer overruns. First, it requires the caller to provide the length of the buffer. Of course, you should not blindly trust this value! Next, in a debug build, the code will probe the buffer to check that it is indeed large enough to hold the source buffer, and if not, it will probably cause an access violation and throw the code into a debugger. It's surprising how many bugs you can find when doing this. Last, and most important, the call to memcpy is defensive; it copies no more data than the destination buffer can hold.

During the Windows® Security Push at Microsoft, they created a list of safe string handling functions for C programmers. You can check them out at Strsafe.h: Safer String Handling in C.

3. Prevent Cross-site Scripting

Cross-site scripting vulnerabilities are Web-specific issues and can compromise a client's data through a flaw in a single Web page. Imagine the following ASP.NET code fragment:

How many of you have seen code like this? You may be surprised to learn it's buggy! Normally, a user would access this code using a URL that looks like this:

http://explorationair.com/welcome.aspx?name=MichaelThe C# code assumes that the data is always well formed and contains nothing more than a name. Attackers, however, abuse this code and provide script and HTML as the name. If you typed the following URL

http://northwindtraders.com/welcome.aspx?name= you'd get a Web page that displays a dialog box, saying "hi!" "So what?" you say. Imagine that the attacker convinces a user to click on a link like this, but the querystring contains some really nasty script and HTML to get your cookie and post it to a site that the attacker owns; the attacker now has your private cookie information or worse.

There are two ways to avoid this. The first is not to trust the input and be strict about what comprises a user's name. For example, you could use regular expressions to check that the name contains only a common subset of characters and is not too big. The following C# code snippet shows the way that you can accomplish this:

Regex r = new Regex(@"^[\w]{1,40}$"); if (r.Match(strName).Success) { // Cool! The string is ok} else { // Not cool! Invalid string}This code uses a regular expression to verify that a string contains between 1 and 40 alphanumeric characters and nothing else. This is the only safe way to determine whether a value is correct.

You cannot squeak HTML or script through this regular expression! Don't use a regular expression to look for invalid characters and reject the request if such characters are found because there is always a case that will slip by you.

The second defense is to HTML-encode all input when it is used as output. This will reduce dangerous HTML tags to more secure escape characters. You can escape any strings that might be a problem in ASP.NET with HttpServerUtility.HtmlEncode, or in ASP with Server.HTMLEncode.

4. Don't Require sa Permissions

The last kind of input trust attack we want to discuss is SQL injection. Many developers write code that takes input and uses that input to build SQL queries to communicate with a back-end data store, such as Microsoft® SQL Server™ or Oracle.

Take a look at the following code snippet:

void DoQuery(string Id) { SqlConnection sql=new SqlConnection(@"data source=localhost;" + "user id=sa;password=password;"); sql.Open(); sqlstring= "SELECT hasshipped" + " FROM shipping WHERE id='" + Id + "'"; SqlCommand cmd = new SqlCommand(sqlstring,sql);•••This code is seriously flawed for three reasons. First, the connection is made from the Web Service to SQL Server as the system administrator account, sa. You'll see why this is bad, shortly. Second, notice the clever use of "password" as the password for the sa account!

However, the real cause for concern is the string concatenation that builds the SQL statement. If a user enters an ID of 1001, then you get the following SQL statement, which is perfectly valid and well formed.

SELECT hasshipped FROM shipping WHERE id = '1001'However, attackers are more creative than this. They would enter an ID of "'1001' DROP table shipping --", which would execute the following query:

SELECT hasshipped FROM shipping WHERE id = '1001' DROP table shipping -- ';This changes the way the query works. Not only does the code attempt to determine if something has shipped or not, it goes on to drop (delete) the shipping table! The -- operator is a comment operator in SQL and it makes it easier for an attacker to build a valid, yet dangerous, series of SQL statements!

At this point you're probably wondering how any user could delete a table in the SQL Server database. Surely only admins can do a task like that. You're right. But here you're connecting to the database as sa, and sa can do anything it wants to do on a SQL Server database. You should never connect as sa from any application to SQL Server; rather, you should either use Windows Integrated authentication, if appropriate, or connect as a predefined account with appropriately restricted rights.

Fixing the SQL injection issue is easy. Using SQL stored procedures and parameters, the following code shows how to build a query like this—and how to use a regular expression to make sure that the input is valid because our business dictates that a shipping ID can only be numeric and between four and ten digits in length:

Regex r = new Regex(@"^\d{4,10}$");if (!r.Match(Id).Success) throw new Exception("Invalid ID"); SqlConnection sqlConn= new SqlConnection(strConn);string str="sp_HasShipped";SqlCommand cmd = new SqlCommand(str,sqlConn);cmd.CommandType = CommandType.StoredProcedure;cmd.Parameters.Add("@ID",Id);Buffer overruns, cross-site scripting, and SQL injection attacks are all examples of trusting input. All these attacks can be mitigated by believing that all input is evil, until proven otherwise.

5. Watch that Crypto Code!

Now let's look at something near and dear to our hearts. It’s a fact that more than 30 percent of the security code we review contains security mistakes. Probably the most common mistake is homegrown encryption code, which is typically quite fragile and easy to break. Never create your own encryption code; you won't get it right. Don't think that just because you've created your own cryptographic algorithm people won't figure it out. Attackers have access to debuggers, and they have both the time and the knowledge to determine exactly how these systems work—and often break them in a matter of hours. Rather, you should use the CryptoAPI for Win32® applications, and the System.Security.Cryptography namespace has a wealth of well-written and well-tested cryptographic algorithms.

6. Reduce Your Attack Profile

If a feature is not required by 90 percent of clients, then it should not be installed by default. Internet Information Services (IIS) 6.0 follows this plan of installation, and you can read about it in Wayne Berry's article, "Innovations in Internet Information Services Let You Tightly Guard Secure Data and Server Processes," The idea behind this installation approach is that where services that you don't use are running, you don't pay attention to them and they can be exploited. If the feature is installed by default, then it should operate under the principle of least privilege. In other words, do not require the app to run with administrative rights if they are not required. Follow this advice as well.

7. Employ the Principle of Least Privilege

The operating system and the common language runtime (CLR) have a security policy for several reasons. Many people think that the main reason the security policy exists is to prevent users from intentionally doing bad things: accessing files they shouldn't be allowed to see, reconfiguring the network to suit their needs, and other dastardly deeds. While it's certainly true that insider attacks are common and need to be guarded against, there's another reason for keeping this security policy tight. The security policy is there to put walls around code so that intentional or (just as frequently) unintentional actions by users don't wreak havoc on the network. For instance, an attachment downloaded via e-mail and executed on Alice's machine is restricted to only accessing resources that Alice can access. If the attachment contains a Trojan horse, a good security policy will limit the damage it can do.

When you design, build, and deploy server applications, you cannot assume that every request will come from a legitimate user. If a bad guy manages to send you a malformed request that (heaven forbid) causes your code to behave badly, you want every possible wall around your application to limit the damage. Our point is that the reason your company has a security policy isn't just because it doesn't trust you or your code. It's also there to protect against well-intentioned code that's been exploited by outsiders.

The principle of least privilege says that any given privilege should be granted to the least amount of code necessary, for the least amount of time necessary. In other words, at any given time, try to erect as many walls around your code as possible. When something bad happens—as Murphy's Law guarantees it will—you'll be glad these walls were in place. So here are some concrete ideas for running code with the least privilege possible.

Choose a security context for your server code that grants access only to the resources it needs to get its work done. If certain parts of your code require significantly higher privileges, consider factoring the code out and running just that code with the higher privileges. To safely separate code that runs with different operating system credentials, your best bet is to run this code in a separate process that runs in a more privileged security context. This means you'll need interprocess communication such as COM or Microsoft .NET remoting, and you'll need to design the interface to that code to keep round-trips to a minimum.

If you're using the .NET Framework when factoring your code into assemblies, consider the required level of privilege of each piece of code. You may find it easy to isolate code that requires high privilege into separate assemblies that can be granted more permissions, allowing the majority of your assemblies to run with fewer privileges, thus adding more walls around your code. An easy way to restrict the privileges on a particular assembly is via assembly-level permission requests. If you do this, don't forget that you're limiting not only the permissions of your own assembly, but those of any assemblies you call, due to the Code Access Security (CAS) stack walk.

Many people build their applications so that new components can be plugged in after their product has been tested and shipped. It's very difficult to secure these types of applications because there's no way you can test every possible code path for bugs and security holes. If your application is managed, however, there's a nifty feature provided by the CLR that you can use to lock down these extensibility points. By declaring a permission object or a permission set and calling PermitOnly or Deny, you add a marker on your stack that chokes down the permissions granted to any code you call. By doing this before calling to some plug-in, you can restrict what the plug-in can do. For instance, a plug-in that's supposed to do amortization calculations shouldn't need any access to the file system. This is just another example of least privilege, where you can protect yourself ahead of time. Be sure to document these restrictions and be aware that highly privileged plug-ins will be able to get around these restrictions with the Assert statement.

8. Pay Attention to Failure Modes

Admit it. You hate writing error handling code just as much as the next guy. There are so many ways a piece of code can fail; it's just depressing thinking about it. Most programmers, ourselves included, would much rather focus on the normal path of execution. That's where the real work gets done. Let's get that error handling done as quickly and painlessly as possible and move on to the next line of real code.

Sadly, this is not a safe frame of mind. We need to pay much closer attention to failure modes in code. These bits of code are often written with little attention to detail and often go completely untested. When was the last time you made absolutely sure you stepped your debugger through every single line of code in a function, including every single one of those little error handlers?

Untested code often leads to security vulnerabilities. There are three things you can do to help alleviate this problem. First of all, pay just as much attention to those little error handlers as you do your normal code. Think about the state of the system when your error-handling code is executing. Are you leaving the system in a valid and secure state? Second, once you write a function, step your debugger through it several times, ensuring that you hit every error handler. Note that even this technique may not uncover subtle timing errors. You may need to pass bad arguments to your function or adjust the state of the system in some way that causes your error handlers to execute. By taking the time to step through the code, you are slowing yourself down long enough to take at least a second look at the code and the state of the system at the time it runs. We've discovered many flaws in our programming logic by carefully stepping through code in a debugger; it's a proven technique. Use it. Finally, make sure your test suites force your functions to fail. Try to have test suites that exercise every line of code in your function. These can help you discover regression, especially if you automate your tests and run them after every build.

There's one more very important thing to say about failure modes. Be sure that if your code fails, it leaves the system in the most secure state possible. Here's some bad code:

bool accessGranted = true; // optimistic!try { // see if we have access to c:\test.txt new FileStream(@"c:\test.txt", FileMode.Open, FileAccess.Read).Close();}catch (SecurityException x) { // access denied accessGranted = false;}catch (...) { // something else happened}Let's say that as far as the CLR is concerned, we're granted access to the file. In this case, a SecurityException won't be thrown. But what if, for instance, the discretionary access control list (DACL) on the file doesn't grant us access? In this case, a different type of exception will be thrown. But due to our optimistic assumption in the first line of code, we'll never know this.

A better way to write this code is to be pessimistic:

bool accessGranted = false; // pessimistic!try { // see if we have access to c:\test.txt new FileStream(@"c:\test.txt", FileMode.Open, FileAccess.Read).Close(); // if we're still here, we're good! accessGranted = true;}catch (...) {}This is much more robust, because no matter how we fail, we'll fall back to the most secure mode.

9. Impersonation is Fragile

When writing server applications, you'll often find yourself using, directly or indirectly, a convenient feature of Windows called impersonation. Impersonation allows each thread in a process to run in a distinct security context, typically the client's security context. For instance, when the file system redirector receives a request for a file via the network, it authenticates the remote client, checks to see that the client's request doesn't violate the DACL on the share, then attaches the client's token to the thread handling the request, thus impersonating the client. This thread can then access the local file system on the server using the security context of the client. This is convenient since the local file system is already secure; it will do an access check that considers the type of access being requested, the DACL on the file, and the impersonation token on the thread. If the access check fails, the local file system reports this to the file system redirector, who then can send a fault back to the remote client. This is incredibly convenient for the file system redirector because it simply passes the buck to the local file system and lets the local file system do its own access checking, just as if the client was local.

This is all well and good for simple gateways like the file system redirector. However, impersonation is often used in other, more complex applications. Take a Web application for instance. If you're writing a classic unmanaged ASP application, ISAPI extension, or an ASP.NET application which specifies

in its Web.config file, you are running in an environment with two different security contexts: you have a process token and a thread token, and generally speaking, the thread token will be used for access checks. Say you are writing an ISAPI application that runs inside the Web server process. Your thread token is likely IUSR_MACHINE, given that most requests are unauthenticated. But your process token is SYSTEM! Say your code is compromised by a bad guy via a buffer overflow exploit. Do you think the bad guy will be content with running as IUSR_MACHINE? No way. It's very likely that his attack code will call RevertToSelf to remove the impersonation token, hoping to elevate his privilege level. In this case, he'll succeed quite nicely. Another thing he can do is call CreateProcess. The token for that new process will be copied not from the impersonation token, but from the process token, so the new process runs as SYSTEM.

What's the solution to this little problem? Well, besides making sure you don't have any buffer overflows to begin with, remember the principle of least privilege. If your code doesn't need the god-like privileges afforded to SYSTEM, don't configure your Web application to run inside the Web server process. If you simply configure your Web application to run with medium or high isolation, your process token will be IWAM_MACHINE. You'll have virtually no privileges at all, and this sort of attack won't be nearly as effective. Note that in IIS 6.0, which will be a component of Windows .NET Server, no user-written code runs as SYSTEM by default. This is based on the realization that developers do make mistakes, and any assistance the Web server can provide to reduce the privileges given to code is a good thing, just in case there is a security bug in the code.

Here's another gotcha that COM programmers can run into. COM has a nasty tendency to play games with threads. If you make a call to an in-process COM server whose threading model doesn't match that of the calling thread, COM will execute the call on a different thread. COM will not propagate the impersonation token on the caller's thread, so the result is that the call will execute in the security context of the process, not of the calling thread. What a Surprise!

Here's another scenario where impersonation can bite you. Say you have a server that accepts requests via named pipes, DCOM, or RPC. You authenticate your clients and impersonate them, opening kernel objects on their behalf while impersonating. Let's say you forget to close one of these objects (for instance, a file) when the client disconnects. When the next client comes along, you authenticate and impersonate that client, and guess what? You can still access the file that was "leaked" from the previous client, even if the new client isn't granted access to the file. For performance reasons, the kernel only performs access checks on objects when you first open them. Even if your security context changes later on because you're impersonating somebody else, you will still be able to access this file.

Each of the scenarios we've mentioned so far is a reminder that impersonation is a convenience for server developers, and it's a fragile convenience at that. Pay close attention to your code when you're running with an impersonation token.

10. Write Apps that Non-admins Can Actually Use

This really is a corollary of the principal of least privilege. If programmers continue to produce code that doesn't run well on Windows unless the user is an administrator, how the heck can we ever expect to shake free of the stigma of targeting an "insecure" system? Windows has a very robust set of security features, but if users are forced to run as administrators to get anything done, they aren't getting much benefit from these features.

How can you help? Well first of all, eat your own dogfood. Quit running as an administrator yourself. You will learn very quickly the pain of using programs that were not designed with security in mind. We hear way too many programmers give excuses for why they choose to run as administrators when developing code. If we all keep ignoring the problem, it's only going to get worse. Folks, it doesn't take admin privileges to edit a text file. It doesn't take admin privileges to compile or debug a program that you started. When you need admin privileges, run individual programs with elevated privileges using the RunAs feature of the operating system. If you are writing tools for developers to use, you have an extra responsibility to the community. We need to stop this vicious circle of folks writing code that only administrators can run, and the only way it's going to happen is if we do it at the grassroots level.

 How To: Secure Your Developer Workstation

 

 

Improving Web Application Security: Threats and Countermeasures
Summary: This How To helps you improve your development workstation security. Developers often have computers running software such as IIS, Microsoft SQL Server, or the Microsoft SQL Server Desktop Engine (MSDE.) For example, Microsoft Visual Studio® .NET is designed for local development with IIS, so it is common for a developer to run IIS locally. As a developer, you need to be able to secure these services against attack, even if your computer is in a protected local area network.
This How To provides quick tips to help you improve the security of your developer workstation, along with tips about how to keep it secure. It also helps you avoid common problems that you are likely to encounter when you secure your workstation. Finally, it provides tips about how to determine problems and to revert security settings if they prove too restrictive.
Note This How To is not exhaustive, but it highlights many of the key issues.
Contents
Before You Begin
Steps to Secure Your Developer Workstation
Run using a least privileged account
Patch and update
Secure IIS
Pitfalls
Secure SQL Server and MSDE
Evaluate your configuration categories
Stay secure
Before You Begin
Before you begin securing your workstation, you need the following tools:
• Microsoft Baseline Security Analyzer (MBSA). Microsoft provides the MBSA tool to help analyze the security configuration of your computers and to identify missing patches and updates. You can download the MBSA tool from http://www.microsoft.com/technet/security/tools/mbsahome.mspx.
• IISLockdown. The IISLockdown tool reduces your computer's attack surface by hardening default IIS and Windows configuration settings and by removing unnecessary IIS extensions. IISLockown also installs the "404.dll" ISAPI filter, which is used to report "404 File Not Found" messages when disabled extensions are requested.
You can download the IISLockdown tool from http://download.microsoft.com/download/iis50/Utility/2.1/NT45XP/EN-US/iislockd.exe.
• URLScan. URLScan is an ISAPI filter that rejects or allows HTTP requests based on a configurable set of rules. It is integrated with IISLockdown, although you can also download it separately. It comes with customizable templates for each supported server role.
To install URLScan without IISLockdown, see Microsoft Knowledge Base article 307608, "INFO: Availability of URLScan Version 2.5 Security Tool," at http://support.microsoft.com/default.aspx?scid=kb;en-us;307608, in the Microsoft Knowledge Base.
Steps to Secure Your Developer Workstation
To secure your developer workstation, perform the following tasks:
• Run using a least privileged account
• Patch and update
• Secure IIS
• Secure SQL Server and MSDE
• Evaluate your configuration categories
• Stay secure
Run Using a Least-Privileged Account
You should develop applications using a non administrator account. Doing so is important primarily to limit the exposure of the logged on user and to help you to design more secure software. For example, if you design, develop, and test an application while you are interactively logged in as an administrator, you are much more likely to end up with software that requires administrative privileges to run.
You should not generally log on using the local administrator account. The account that you use on a daily basis should not be a member of the local Administrators group. Sometimes you might still need an account that has administrative privileges — for example, when you install software or edit the registry. Because the default local administrator account is well known, however, and it is the target of many attacks, create a non-standard administrator account and use this only when it is required.
To create accounts for development
1. Remove your current user account from the Administrators group if it is a member.
2. Create a new custom administration account using a nonstandard name and strong password.
3. Use your non-administrator account to logon interactively on a daily basis. When you need to run a command with administrative privileges, use your custom administration account with the Runas.exe command line utility.
Running Privileged Commands
To run a privileged command, you can use one of the following techniques to temporarily change your security context:
• Use the Runas.exe utility from a command line. The following command shows you how to use the Runas.exe utility to launch a command console that runs under your custom administration account.
runas.exe /user:mymachine\mycustomadmin cmd.exe
By executing Cmd.exe, you start a new command window that runs under the security context of the user you specify with the /user switch. Any program you launch from this command window also runs under this context.
• Use Run As from Windows Explorer. You can right-click an executable file in Windows Explorer and click Run As. To display this item on Windows 2000 or Windows Server 2003, hold down the SHIFT key and then right-click an executable file. When you click Run As, you are prompted for the credentials of the account you want to use to run the executable file.
• Use Run As shortcuts. You can create quick launch and desktop shortcuts to easily run applications using a privileged user account. The following example shows a shortcut that you can use to run Windows Explorer (Explorer.exe) using the administrator account:
%windir%\System32\runas.exe /user:administrator explorer
Note If using a non-administrator account proves impractical for your environment, still test your application or component while running as a least privileged user to catch and correct problems before deploying. For example, your application might incorrectly require administrator privileges without your realizing it, which would cause the application to fail when it is deployed in a production environment.
Patch and Update
Ensure that your workstation has the latest service packs and patches. Check the operating system, IIS, SQL Server, MSDE, Microsoft Data Access Components (MDAC), and the .NET Framework. Microsoft offers several tools and methods to help you scan and update your system. These include the Windows Update site, the Microsoft Baseline Security Analyzer (MBSA) tool, and the Automatic Updates feature.
Using Windows Update
You can use Windows Update (available from the Start menu) to scan for updates and patches for Windows. Alternatively, you can directly scan for updates at http://windowsupdate.microsoft.com.
Note After you update your system using the Windows Update site, use MBSA to detect missing updates for SQL Server, MSDE, and MDAC.
Using MBSA
You can use MBSA to assess security and to verify patches. If you used automatic updates or Windows Update to update your operating system and components, MBSA verifies those updates and additionally checks the status of updates for SQL Server and Microsoft Exchange Server. MBSA lets you create a script to check multiple computers.
To detect and install patches and updates
1. Download MBSA from the MBSA home page at http://www.microsoft.com/technet/security/tools/mbsahome.asp.
If you do not have Internet access when you run MBSA, MBSA cannot retrieve the XML file that contains the latest security settings from Microsoft. You can use another computer to download the XML file, however. Then you can copy it into the MBSA program directory. The XML file is available at http://download.microsoft.com/download/xml/security/1.0/nt5/en-us/mssecure.cab.
2. Run MBSA by double-clicking the desktop icon or selecting it from the Programs menu.
3. Click Scan a computer. MBSA defaults to the local computer.
4. Clear all check boxes except for Check for security updates. This option detects which patches and updates are missing.
5. Click Start scan. Your server is now analyzed. When the scan completes, MBSA displays a security report, which it also writes to the %Userprofile%\SecurityScans directory.
6. Download and install the missing updates. Click Result details next to each failed check to view the list of missing security updates.
The resulting dialog box displays the Microsoft security bulletin reference number. Click the reference to find out more about the bulletin and to download the update.
For more information about using MBSA, see "How To: Use Microsoft Baseline Security Analyzer (MBSA)," in the How To section of this guide.
Note MBSA will not indicate required .NET Framework updates and patches. Browse the .NET Framework downloads page at http://msdn.microsoft.com/netframework/downloads/default.asp.
Using Automatic Updates
The Automatic Updates feature offers the easiest method to update your operating system with the latest critical security patches. The feature is built into Windows XP, Windows Server 2003 and is installed with Windows 2000 Service Pack 3.
To configure Automatic Updates with Windows 2000, click Automatic Updates in the Control Panel. For more information about Automatic Updates and Windows 2000, see Microsoft Knowledge Base article 327850, "How To: Configure and Use Automatic Updates in Windows 2000."
To configure Automatic Updates with Windows XP
1. Right-click the My Computer icon on the desktop or the System icon in Control Panel.
2. Click System Properties.
For more information about Automatic Updates and Windows XP, see Microsoft Knowledge Base article, 306525, "How To: Configure and Use Automatic Updates in Windows XP."
Note For more information about Automatic Updates for Windows Server 2003, see Microsoft Knowledge Base article 327838, "How to schedule automatic updates in Windows Server 2003, in Windows XP, and in Windows 2000."
Automatic Updates scans and installs updates for the following operating systems (including the .NET Framework and IIS where applicable):
• Microsoft Windows 2000 Professional
• Microsoft Windows 2000 Server
• Microsoft Windows XP Professional
• Microsoft Windows Server 2003
In addition to using Automatic Updates, use MBSA to detect missing updates for SQL Server, MSDE and MDAC.
Secure IIS
You often need to run IIS locally for Web development. If you run IIS, secure it. IISLockdown and URLScan significantly reduce your Web server's attack profile. IISLockdown points unused or forbidden script mappings to 404.dll and helps secure access to system directories and system tools. URLScan blocks known dangerous requests.
Although IISLockdown improves IIS security, if you choose the wrong installation options or do not modify the URLScan configuration file, URLScan.ini, you could encounter the following issues:
• You cannot create new ASP.NET Web applications. NTFS file system permissions are configured to strengthen default access to Web locations. This may prevent the logged on user from creating new ASP.NET Web applications.
• Cannot debug existing ASP.NET Web applications. URLScan blocks the DEBUG verb, which is used when you debug ASP.NET Web applications.
The following steps show you how to improve IIS security on your development workstation and avoid the issues listed above:
• Install and run IISLockdown
• Configure URLScan
• Restrict access to the local Web server
Install and Run IISLockdown
Note By default, IIS 6.0 has security-related configuration settings similar to those made by the IIS Lockdown Tool. Therefore you do not need to run the IIS Lockdown Tool on Web servers running IIS 6.0. However, if you are upgrading from a previous version of IIS (5.0 or lower) to IIS 6.0, it is recommended that you run the IIS Lockdown Tool to enhance the security of your Web server.
To install and run IISLockdown
1. Run the IISLockdown installation program (Iislockd.exe) from http://download.microsoft.com/download/iis50/Utility/2.1/NT45XP/EN-US/iislockd.exe.
Note If you run Iislockd.exe a second time, it removes all changes based on the log file \WINNT\System32\Inetsrv\oblt-log.log.
2. During setup, choose the Dynamic Web Site option, and choose the option to install URLScan. ASP.NET Web Forms use the HTTP POST verb. Choosing the static option and installing URLScan blocks the POST verb in URLScan.ini.
The Dynamic Web Site option does the following:
• Adds POST to the [AllowVerbs] section as shown below.
[AllowVerbs]
GET
HEAD
POST
• Disables the following Internet Services: Web service (HTTP), File Transfer Protocol (FTP), the Simple Mail Transport Protocol (SMTP) e-mail service, and the Network News Transport Protocol (NNTP) news service.
• Maps the following script maps to 404.dll: Index Server, Web Interface (.idq, .htw, .ida), server side includes (.shtml, .shtm, .stm), Internet Data Connector (.idc), HTR scripting (.htr), Internet printing (.printer)
• Removes the following virtual directories: IIS Samples, MSADC, IISHelp, Scripts, and IISAdmin.
• Restricts anonymous access to system utilities and the ability to write to Web content directories.
• Disables Web Distributed Authoring and Versioning (WebDAV).
• Installs the URLScan ISAPI filter.
Pitfalls
If you use IISLockdown, note the following pitfalls:
• IIS metabase updates can be lost. If you undo IISLockdown changes by running Iislockd.exe a second time, you lose any changes made to the IIS metabase since the last time IISLockdown was run. For example, if you configure a virtual directory as an application root after running IIS lockdown, that change is lost when you run IISLockdown again.
• Resources are blocked by 404.dll. If you receive a 404 error for a previously available resource, it might be because the resource type is blocked by 404.dll. To confirm whether or not this is the case, check the script mapping for the requested resource type in IIS.
Configure URLScan
The URLScan ISAPI filter installs when you run IISLockdown. If you do not explicitly allow the DEBUG verb, URLScan prevents debugging. Also, URLScan blocks requests that contain unsafe characters such as the period (.) used for directory traversal.
Note IIS 6.0 on Windows Server 2003 has functionality equivalent to URLScan built in. Your decision whether to implement UrlScan should be based on your organization's specific requirements. For more information and guidance, see "Installing UrlScan 2.5" at http://www.microsoft.com/technet/security/tools/urlscan.mspx#EEAA.
To configure URLScan, edit URLScan.ini in %Windir%\System32\inetsrv\urlscan\. To allow debugging with URLScan, add DEBUG to the [AllowVerbs] section in URLScan.ini as shown below.
[AllowVerbs]
GET
HEAD
POST
DEBUG
Pitfalls
If you install URLScan, note the following pitfalls:
• When you debug an application by using Visual Studio.NET, you may see the following error:
Microsoft Development Environment:
Error while trying to run project: Unable to start debugging on the Web server. Could not start ASP.NET or ATL Server debugging.
Verify that ASP.NET or ATL Server is correctly installed on the server. Would you like to disable future attempts to debug ASP.NET pages for this project?
You should see a log entry similar to the one shown below in URLScan.log in the \WINNT\system32\inetsrv\urlscan folder.
[02-08-2008- 22:25:26] Client at 127.0.0.1: Sent verb 'DEBUG', which is not specifically allowed. Request will be rejected.
• Requests that you expect to work might get blocked.
• You may not be able to create new Web projects in Visual Studio .NET because you use characters in the project name that URLScan rejects. For example, the comma (,) and the pound sign (#) will be blocked.
If you experience errors during debugging, see Microsoft Knowledge Base article 306172, "INFO: Common Errors When You Debug ASP.NET Applications in Visual Studio .NET," at http://support.microsoft.com/default.aspx?scid=kb;EN-US;306172.
Secure SQL Server and MSDE
To update SQL Server and MSDE, you must:
• Apply patches for each instance of SQL Server and MSDE
• Analyze SQL Server and MSDE security configuration
Apply Patches for Each Instance of SQL Server and MSDE
MSDE shares common technology with SQL Server, and it enables developers, partners, and IT professionals to build database applications without requiring the full SQL Server product. MSDE can be packaged with applications that require database support. To apply patches to MSDE, you must know which application installed it on your system. This is important because you must obtain the patch for MSDE from the product vendor.
For more information on applications that include MSDE, refer to the following resources:
• "Microsoft Products That Include MSDE," at http://www.microsoft.com/technet/security/bulletin/msdeapps.mspx
• "SQL Server/MSDE-Based Applications," at http://www.sqlsecurity.com/DesktopDefault.aspx?tabid=31
If your third-party vendor does not supply a patch for MSDE, and if it becomes critical to have the latest patches, you can only do the following:
• Uninstall the instance of SQL Server using Add/Remove Programs. If you do not see an uninstall option for your instance, you might need to uninstall your application.
• Stop the instance of SQL Server using the Services MMC snap-in in Computer Management. You can also stop the instance from the command line by running the following command:
net stop mssqlserver (default instance), mssql$instancename (for instances)
• Use IPSec to limit which hosts can connect to the abandoned (unpatched) instances of SQL Server. Restrict access to localhost clients.
Analyze SQL Server and MSDE Security Configuration
Use MBSA to analyze your Microsoft SQL Server or MSDE configuration on your workstation.
To analyze SQL Server and MSDE security configuration
1. Run MBSA by double-clicking the desktop icon or selecting it from the Programs menu.
2. Click Scan a computer. MBSA defaults to the local computer.
3. Clear all check boxes except for Check for SQL vulnerabilities.
This option scans for security vulnerabilities in the configurations of SQL Server 7.0, SQL Server 2000, and MSDE. For example, it checks the authentication mode, the sa account password, and the SQL Server service account, among other checks.
A number of the checks require that your instance of SQL Server is running. If it is not running, start it.
4. Click Start scan. Your configuration is now analyzed. When the scan completes, MBSA displays a security report, which it also writes to the %Userprofile%\SecurityScans directory.
5. Review the failed checks, and fix vulnerable configuration settings.
Click Result details next to each failed check for more information about why the check failed. Click How to correct this, for information about how to fix the vulnerability.
For more information about using MBSA, see "How To: Use Microsoft Baseline Security Analyzer (MBSA)," in the How To section of this guide.
Evaluate Your Configuration Categories
To evaluate the security of your workstation configuration, review the configuration categories shown in Table. Start by using the categories to evaluate the security configuration of the base operating system. Then apply the same configuration categories to review your IIS, SQL Server, and .NET Framework installation.
Configuration Categories
Configuration Category Methodology
Patches and updates Setup Automatic Updates. Use MBSA or Windows Updates to verify that the latest updates are installed
Services Disable unused services.
Protocols Check that SMB and NetBIOS over TCP are removed if your workstation is not a member of a domain.
Accounts Check that all local accounts use strong passwords.
Files and directories Be sure your workstation uses only NTFS partitions.
Shares Enumerate shares, remove unnecessary ones, and secure the remaining ones with restricted permissions.
Ports Ensure that unused ports are closed by disabling the service that has the port open. To verify which ports are listening use the netstat –n –a command.
Registry Disable null sessions.
Auditing and logging Audit failed Windows attempts to log on and log failed actions across the file system.
Stay Secure
Monitor the security state of your workstation, and update it regularly to help prevent newly discovered vulnerabilities from being exploited.

General Web Application Security Recommendations

Even the most elaborate application security can fail if a malicious user can use simple ways to gain access to your computers. General Web application security recommendations include the following:

· Back up data often and keep your backups physically secure.

· Keep your Web server physically secure so that unauthorized users cannot gain access to it, turn it off, physically steal it, and so on.

· Use the Windows NTFS file system, not FAT32. NTFS offers substantially more security than FAT32. For details, see the Windows Help documentation.

· Protect the Web server and all of the computers on the same network with strong passwords.

· Close any unused ports and turn off unused services.

· Run a virus checker that monitors site traffic. Use a firewall

· Learn about and install the latest security updates from Microsoft and other vendors.

· Use Windows event logging and examine the logs frequently for suspicious activity. This includes repeated attempts to log on to your system and excessive requests against your Web server.

Run Applications with Minimum Privileges

When your application runs, it runs within a context that has specific privileges on the local computer and potentially on remote computers. To run with the minimum number of privileges needed, follow these guidelines:

· Do not run your application with the identity of a system user (administrator).

· Run the application in the context of a user with the minimum practical privileges.

· Set permissions (ACLs, or Access Control Lists) on all the resources required for your application. Use the most restrictive setting. For example, if practical in your application, set files to be read-only.

· Keep files for your Web application in a folder below the application root. Do not allow users the option of specifying a path for any file access in your application. This helps prevent users from getting access to the root of your server.

Know Your Users

In many applications, it is possible for users to access the site without having to provide credentials. If so, your application accesses resources by running in the context of a predefined user. By default, this context is the local ASPNET user (Windows 2000 or Windows XP) or NETWORK SERVICE user (Windows Server 2003) on the Web server.

To restrict access to users who are authenticated, follow these guidelines:

· If your application is an intranet application, configure it to use Windows Integrated security. This way, the user's login credentials can be used to access resources.

· If you need to gather credentials from the user, use one of the ASP.NET authentication strategies.

Guard Against Malicious User Input

As a general rule, never assume that input you get from users is safe. It is easy for malicious users to send potentially dangerous information from the client to your application. To help guard against malicious input, follow these guidelines:

· In forms, filter user input to check for HTML tags, which might contain script.

· Never echo (display) unfiltered user input. Before displaying untrusted information, encode HTML to turn potentially harmful script into display strings.

· Similarly, never store unfiltered user input in a database.

· If you want to accept some HTML from a user, filter it manually. In your filter, explicitly define what you will accept. Do not create a filter that tries to filter out malicious input; it is very difficult to anticipate all possible malicious input.

· Do not assume that information you get from the header (usually via the Request object) is safe. Use safeguards for query strings, cookies, and so on. Be aware that information that the browser reports to the server (user agent information) can be spoofed, in case that is important in your application.

· If possible, do not store sensitive information in a place that is accessible from the browser, such as hidden fields or cookies. For example, do not store a password in a cookie.

· View state is stored in a hidden field in an encoded format. By default, it includes a message authentication code (MAC) so that the page can determine whether view state has been tampered with.

Access Databases Securely

Databases typically have their own security. An important aspect Web application security is designing a way for the application to access the database securely. Follow these guidelines:

· Use the inherent security of your database to limit who can access database resources. The exact strategy depends on your database and your application:

· If practical in your application, use Windows Integrated security so that only Windows-authenticated users can access the database. Integrated security is more secure than using SQL Server standard security.

· If your application uses anonymous access, create a single user with very limited permissions, and perform queries by connecting as this user.

· Do not create SQL statements by concatenating strings that involve user input. Instead, create a parameterized query and use user input to set parameter values.

· If you must store a user name and password somewhere to use as the database login credential, store them securely. If practical, encrypt or hash them.

Create Safe Error Messages

If you are not careful, a malicious user can deduce important information about your application from the error messages it displays. Follow these guidelines:

· Do not write error messages that echo information that might be useful to malicious users, such as a user name.

· Configure the application not to show detailed errors to users. If you want to display detailed error messages for debugging, check first that the user is local to the Web server.

· Use the customErrors configuration element to control who can view exceptions from the server.

· Create custom error handling for situations that are prone to error, such as database access.

Keep Sensitive Information Safely

Sensitive information is any information that you need to keep private. A typical piece of sensitive information is a password or an encryption key. If a malicious user can get to the sensitive information, then the data protected by the secret is compromised. Follow these guidelines:

· If your application transmits sensitive information between the browser and the server, consider using Secure Sockets Layer (SSL.

· Use Protected Configuration to secure sensitive information in configuration files such as the Web.config or Machine.config files.

· If you must store sensitive information, do not keep it in a Web page, even in a form that you think people will not be able to view (such as in server code).

· Use the strong encryption algorithms supplied in the System.Security.Cryptography namespace.

Use Cookies Securely

Cookies are an easy and useful way to keep user-specific information available. However, because cookies are sent to the browser's computer, they are vulnerable to spoofing or other malicious use. Follow these guidelines:

· Do not store any critical information in cookies. For example, do not store a user's password in a cookie, even temporarily. As a rule, do not store any sensitive information in a cookie that. Instead, keep a reference in the cookie to a location on the server where the information is located.

· Set expiration dates on cookies to the shortest practical time you can. Avoid permanent cookies if possible.

· Consider encrypting information in cookies.

· Consider setting the Secure and HttpOnly properties on your cookies to true.

Guard Against Denial-of-Service Threats

An indirect way that a malicious user can compromise your application is by making it unavailable. The malicious user can keep the application too busy to service other users, or if nothing else can simply crash the application. Follow these guidelines:

· Close or release any resource you use. For example, always close data connections and data readers, and always close files when you are done using them.

· Use error handling (for example, try/catch blocks). Include a finally block in which you release resources in case of failure.

· Configure IIS to use throttling, which prevents an application from using a disproportionate amount of CPU.

· Test size limits of user input before using or storing it.

· Put size safeguards on database queries to help guard against large queries using up system resources.

· Put a size limit on file uploads, if those are part of your application. You can set a limit in the Web.config file using syntax such as the following code example, where the maxRequestLength value is in kilobytes:

You can also use the RequestLengthDiskThreshold property in to reduce the memory overhead of large uploads and form posts