July 0931

ASP.NET Forms Authentication with ReturnURL

I’ll start with a question, how do you get values from the QueryString? I’ve always used Request.QueryString(“NameOfMyParameter”) so when I needed to access a value from the querystring in something I’m working on at the moment didn’t give it a second thought – I’ll just use my trusty friend and get on with the next thing. It didn’t turn out quite as trouble free as that.

The site I’m working on uses ASP.NET Forms Authentication and so when a user is not authenticated they are redirected to Login.aspx, the page they were on and anything in the querystring is encoded and sent along to the login page in the ReturnUrl parameter so that after successful authentication and redirecting back to the original page their querystring values are intact. If you think about it this makes perfect sense, if the page you are on is using the querystring for paging and you’re on page 10 then simply because you’ve timed out shouldn’t mean that you have to start at page 1 again. In my case http://localhost:43751/Default.aspx?id=H1234 will redirect the user to http://localhost:43751/Login.aspx?ReturnUrl=%2fDefault.aspx%3fid%3dH1234 and on the Login page I need to check the id value. As I said at the beginning, sounds simple right. Wrong. It isn’t very obvious why when the url is encoded but Server.UrlDecode(Request.RawUrl) results in /Login.aspx?ReturnUrl=/Default.aspx?id=H1234 – notice the second question mark? Request.QueryString doesn’t get as far as that so never sees the id value.

Still I needed to get to the value in the id parameter so resorted to writing a dirty little method to let me get at querystring values passed in this way.

Private Function GetParam(ByVal paramName As String, ByVal paramMaxLength As Integer) As String
    Dim paramValue As String = String.Empty
    Dim url As String = Server.UrlDecode(Request.RawUrl())

    If Not url.Contains(paramName) Then
        Return paramValue
    End If

    url = url.Substring(url.LastIndexOf("?") + 1)
    ExtractParamValue(paramName, paramValue, url)

    If paramValue.Length > paramMaxLength Then
        paramValue = paramValue.Remove(paramMaxLength)
    End If

    Return paramValue
End Function

It works by decoding the url and then checking to see whether the required querystring key value exists. If it does it cuts out anything before the second question mark then splits the remaining string at ampersands and then looks for the key. If it finds it the value is stored in paramValue which is then sanitised (to some degree) by truncating anything longer than the expected length. It isn’t perfect, but it should prevent the querystring being abused and malicious values passed through it.

I refactored ExtractParamValue out to its own method:

Private Shared Sub ExtractParamValue(ByVal paramName As String, ByRef paramValue As String, ByVal url As String)
    For Each valuePair As String In url.Split("&")
        If valuePair.StartsWith(paramName) Then
            paramValue = valuePair.Substring(paramName.Length + 1)
        End If
    Next
End Sub

I recognise that there are quite a few limitations to this approach but I needed to get this done and move on. I really hadn’t counted on it taking me any more than a few seconds to get to the value and it took me a lot longer. If anyone knows any better approach please use the comments!

Permalink | Comments (0)
Comments are closed