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.

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!

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 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.

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 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.

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 dynamic-link library (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.

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

The buffer overrun issue I want to spell out 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 / sizeof(g_wszHostName[0]));

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.

  • 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 they are.

Don t Store Secrets in Web Pages

Storing secrets in Web pages is an exceedingly common flaw, because many people store database connection strings in their Web pages. How many times have you seen ASP code that includes a line like the following?

strDSN = provider=SQLOLEDB; + _ server=SQLBox; + _ initial catalog=Client; + _ uid=sa;pwd=^&hjabW0!; + _ network=dbmssocn 

If for some reason an attacker can view the ASP code, he can learn a number of things about your environment, including the name of the SQL Server database (SQLBox), the username and password used to connect to the database, and the fact that the ASP application uses sockets to communicate with the database, which probably means that port 1433, the default SQL Server socket port, is open on the computer running SQL Server. This information makes it somewhat trivial for an attacker to compromise that computer directly. You should never store secrets in Web-based files, for plainly obvious reasons.

note

A cautious designer would configure a firewall between the Web server and the SQL Server database such that traffic can flow only from the Web server to the database, and vice versa. The same can be achieved using Internet Protocol Security (IPSec) in Windows 2000 and later. If an attacker gained information about the SQL Server database, she would also have to compromise the Web server and use the Web server to access the data on the database server.

To mitigate this threat, first use a COM object to access the private data in some other resource, such as the registry. This is both simple to do and surprisingly effective. Don t use the na ve approach of storing the secret data in a COM component, which is bad for two reasons. First, if you change the data, you have to recompile the code, and second, if the attacker can download the COM component binary, he can easily determine the secret data.

Another useful way to protect the sensitive data, which takes a little more work, is to use a COM+ object constructor string; this data is configured by the administrator and passed by the COM+ run time to the component. An administrator can set the string by using the Component Services administration tool. The following C++ code shows some of the code from a simple implementation written in ATL. The code lines appearing in boldface are code you must add to the default ATL COM+ server wizard-generated code. The complete code listing is available on the companion CD in the folder Secureco\Chapter 12\ConsString.

//The Header File Connection.h #include COMSvcs.h" class ATL_NO_VTABLE CConnection : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CConnection, &CLSID_Connection>, public IObjectConstruct, public IDispatchImpl<IConnection, &IID_IConnection, &LIBID_CONSSTRINGLib> { public: CConnection(){} DECLARE_REGISTRY_RESOURCEID(IDR_CONNECTION) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CConnection) COM_INTERFACE_ENTRY(IConnection) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IObjectConstruct) END_COM_MAP() // IConnection public: STDMETHOD(get_String)(/*[out, retval]*/ BSTR *pVal); BSTR m_bstrConstruct; STDMETHODIMP Construct(IDispatch * pUnk); protected: CComPtr< IObjectContext > m_spObjectContext; }; // The Source File Connection.cpp STDMETHODIMP CConnection::Construct( IDispatch* piDispatch ) { if (!piDispatch) return E_UNEXPECTED; CComQIPtr< IObjectConstructString, &IID_IObjectConstructString > spObjectConstructString = piDispatch; return spObjectConstructString->get_ConstructString (&m_bstrConstruct); } STDMETHODIMP CConnection::get_String(BSTR *pVal) { *pVal = m_bstrConstruct; return S_OK; }

It s considerably easier to access a COM+ constructor string if you write COM+ components using Visual Basic. Refer to Knowledge Base article Q271284, HOWTO: Access the COM+ Object Constructor String in a Visual Basic Component, at support.microsoft.com/support/kb/articles/Q271/2/84.ASP.

The following ASP code shows how you can call this COM+ object to get the constructor string:

<% Dim o, strDSN o = CreateObject( ConsString.Connection ) strDSN = o.String Now use the data held in strDSN to connect to the database. %>

And finally, you can configure the constructor string itself in the Component Services administration tool once you ve added the component to the list of COM+ applications in the tool. Figure 12-4 shows where you can set this option in the Component Services tool.

Figure 12-4

Setting the constructor string in the Component Services tool.

Personally, I would store the data in the registry and ACL the registry key accordingly. It s not perfect, but it s a lot better than storing the key in a Web server file.

Other Forms of Private Data

Other private data you should be wary of storing in a Web page include comments like these:

 ************************************** Title: HandOffAuth.asp Project: Jupiter Date: 13-July-2001 Author: Michael Howard (mike@northwindtraders.com) Phone: 425 111 1111 Location: Building 7, Redmond **************************************

An attacker might use this to glean insights into the organization, which in turn might give him more information to mount social engineering attacks. A social engineering attack involves an attacker sounding convincing on a phone or in person to gain access to private information maintained by an organization. Based on the comment above, an attacker could phone someone at the company and say, Hi, Lynne, this is Mike from building 7. I worked on the Jupiter project in July. We seem to have some problems with the system. Can you please change your password to Fr0tzB1tx# so we can rectify it? Guess what Mike does next? You guessed it he logs on as Lynne by using Fr0tzB1tx# as the password.

I have also seen developers accidentally leave internal e-mail aliases and computer names in their code not in comments, but in code, especially in default data values. Here s a sample written in C++. It s not a Web sample, but I m sure you understand the issue!

BOOL AccessServer(char *szServer, char *szName) { BOOL fRet = FALSE; if (szServer == NULL) szServer="\\\\TheDatabase"; if (szName == NULL) szName="Northwindtraders\\mike"; // Access the server. fRet = ConnectToServer(szServer, szName, READONLY); // SNIP return fRet; }

You should scour all your code for such revelations.

Do You Really Need to Use sa? Probably Not!

Earlier, in the section Don t Store Secrets in Web Pages, I pointed out the error of making connections to SQL Server, or any other database server, as sysadmin from Web pages. In the case of SQL Server, the sysadmin account is named sa. In Oracle, the account is named internal. You should never make a connection to any database server by using such a dangerous account; sa is to SQL Server what SYSTEM is to Windows NT and later. Both are, by far, the most capable and potentially damaging accounts in their respective systems.

If you re having problems making the connection, imagine this: every time you access a Windows server, you can run applications as SYSTEM and can do whatever SYSTEM can do, which is everything. This is what it means to use a Web page that connects to a SQL database as sa. If you see a connection string that connects to the database as a sysadmin account, file a bug and get it fixed. You are violating the principles of least privilege and defense in depth if you use a sysadmin-like account to connect from your Web application to the database.

Most Web-based applications do not need the capabilities of sysadmin to run; most database-driven applications allow users to add and update their own data. If the connection is made as sysadmin and there s a bug in the SQL code, an attacker can perform any task sysadmin can, including the following:

  • Delete (called dropping) any database or table in the system

  • Delete any data in any table in the system

  • Change any data in any table in the system

  • Change any stored procedure, trigger, or rule

  • Delete logs

  • Add new users to the system

As you can see, the potential for damage is unlimited. One way to mitigate this issue is to support authenticated connections by using native operating-system authentication and authorization by setting Trusted_Connection=True in the connection string. If you cannot use native authentication techniques, you should create a specific account that has just the correct privileges to read, write, and update the appropriate data in the database, and you should use that to connect to the database. This account should be regularly checked to determine what privileges it has in the database and to make sure an administrator has not accidentally given it capabilities that could compromise the system.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2005
Pages: 153

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