Browsing Posts published in July, 2005

While simultaneously mucking around with the Indigo RC1 bits, I decided to upgrade to DasBlog 1.8 RC1 and kick the tires. (If my OS can multitask, why can’t I?) Very easy upgrade with some nifty goodies. Great job on the new release to Scott, Omar, and the rest of the DasBlog team!


I also decided to change my blog layout to the new “Portal”, which mimics the look and feel of Windows SharePoint Portal. Thanks to Johnny Hughes for the new theme.

You have an ASP.NET application running on your Windows Server 2003 and you’re merrily logging events to the Application Event Log (or any event log for that matter). Then you upgrade to Windows Server 2003 SP1 and see something like this:



Security Exception


Description: The application attempted to perform an operation not allowed by the security policy. To grant this application the required permission please contact your system administrator or change the application’s trust level in the configuration file.


Exception Details: System.Security.SecurityException: Requested registry access is not allowed.


Source Error:


An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. 


Stack Trace:


[SecurityException: Requested registry access is not allowed.]
   Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable) +473
   System.Diagnostics.EventLog.CreateEventSource(String source, String logName, String machineName, Boolean useMutex) +443
   System.Diagnostics.EventLog.WriteEntry(String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData) +348
   System.Diagnostics.EventLog.WriteEntry(String message, EventLogEntryType type, Int32 eventID, Int16 category) +21
   AspNetTest.WebForm1.Page_Load(Object sender, EventArgs e) in c:\dev\aspnettest\webform1.aspx.cs:23
   System.Web.UI.Control.OnLoad(EventArgs e) +67
   System.Web.UI.Control.LoadRecursive() +35
   System.Web.UI.Page.ProcessRequestMain() +2112
   System.Web.UI.Page.ProcessRequest() +218
   System.Web.UI.Page.ProcessRequest(HttpContext context) +18
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() +179
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +87


What happened? The problem is caused by Microsoft tightening up security around the event logs in Windows Server 2003 SP1. (See the section entitled “Tighter ACLs on Event Logs”.)Tightening security is a good idea, but logging events to the event log from an ASP.NET application is a rather common thing to do. So how do we re-enable the ability of ASP.NET to write to the event log?


I have seen information on the web, the sources of which shall remain nameless to protect the seriously misled, that basically tells you to modify your ASP.NET process identity in machine.config from machine to system so that your application can write to the event log. What a collosally bad idea! What’s so bad about this? Imagine that you’re going away for holidays and you ask a friend to water your plants. You realize that your friend cannot open the locked front door. So what do you do? You leave the door unlocked for two weeks while you’re away. That way your friend can get in and water the plants. Does this sound reasonable to you? Of course not. You give your friend a key to get into the house.


So how do you give ASP.NET a key to the event log? I’m glad you asked. There is a custom security descriptor on each event log that determines which users can access that particular event log. Where is this custom security descriptor stored? In the registry of course. So fire up regedt32 and browse to the following registry key:


HKLM\SYSTEM\CurrentControlSet\Services\EventLog\{logName}\CustomSD


where {logName} is Application in our case. You should see a string value that looks like:


O:BAG:SYD:(D;;0xf0007;;;AN)(D;;0xf0007;;;BG)(A;;0xf0007;;;SY)(A;;0×7;;;BA)(A;;0×7;;;SO)(A;;0×3;;;IU)(A;;0×3;;;SU)(A;;0×3;;;S-1-5-3)


What the heck is this? It’s Security Descriptor Description Language (SDDL), my dear Watson. SDDL is a text-based (and human authorable, believe it or not) representation of a security descriptor.


What does it mean in simple terms? The first part is some general information about the security descriptor:












O:BA Object owner is built-in administrators
G:SY Primary Group is SYSTEM
D: This is a discretionary access control list (DACL) as opposed to a SACL or audit entry

Next come the access control entries (ACE). I’ll only talk about the fields needed for the custom security descriptor on the event logs. You can find full information about the ACE format here. First is allow (A) or deny (D). Hex number in the middle is a permissions bitmask:















0×1 READ
0×2 WRITE
0×4 CLEAR
0xf000 DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER

Last comes the SID, which has abbreviated forms for most common built-in accounts.


So here are the ACEs:
























(D;;0xf0007;;;AN) Deny everything to Anonymous
(D;;0xf0007;;;BG) Deny everything to Builtin Guests
(A;;0xf0007;;;BA) Allow everything to Builtin Administrators
(A;;0×7;;;SO) Allow read, write, and clear to Server Operators
(A;;0×3;;;IU) Allow read and write to Interactive Users
(A;;0×3;;;SU) Allow read and write to Service Accounts*
(A;;0×3;;;S-1-5-3) Allow read and write to Batch Accounts*

