Search code examples
c#obfuscationhttpmodulespam-prevention

HTTPModule Issue: Replacing Text On Page Render


I am writing an HTTPModule that will search out all mailto links in a webpage, obfuscate the email address and trailing parameters and then place the newly obfuscated string back into the HTML document. I then use a little JavaScript to un-obfuscate the mailto link in the browser so that it will behave properly when the user clicks the link.

So far, I have successfully obfuscated and un-obfuscated the information with no problems. The issue that I am running into is the placement of the obfuscated strings back into the stream. If a mailto link only appears once in a document, then it perfectly places the obfuscated string in place of the mailto link, but if there are more than one mailto link, the placement of the strings is seemingly random. I’m pretty sure it has to do with the position of the regex match indexes as the function loops through the matches and basically increases the length of the HTML coming through the stream. I’m going to post some strategically-edited code here to see if anyone has an idea on how to correctly target the placement of the obfuscated string.

I'm also posting the work I did to obfuscate the string in the hopes that it might help someone trying to do the same thing.

public override void Write(byte[] buffer, int offset, int count)
  {
      byte[] data = new byte[count];
      Buffer.BlockCopy(buffer, offset, data, 0, count);
      string html = System.Text.Encoding.Default.GetString(buffer);

      //--- Work on the HTML from the page. We want to pass it through the 
      //--- obfusication function before it is sent to the browser.
      html = html.Replace(html, obfuscate(html));

      byte[] outdata = System.Text.Encoding.Default.GetBytes(html);
      _strmHTML.Write(outdata, 0, outdata.GetLength(0));
  }


protected string obfuscate(string input)
    {

      //--- Declarations
      string email = string.Empty;
      string obsEmail = string.Empty;
      string matchedEMail = string.Empty;
      int matchIndex = 0;
      int matchLength = 0;

      //--- This is a REGEX to grab any "a href=mailto" tags in the document.
      MatchCollection matches = Regex.Matches(input, @"<a href=""mailto:[a-zA-Z0-9\.,|\-|_@?= &]*"">", RegexOptions.Singleline | RegexOptions.IgnoreCase);

      //--- Because of the nature of doing a match search with regex, we must now loop through the results
      //--- of the MatchCollection.
        foreach (Match match in matches)
        {

            //--- Get the match string
            matchedEMail = match.ToString();
            matchIndex = match.Index;
            matchLength = match.Length;

            //--- Obfusicate the matched string.
            obsEmail = obfusucateEmail(@match.Value.ToString());

           //--- Reform the entire HTML stream. THis has to be added back in at the right point.
           input = input.Substring(0, matchIndex) + obsEmail + input.Substring(matchIndex + matchLength);                 
        }

      //--- Return the obfuscated result.
      return input;
    }



protected string obfusucateEmail(string input)
  {

      //--- Declarations
      string email = string.Empty;
      string obsEmail = string.Empty;

      //--- Reset these value, in case we find more than one match.
      email = string.Empty;
      obsEmail = string.Empty;

      //--- Get the email address out of the array
      email = @input;

      //--- Clean up the string. We need to get rid of the beginning of the tag, and the end >. First,
      //--- let's flush out all quotes.
      email = email.Replace("\"", "");

      //--- Now, let's replace the beginning of the tag.
      email = email.Replace("<a href=mailto:", "");

      //--- Finally, let's get rid of the closing tag.
      email = email.Replace(">", "");


      //--- Now, we have a cleaned mailto string. Let's obfusicate it.
      Array matcharray = email.ToCharArray();

      //--- Loop through the CharArray and encode each letter.
      foreach (char letter in matcharray)
      {
          //Convert each letter of the address to the corresponding ASCII code.
          //Add XX to each value to break the direct ASCII code to letter mapping. We'll deal
          // with subtracting XX from each number on the JavaScript side.
          obsEmail += Convert.ToInt32((letter) + 42).ToString() + "~";
      }

      //--- Before we return the obfusicated value, we need to reform the tag.
      //--- Remember, up above, we stripped all this out. Well now, we need 
      //--- to add it again.
      obsEmail = "<a href=\"mailto:" + obsEmail + "\">";

      return obsEmail;
  }

I appreciate any ideas!

Thanks, Mike


Solution

  • Another thing you can do is use the match evaluator in your regex ....

    protected string ObfuscateUsingMatchEvaluator(string input)
    {
                var re = new Regex(@"<a href=""mailto:[a-zA-Z0-9\.,|\-|_@?= &]*"">",            RegexOptions.IgnoreCase | RegexOptions.Multiline);
                return re.Replace(input, DoObfuscation);
    
    }
    
    protected string DoObfuscation(Match match)
    {
           return obfusucateEmail(match.Value);
    }