From the June 2002 issue of MSDN Magazine.
|XML Security Questions |
|Q I want to develop a secure XML Web Service that will hold information to authenticate a user so they can view their Microsoft® Exchange Inbox. I'm running Microsoft Internet Explorer 6.0, Windows® 2000 Server, Internet Information Services (IIS), the RTM version of the .NET Framework, and Exchange 6.0. I want to write a client that connects to a .NET (C#) Web application on the Web server so users can call a page that will display the Inbox contents and Calendar. On a standalone machine, one that hosts Exchange and IIS, I use Windows Authentication and can use impersonation to access the user's Inbox.|
The problem occurs when the Web server has to retrieve the client's mailbox information from the Exchange server; I use the Web gateway on the Exchange server and generate the relevant URL—for example, http://ExchangeServer/Exchange/ClientUsername/inbox/. At this point, the Web server has the client's username and can act on their behalf, but it does not have the user's password. Thus, the Exchange server rejects the Web server.
A One approach that you can take to this problem is to set up Kerberos authentication with delegation turned on between the Web server and the Exchange server. Credential delegation requires the Kerberos authentication protocol, which is part of Integrated Windows Authentication.
Furthermore, for credential delegation to work with Kerberos, all three tiers (client, middle-tier SPS server, and back-end Web server) must be running Windows 2000 or later, and Active Directory® must be deployed. Finally, you should not use XMLHTTP on the middle-tier server; use ServerXMLHTTP instead. XMLHTTP is designed for client-side use and could possibly jeopardize the stability of the server.
Q When I call selectSingleNode (L "ServiceInstanceSet/ServiceInstance/ ServiceInstanceId") on the following node
the call returns a failure when working with MSXML 4.0, whereas the same code works with MSXML 3.0.
How can I get this to work in MSXML 4.0? Also, if I qualify the namespace in input nodes to look something like this
what changes do I need in my XPath so that a call to selectSingleNode returns the node?
A Somewhat nonintuitively, you do not need to make any changes to your XML. XPath is selecting the nodes based on the URI, not the prefix you've assigned. The behavior you describe is by design: by default, MSXML 3.0 uses XSL for selecting nodes, which doesn't consider namespaces when selecting items. MSXML 4.0 (and 3.0 if you change the selection language to XPath) uses XPath 1.0, which respects the namespace that an element is in.
To select using a particular namespace, set the SelectionNamespaces property:
Then to refer to your elements, simply use the prefix you assigned (for instance, if you assign the prefix b to your namespace: b:ServiceInstanceSet).
Q I am using XMLHttpRequest object in client-side script of an HTML page to access a user's personal calendar appointments from my corporate domain Exchange server. But the browser displays the following security warning while executing the script.
Further, if the user selects "No" on the security warning dialog the script gives a "permission denied" error.
This page is accessing information that is not under its control.
This poses a security risk. Do you want to continue?
The article "XML Client Security" says if a user loads a page in the Local intranet zone that uses MSXML to access data from another site in the Local intranet zone, the user will be prompted that data is being accessed across domains.
The HTML page running the XMLHTTP script is hosted on an intranet Web site. There is a possibility that the users of the application have the "Access data sources across domains" option set to Prompt (or Disable).
Is there any way to prevent this dialog box from being displayed without changing the default browser setting?
A This is how cross-domain security fundamentally works. It's far from a perfect system, but it's simple. Since there is no way to specify which pages trust other pages to access their data, Internet Explorer simply says that if two pages are not in the same domain, they cannot communicate. More precisely, Zone Manager (found on the security tab in Internet Settings) does allow the user to say that a page may access another page, but as you point out, most people leave it set on prompt. You can suggest users add the page to the trusted site zone, or merely say Yes to the dialog box. Cross-domain security issues can be quite serious. Whenever you access data sources that are in a different context than your script, there are potential problems. A solution here would be to create a safe ActiveX® control that will perform the tasks you need and lock it down to the intranet site.
Q In my financial services application, I store all our customer data in the Internet Explorer DOM. While the data that is presented to the UI is based on the user's role and authorization, my concern is that a user may be able to read the DOM cache, or access the DOM itself programmatically and reveal its contents.
A Your concerns are well founded. Through debugging, someone could examine the contents of the DOM from the command window, provided they figure out from the script source how to reference its contents programmatically. For instance, if you have a global variable in your client-side script source
the user could set a breakpoint anywhere in the code, then type
var oDomDoc = new ActiveXObject("MSXML2.DOMDocument")
to view the entire contents of the document. Similarly, if you use XMLHTTP within the code to retrieve the XML doc, a user could potentially mimic the app's behavior and retrieve their personal XML doc (or worse yet, someone else's!) directly from the source, depending on how you've implemented that portion of the app.
If a DOMDocument object can access the data from script on the user's client machine, then that user can write their own script to access the data. In general, if there is any way to get (unencrypted) data on a machine, there is also a way to view it. The only secure way to handle this (until digital signatures, encryption, and so forth get integrated into XML) is to hide data on the server, and only transmit data that the user has permission to view.
Q When I browse to an HTML page that downloads XML/XSL and does a transform, there are security limitations around the script in the XSL. For example, the script cannot create a Scripting.FileSystemObject. If the XSL file is on the local machine, instead of an error, I get a dialog popping up asking if I want to allow the object to be created.
When using MSXML 3.0 to load and transform the XML/XSL, I don't get any error, and the object is created safely. Is there a way, programmatically, to ensure safety when using the DOM to do XSL transforms?
I get no error at all when using C++, calling CoCreateInstance to get my XMLDOMDocuments, and calling transformNodeToObject. It happens whether the XSL file comes from the local machine or over HTTP.
A An XSL script uses the same security settings as the browser (under Tools|Internet Options|Security in Internet Explorer) when it runs within the context of an HTML page. The mystery is what security settings apply when you run a transform on your local machine. In this case, the base URI of the style sheet that you loaded in the DOM determines what scripting permissions the XSL script has.
If you use the Msxml2.DOMDocument.3.0 object to load XSL, and you load it from an Internet path such as this
you will get an error if bad.xsl tries to instantiate any unsafe-for-scripting objects such as Scripting.FileSystemObject. This is because the base URI of the style sheet that you loaded in DOM is Internet zone and unsafe scripting objects are not allowed to run in this security zone.
These limitations are by design. Unless your C++ code tells the DOMDocument to be secure, the XSL will run any script. You need to QueryInterface the DOMDocument for IObjectSafety and call SetInterfaceSafetyOptions. In addition, you must provide a site for your DOMDocument. The Document will then ask the site for a secure base URL. There are several ways to pass the secureBaseURL from the site to the DOMDocument. The easiest way to do this is to use the built-in site functionality of the DOMDocument. Create a second DOMDocument and load a document. This will be your site. Pass this DOMDocument to the first DOMDocument via SetClientSite. Whatever URL has been loaded in the site document will be the secure base URL for the other document.
If you want to do more work, implement your own IOleClientSite and the DOMDocument will call GetMoniker.
Got a question? Send questions and comments to email@example.com.
| Thanks to the following Microsoft developers for their technical expertise: Aaron Averbuch, Harsha Bennur, Matthew Blain, Michael Brundage, Derek Denny-Brown, Erik Fuller, Matthew Goldberg, Dion Houston, Michael Howard, Paresh Joshi, Praj Joshi, Gurujeet Khalsa, Richie Lai, Anton Lapounov, Kalmadi Santhosh Rao, Arun Sacheti, David Schach, Daniel Simmons.|