* These two are not an actual groups, but are flags in the security token, which can be configued by local or group security policy.


You’ll notice that Network Service isn’t mentioned anywhere on that list. Simply add (A;;0×3;;;NS) to the end of the list and Network Service will be permitted read and write access to the event log. Note that if you are using impersonation (<identity impersonate=”true” /> in your web.config), the event log access will be done under the credentials of the impersonated user. In this case, you’ll want to permit authenticated users read and write access, which can be done using (A;;0×3;;;AU). You should now be merrily writing to the event logs from your ASP.NET applications with your security intact.


Afterword: After writing this blog post, I discovered that Dominick Baier has a blog entry about the same problem. Dominick is extremely knowledgeable about all things security on the Windows platform. If you haven’t subscribed to his RSS feed, do so now!


Edit: I originally attributed the information on http://www.leastprivilege.com to Keith Brown. I feel so embarassed. Keith’s blog is http://www.pluralsight.com/blogs/Keith. Both Keith and Dominick are definitely Windows security gurus. I highly recommend subscribing to both of their blogs! Sorry, guys!


How to Reproduce this Error


To reproduce the problem, create a new event source called “AspNetTest” that can write to the local Application log by running the following code in a console app as a local administrator:

string sourceName = “AspNetTest”;
string logName = “Application”;
string machineName = “.”;
if(!EventLog.SourceExists(sourceName, machineName)) {
EventLog.CreateEventSource(sourceName, logName, machineName);
}
Create an ASP.NET web application using the wizard and add the following two lines to Page_Load of WebForm1:
private void Page_Load(object sender, System.EventArgs e) {
EventLog log = new EventLog(“Application”, “.”, “AspNetTest”);
log.WriteEntry(“Writing from AspNetTest application”, EventLogEntryType.Information, 42, 42);
}

When run on Windows Server 2003 SP1, you will see a security exception like the one above. Modify the CustomSD on the Application event log and browse to WebForm1.aspx again. The web application will successfully write into the event log, which you can verify using the Event Viewer.

I get this question relatively frequently:

“I need to send binary data in my SOAP message. What is the recommended way of doing this?”

(I’ll admit that I’m a bit late to the party on this one. Most of the information below is summarized from the referenced sources near the end of this post.)

You can always Base-64 encode the binary data, but this has a number of undesirable consequences including the encoding/decoding costs at the endpoints and a 33% size bloat on the wire. It does have the advantage that all the WS-* specs work with it.

So the next obvious question is how can I send the binary data as binary? This leads us to SOAP attachments. Unfortunately the SOAP attachments space is somewhat fragmented at the moment. The current options are:

  • SwA (SOAP with Attachments)
  • DIME (Direct Internet Message Encapsulation) (AKA WS-Attachments)
  • PASwA (Proposed Infoset Addendum to SOAP Messages with Attachments)
  • MTOM (Message Transmission Optimisation Mechanism)

All of these techniques send the attachments using MIME or a MIME-like mechanism. DIME adds record lengths to MIME for quick lookup of binary data. Unfortunately with SwA and DIME, the attachments are not part of the XML InfoSet, which means that you cannot apply the WS-* specs to them. (Probably most notable and serious is WS-Security. Using SwA or DIME, you can sign and/or encrypt parts of the SOAP message, but you cannot sign or encrypt the attachments. You can make guarentees that the message has not been tampered with, but you cannot make those same guarentees about the attachments.)

PASwA and MTOM solve this problem using an include element to incorporate the attachment into the XML Infoset. There seems to be general agreement that the way forward is MTOM. MTOM will be available with WSE 3.0 and Indigo. (WSE 3.0 is currently available as a CTP and Indigo is a Beta1 RC.)

So what should I do in the meantime? If you’re dealing with relatively few small binary attachments, Base-64 encoding seems to be the way to go. The extra 33% size and encoding/decoding costs probably won’t matter much to you.* On the plus side, you get to use all those snazzy WS-* specs. If you’re processing large numbers of messages and/or your attachments are large, the extra 33% size and encoding/decoding costs probably matter to you.* So you’ll have to use WSE 2.0 and DIME or roll your own SwA implementation (as Microsoft does not have an implemenation of SwA). Be aware that any WS-* goo that you apply will not work on the attachments. So don’t go sending images of bank statements via SwA or DIME!

* As with all things perf-related, measure, measure, measure. Don’t assume that Base-64 encoding is too slow for your situation and write a pile of extra encryption code for DIME attachments. Establish some performance criteria and measure against it. Then make an educated decision as to the solution architecture.

Here are some background articles that were good reads on the topic:

And don’t forget to catch John Bristowe‘s GrokTalk on MTOM in WSE 3.0:

Edit: Corrected wonky links and strange HTML formatting.