This HttpModule encrypts and decrypts the query strings that are passed to pages with the URL. With a little help of Reflection (to hack the Request.QueryString collection) and Regular Expressions (to change the page links before they are sent to the client) these classes automatically encrypt and decrypt the parameters without any special code in the pages. Just use Respose.QueryString and write links like you usually do and the module will do the rest.
Installing the module
To add the module to a web application just copy the dll to its bin directory and add the module in the web.config file. You can also add the dll to the project references if you want or have to encrypt a query string in the application code.
<configuration> <system.web> ... ... ... <httpModules> <add type="Edanmo.Web.Security.QueryStringEncryptionModule,Edanmo.Web.QSE" name="QSE" /> </httpModules> </system.web> </configuration>
How it works
When the module it's initialized the code add handlers for two application events: PreRequestHandlerExecute and PostRequestHandlerExecute.
Private Sub Init(ByVal context As System.Web.HttpApplication) Implements IHttpModule.Init ' Set the handler for the PreRequestHandlerExecute event AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute ' Set the handler for the PostRequestHandlerExecute event AddHandler context.PostRequestHandlerExecute, AddressOf OnPostRequestHandlerExecute End Sub
The PreRequestHandlerExecute event is raised before the page handler is called and will be used to decrypt the query string sent to the page. PostRequestHandlerExecute is called after the page handler finishes and will be used to set a response filter which will find and encrypt the query strings that are in the response before it is sent to the client.
The OnPreRequestHandlerExecute method
As I said before, this method gets the encrypted query string and decrypts it. The interesting part of this is that the decrypted parameters are added to the QueryString collection, and is interesting because QueryString is a read-only collection! Here is were Reflection comes handy. Using Reflection we can access private members of a class and that's what the code does. It gets the private IsReadOnly property of the collection and sets it to false. After doing that we can add and remove values from it.
' Get the PropertyInfo for the NameValueCollection.IsReadOnly property Dim isReadOnly As PropertyInfo = queryCollection.GetType.GetProperty("IsReadOnly", _ BindingFlags.Instance Or BindingFlags.NonPublic) ' Set the query string collection to read/write isReadOnly.SetValue(queryCollection, False, Nothing)
After doing that the code decrypts the query string and adds each parameter to the collection and removes the encrypted one. At the end it sets the collection is set back to read-only.
The OnPostRequestHandlerExecute method
This method sets the response filter stream that will encrypt the query strings in the response before it is sent to the client. Before setting the filter it checks if the response content type is text/html to set the filter only for HTML content (you don't want binary data changed!).
' Get the application object Dim app As HttpApplication = CType(sender, HttpApplication) With app.Response ' Set the response filter stream if the ' content type is text/html If .ContentType.ToLower = "text/html" Then .Filter = New QueryStringEncryptionResponseFilter(.Filter) End If End With
The QueryStringEncryptionResponseFilter class
A response filter class is a class that inherits the System.IO.Stream class. Only the Write method is important for this module. It gets the data sent by the page handler, using three regular expressions (one for the action attribute of <form>, one for the src attribute of any tag and one for the href attribute of any tag) it finds the query strings and encrypts them and then write the data in the base stream.
Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) ' Get the HTML from the buffer Dim html As String = UTF8.GetString(buffer, offset, count) ' Encrypt the query string in the action attribute of forms html = _regexForm.Replace(html, AddressOf QueryStringMatchEvaluator) ' Encrypt the query string in the src attributes html = _regexSrc.Replace(html, AddressOf QueryStringMatchEvaluator) ' Encrypt the query string in the href attributes html = _regexHRef.Replace(html, AddressOf QueryStringMatchEvaluator) ' Write the new response to the base stream Dim buffer2() As Byte = UTF8.GetBytes(html) _stream.Write(buffer2, 0, buffer2.Length) End Sub