Today I had another trivial problem that was unbelievably hard to debug just because I could not tell that an error caused by a web resource was caused by exactly that resource. I was dealing with a forgotten [WebResource] attribute that did not have a matching resource built in the assembly and both generated a server side exception and gave browsers a 404 HTTP error.

I wanted to decrypt the query string data that was being passed to WebResource.axd and extract the resource and assembly name from it. MSDN told me that what I needed was the "d" query string parameter, as it contained the encrypted assembly and resource name. The "t" attribute is the assembly time stamp, it is there, so that we have a different URL when we upgrade the assembly and our clients do not cache and use the old web resources.

Back to decrypting that string. I noticed that it was being encrypted using the MachineKeySection.EncryptOrDecryptData() method, so we can easily decrypt that. Unfortunately, the method is declared internal. That should not be allowed to stop us, should it? Here goes the code:

=======================================

        byte[] encryptedData = HttpServerUtility.UrlTokenDecode(urlEncodedData);

        Type machineKeySection = typeof(MachineKeySection);
        Type[] paramTypes = new Type[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) };
        MethodInfo encryptOrDecryptData = machineKeySection.GetMethod("EncryptOrDecryptData", BindingFlags.Static | BindingFlags.NonPublic, null, paramTypes, null);

        try
        {
            byte[] decryptedData = (byte[])encryptOrDecryptData.Invoke(null, new object[] { false, encryptedData, null, 0, encryptedData.Length });
            string decrypted = Encoding.UTF8.GetString(decryptedData);

            decryptedLabel.BackColor = Color.Lime;
            decryptedLabel.Text = decrypted;
        }
        catch (TargetInvocationException)
        {
            decryptedLabel.BackColor = Color.Red;
            decryptedLabel.Text = "Error decrypting data. Are you running your page on the same server and inside the same application as the web resource URL that was generated?";
        }

=======================================

The tricky part is that we use the MachineKeySection class to do our job and we deal with encryption settings specific to the current application. This means that decrypting web resource URL will work if and only if you run the code on the same server and from the same web application that generated the resource.

I am attaching a standalone page that you can drop in your application’s root and request it. You can then paste a web resource URL in the text box and decrypt it. You can even drop controls on the page and the dropdown will be automatically filled with all registered scripts and stylesheets served from web resources. Happy hacking!


rahnev
About the Author

Stefan Rahnev

Stefan Rahnev (@StDiR) is Product Manager for Telerik Kendo UI living in Sofia, Bulgaria. He has been working for the company since 2005, when he started out as a regular support officer. His next steps at Telerik took him through the positions of Technical Support Director, co-team leader in one of the ASP.NET AJAX teams and unit manager for UI for ASP.NET AJAX and Kendo UI. Stefan’s main interests are web development, agile processes planning and management, client services and psychology.

Related Posts

Comments