XML Signatures and References

Last week I showed a peculiar XML Signature that validates even though the containing document was changed. The reason is that the signature lacks References. Before explaining what’s wrong with the signature – and with the validation code, we’ll have a look at how XML Signatures work.

XML DSig Primer

XML in general is a powerful beast, with so many options available that it quickly gets really complex. The XML Digital Signatures standard is no exception to that. The extra features complexity of XML DSig compared to other signature standard is that one or more different blocks of data can be signed by the same signature block. That data can be the containing XML Document, part of an XML document or some other resource such as a web page. In this post we’ll only look at signing resources in the document containing the signature.

An Always Valid XML Signature

XML Signatures are powerful, but also a bit tricky to get right. Here’s a challenge: I have a signature that will validate, even though the contents of the XML document are altered.

This is the “magic” signature that validates regardless of what XML document it is placed in.

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
  </SignedInfo>
  <SignatureValue>ZlSHRu+tG6bVTPxyKvp2PcNqg+lVmBSB2TnzABa2eJZiFcIBtD4/0dhT8Mhr+TbcpzGTbPgMFOx1JmZzfQVzbcMUJfnU674C368VlULAnRa3Avqb+MNJWdAIT8cgdB1yJyZbtuChww13e2CMhikW+xZhaZFzD11KTKqiR+7DRcd+k026w7y6JYy/XgUkS3y1MzuUFO0Uk+tIKI2ik/iLH0XvO0TFO+5uLoz3VaVYj4BIgwFZlYFE/y36EVTeVC4fW7bxPiLdKfZNMin2ZpOusgr/Lyp+J5NQBUOV1FklGsHJbFLN7GJcaUBwnmAib8yReVmAIjsEWBRhB5b6TLojbw==</SignatureValue>
  <KeyInfo>
     <X509Data>
        <X509Certificate>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</X509Certificate>
     </X509Data>
  </KeyInfo>
</Signature>

I’ve made a small test program where I try it out.

Secure Account Activation with ASP.NET Identity

Distribution of credentials to new users of a system is often done in an insecure way, with passwords being sent over unsecure e-mail. With ASP.NET Identity, the password recovery functionality can be used to create a secure account activation mechanism.

The scenario for ASP.NET Identity, in the default MVC template is to let users self register. Then there are mechanisms to confirm the e-mail address, to make sure that the user actually is in control of the given e-mail address. There are also support for letting the user associate the account with external sign on solutions such as Google, Facebook and Twitter. That’s perfectly fine, but not for most applications I build.

I’m building line of business applications. They are actually often exposed on the Internet as they need to be available for partners. But, they are not meant to be available through self registration for anyone on the Internet. Those applications are invite only. That means that a user account is created for a new user. Then that user somehow has to be notified that the account has been created. The usual way to do that is to create the account, set a good password like “ChangeMe123” and send the user a mail with the new credentials. There are two problems with this

  1. A lot of users don’t get the hint and keep the “ChangeMe123” password.
  2. The e-mail can be sitting unread for a long time in the inbox, until someone gets hold of it – and the account.

Fortunately, there is a much more secure way to do account activation with ASP.NET Identity without much coding at all – by reusing the password recovery mechanism.

SAML2 for Thinktecture IdentityServer 3 with Kentor.AuthServices

Using the Kentor.AuthServices SAML2 Service Provider with Thinktecture IdentityServer 3 bridges the gap between SAML2 and OAuth2/OpenID Connect. Thinktecture IdentityServer 3 support clients using the modern OAuth2 and OpenID Connect protocols. It can either have a local account database through e.g. ASP.NET Identity, or use external authentication services. By registering Kentor.AuthServices with IdentityServer, IdentityServer can authenticate to a SAML2 Idp.

I know that SAML2 is often regarded as legacy, but the truth is that there is still vast amounts of infrastructure out there that supports SAML2, but has not yet taken the leap to OpenID Connect. When the client applications prefer modern standards, a bridge between them is needed. With Kentor.AuthServices, Thinktecture IdentityServer can be that bridge.

Get It Running

To add SAML2 to IdentityServier, changes are needed in three places: Installing the Kentor.AuthServices.Owin package, alter the startup configuration method for IdentityServer and add two lines to the web/app.config file.

Catching the System.Web/Owin Cookie Monster

CookieMonster-SittingCookies set through the Owin API sometimes mysteriously disappear. The problem is that deep within System.Web, there has been a cookie monster sleeping since the dawn of time (well, at least since .NET and System.Web was released). The monster has been sleeping for all this time, but now, with the new times arriving with Owin, the monster is awake. Being starved from the long sleep, it eats cookies set through the Owin API for breakfast. Even if the cookies are properly set, they are eaten by the monster before the Set-Cookie headers are sent out to the client browser. This typically results in heisenbugs affecting sign in and sign out functionality.

TL;DR

The problem is that System.Web has its own master source of cookie information and that isn’t the Set-Cookie header. Owin only knows about the Set-Cookie header. A workaround is to make sure that any cookies set by Owin are also set in the HttpContext.Current.Response.Cookies collection.

This is exactly what my Kentor.OwinCookieSaver middleware does. It should be added in to the Owin pipeline (typically in Startup.Auth.cs), before any middleware that handles cookies.

app.UseKentorOwinCookieSaver();

The cookie saver middleware preserves cookies set by other middleware. Unfortunately it is not reliable for cookies set by the application code (such as in MVC Actions). The reason is that the System.Web cookie handling code might be run after the application code, but before the middleware. For cookies set by the application code, the workaround by storing a dummy value in the sessions is more safe.

Software Development is a Job – Coding is a Passion

I'm Anders Abel, an independent systems architect and developer in Stockholm, Sweden.

profile for Anders Abel at Stack Overflow, Q&A for professional and enthusiast programmers

Code for most posts is available on my GitHub account.

Popular Posts

Archives

Series

Powered by WordPress with the Passion for Coding theme.