Search code examples
asp.net-mvcbase64url-encoding

Unable to decode Base-64 URLs


I have an application that builds an HTML email. Included in the content is an encoded URL parameter that might, for example, contain a promotional code or product reference. The email is generated by a Windows service (essentially a console application) and the link, when clicked is handled by an MVC web site. Here is the code for creating the email link:

string CreateLink(string domain, string code) {
    // code == "xyz123"
    string encrypted = DES3Crypto.Encrypt(code);  // H3uKbdyzrUo=
    string urlParam = encrypted.EncodeBase64();   // SDN1S2JkeXpyVW890
    return domain + "/" + urlParam;
}

The action method on the MVC controller is constructed as follows:

public ActionResult Index(string id) {
    string decoded = id.DecodeBase64();
    string decrypted = DES3Crypto.Decrypt(decoded);
    ...
}

In all our testing, this mechanism has worked as expected, however, now we have gone live we are seeing around a 4% error rate where the conversion from base-64 fails with the following exception:

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters.

The id parameter from the url 'looks' OK. The problem appears to be with the EncodeBase64/DecodeBase64 methods that are failing as DecodeBase64 method returns a 'garbled' string such as "�nl����□��7y�b�8�sJ���=" on the failed links.

Furthermore, most of the errors are from IE6 user agents leading me to think this is a character encoding problem but I don't see why.

For reference, here is the code for my base-64 URL encoding:

  public static string EncodeBase64(this string source)
  {
     byte[] bytes = Encoding.UTF8.GetBytes(source);
     string encodedString = HttpServerUtility.UrlTokenEncode(bytes);
     return encodedString;
  }

  public static string DecodeBase64(this string encodedString)
  {
     byte[] bytes = HttpServerUtility.UrlTokenDecode(encodedString);
     string decodedString = Encoding.UTF8.GetString(bytes);
     return decodedString;
  }

Any advice would be much appreciated.


Solution

  • To recap, I was creating a URL that used a base-64 encoded parameter which was itself a Triple DES encrypted string. So the URL looked like http://[Domain_Name]/SDN1S2JkeXpyVW890 The link referenced a controller action on an MVC web site.

    The URL was then inserted into an HTML formatted email. Looking at the error log, we saw that around 5% of the public users that responded to the link were throwing an "invalid base-64 string error". Most, but not all, of these errors were related to the IE6 user agent.

    After trying many possible solutions based around character and URL encoding, it was discovered that somewhere in the client's process the url was being converted to lower-case - this, of course, broke the base-64 encoding (as it is uses both upper and lower case encoding characters).

    Whether the case corruption was caused by the client's browser, email client or perhaps local anti-virus software, I have not been able to determine.

    The Solution Do not use any of the standard base-64 encoding methods, instead use a base-32 or zBase-32 encoding instead - both of which are case-insensitive.

    See the following links for more details

    Base-32 - Wikipedia

    MyTenPennies Base-32 .NET Implementation

    The moral of the story is, Base-64 URL encoding can be unreliable in some public environments. Base-32, whilst slightly more verbose, is a better choice.

    Hope this helps.