Other Web-Based Security Topics

Other Web-Based Security Topics

This section outlines common security mistakes I've seen in Web-based applications over the past few years. It's important to note that many of these issues apply to both Microsoft and non-Microsoft solutions.

eval() Can Be Bad

You have a serious security flaw if you create server-side code that calls the JavaScript eval function (or similar) and the input to the function is determined by the attacker. JavaScript eval makes it possible to pass practically any kind of code to the browser, including multiple JavaScript statements and expressions, and have them executed dynamically. For example, eval("a=42; b=69; document.write(a+b);""); writes 111 to the browser. Imagine the fun an attacker could have if the argument string to eval is derived from a form field and is unchecked!

HTTP Trust Issues

HTTP requests are a series of HTTP headers followed by a content body. Any of this data can be spoofed because there's no way for the server to verify that any part of the request is valid or, indeed, that it has been tampered with. Some of the most common security mistakes Web developers make include trusting the content of REFERER headers, form fields, and cookies to make security decisions.

REFERER Errors

The REFERER header is a standard HTTP header that indicates to a Web server the URL of the Web page that contained the hyperlink to the currently requested URL. Some Web-based applications are subject to spoofing attacks because they rely on the REFERER header for authentication using code similar to that of this ASP page:

<% strRef = Request.ServerVariables("HTTP_REFERER") If strRef = "http://www.northwindtraders.com/login.html" Then ' Cool! This page is called from Login.html! ' Do sensitive tasks here. End If %>

The following Perl code shows how to set the REFERER header in an HTTP request and convince the server that the request came from Login.html:

use HTTP::Request::Common qw(POST GET); use LWP::UserAgent; $ua = LWP::UserAgent->new(); $req = POST 'http://www.northwindtraders.com/dologin.asp', [ Username => 'mike', Password => 'mypa$w0rd', ]; $req->header(Referer => 'http://www.northwindtraders.com/login.html'); $res = $ua->request($req);

This code can convince the server that the request came from Login.html, but it didn't it was forged! Never make any security decision based on the REFERER header or on any other header, for that matter. HTTP headers are too easy to fake. This is a variation of the oft-quoted never make a security decision based on the name of something, including a filename lemma.

NOTE
A colleague told me he sets up trip wires in his Web applications so that if the REFERER header isn't what's expected, he's notified that malicious action is possibly afoot!

ISAPI Applications and Filters

After performing numerous security reviews of ISAPI applications and filters, I've found two vulnerabilities common to such applications: buffer overruns and canonicalization bugs. Both are covered in detail in other parts of this book, but a special case of buffer overruns exists, especially in ISAPI filters. These filters are a special case because in IIS 5 ISAPI filters run in the Inetinfo.exe process, which runs as SYSTEM. Think about it: a DLL accepting direct user input running as SYSTEM can be a huge problem if the code is flawed. Because the potential for damage in such cases is extreme, you must perform extra due diligence when designing, coding, and testing ISAPI filters written in C or C++.

NOTE
Because of the potential seriousness of running flawed code as SYSTEM, by default, no user-written code runs as SYSTEM in IIS 6.

More Info
An example of an ISAPI vulnerability is the Internet Printing Protocol (IPP) ISAPI buffer overrun. You can read more about this bug at http://www.microsoft.com/ technet/security/bulletin/MS01-023.asp.

The buffer overrun issue I want to spell out here is the call to lpECB->GetServerVariable, which retrieves information about an HTTP connection or about IIS itself. The last argument to GetServerVariable is the size of the buffer to copy the requested data into, and like many functions that take a buffer size, you might get it wrong, especially if you're handling Unicode and ANSI strings. Take a look at this code fragment from the IPP flaw:

TCHAR g_wszHostName[MAX_LEN + 1]; BOOL GetHostName(EXTENSION_CONTROL_BLOCK *pECB) { DWORD dwSize = sizeof(g_wszHostName); char szHostName[MAX_LEN + 1]; //Get the server name. pECB->GetServerVariable(pECB->ConnID,  "SERVER_NAME", szHostName, &dwSize); //Convert ANSI string to Unicode. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)szHostName, -1, g_wszHostName, sizeof (g_wszHostName));

Can you find the bug? Here's a clue: the code was compiled using #define UNICODE, and TCHAR is a macro. Still stumped? There's a Unicode/ANSI byte size mismatch; g_wszHostName and szHostName appear to be the same length, MAX_LEN + 1, but they are not. When Unicode is defined during compilation, TCHAR becomes WCHAR, which means g_wszHostName is MAX_LEN + 1 Unicode characters in size. Therefore, dwSize is really (MAX_LEN + 1) * sizeof (WCHAR) bytes, because sizeof(WCHAR) is 2 bytes in Windows. Also, g_wszHostName is twice the size of szHostName, because szHostName is composed of one-byte characters. The last argument to GetServerVariable, dwSize, however, points to a DWORD that indicates that the size of the buffer pointed to by g_wszHostName is twice the size of szHostName, so an attacker can overrun szHostName by providing a buffer larger than sizeof(szHostName). Not only is this a buffer overrun, it's exploitable because szHostName is the last buffer on the stack of GetHostName, which means it's right next to the function return address on the stack.

The fix is to change the value of the dwSize variable and use WCHAR explicitly rather than TCHAR:

WCHAR g_wszHostName[MAX_LEN + 1]; BOOL GetHostName(EXTENSION_CONTROL_BLOCK *pECB) { char szHostName[MAX_LEN + 1]; DWORD dwSize = sizeof(szHostName); //Get the server name. pECB->GetServerVariable(pECB->ConnID,  "SERVER_NAME", szHostName, &dwSize); //Convert ANSI string to Unicode. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)szHostName, -1, g_wszHostName, sizeof (g_wszHostName) / sizeof(g_wszHostName[0]));

Two other fixes were added to IIS 6: IPP is off by default, and all users must be authenticated if they want to use the technology once it is enabled.

Some important lessons arise from this bug:

  • Perform more code reviews for ISAPI applications.

  • Perform even more code reviews for ISAPI filters.

  • Be wary of Unicode and ANSI size mismatches, which are common in ISAPI applications.

  • Turn less-used features off by default.

  • If your application accepts direct user input, authenticate the user first. If the user is really an attacker, you have a good idea who he or she is.

Sensitive Data in Cookies and Fields

If you create a cookie for users, you should consider what would happen if the user manipulated data in the cookie. The same applies to hidden fields; just because the field is hidden does not mean the data is protected.

I've seen two almost identical examples, one implemented using cookies, the other using hidden fields. In both cases, the developer placed a purchasing discount field in the cookie or the field on the HTML form, and the discount in the cookie or field was applied to the purchase. However, an attacker could easily change a 5 percent discount into a 50 percent discount, and the Web site would honor the value! In the case of the cookie example, the attacker simply changed the file on her hard drive, and in the field example, the attacker saved the source code for the HTML form, changed the hidden field value, and then posted the newly changed form to the Web site.

More Info
A great example of this kind of vulnerability was the Element N.V. Element InstantShop Price Modification vulnerability. You can read about this case at http://www.securityfocus.com/bid/1836.

The first rule is this: don't store sensitive data in cookies, hidden fields, or in any data that could potentially be manipulated by the user. If you must break the first rule, you should encrypt and apply a message authentication code (MAC) to the cookie or field content by using keys securely stored at the server. To the user, these data are opaque; they should not be manipulated in any way by any entity other than the Web server. It's your data you determine what is stored, what the format is, and how it is protected, not the user. You can learn more about MACs in Chapter 6, Determining Appropriate Access Control.

Be Wary of Predictable Cookies

The best way to explain this is by way of a story. I was asked to pass a cursory eye over a Web site created by a bank. The bank used cookies to support the user's sessions. Remember that HTTP is a stateless protocol, so many Web sites use cookies to provide a stateful connection. RFC 2965, HTTP State Management Mechanism, (http://www.ietf.org/rfc/rfc2965.txt) outlines how to use cookies in this manner.

The user maintained a list of tasks at the bank's Web server akin to a commerce site's shopping cart. If an attacker can guess the cookie, she can hijack the connection and manipulate the user's banking tasks, including moving money between accounts. I asked the developers how the cookies were protected from attack. The answer was not what I wanted but is very common: We use SSL. In this case, SSL would not help because the cookies were predictable. In fact, they were simply 32-bit hexadecimal values incrementing by one for each newly connected user. As an attacker, I simply connect to the site by using SSL and look at the cookie sent by the Web server to my client. Let's say it's 0005F1CC. I then quickly access the site again from a different session or computer, and let's say this time the cookie is 0005F1CE. I do it again and get 0005F1CF. It's obvious what's going on: the cookie value is incrementing, and it looks like someone accessed the site between my first two connections and has a cookie valued 0005F1CD. At any point, I can create a new connection to the Web site and, by using the Cookie: header, set the cookie to 0005F1CD or any other value prior to my first connection cookie and hijack another user's session. Then, potentially I can move funds around. Admittedly, I cannot choose my victim, but a disgruntled customer could be a huge loss for the bank, and of course the privacy implications of such an attack are serious.

The remedy and the moral of this story: make the cookies used for high-security situations unpredictable. In this case, the bank started creating cookies by using a good random number generator, which is discussed in Chapter 8, Cryptographic Foibles. Also, do not rely on SSL, our next subject, to protect you from all attacks.

SSL/TLS Client Issues

I've lost count of how many times I've heard designers and developers believe they are secure from attack because they use that good old silver bullet called SSL. SSL or, more accurately, TLS as it's now called, helps mitigate some threats but not all. By default, the protocol provides

  • Server authentication.

  • On-the-wire privacy using encryption.

  • On-the-wire integrity using message authentication codes.

It can also provide client authentication, but this option is not often used. The protocol does not provide the following:

  • Protection from application design and coding flaws. If you have a buffer overrun in your code, you still have a buffer overrun when using SSL/TLS.

  • Protection for the data once it leaves the secured connection.

You should also be aware that when a client application connects to a server by using SSL/TLS, the connection is protected before any other higher-level protocol data is transferred.

Finally, when connecting to a server, the client application should verify that the server name is the same as the common name in the X.509 certificate used by the server, that the certificate is well-formed and valid, and that it has not expired. By default, WinInet, WinHTTP, and the .NET Framework's System.Net will automatically verify these for you. You can turn these checks off, but it is highly discouraged.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2001
Pages: 286

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net