Why I use IE8

Let’s be clear I like Internet Explorer.

I use IE8 and I have to hear jokes and all kind of comments because of it. Before I joined Microsoft I was arguing for a while until get tired of the conversation, moment where I ended always with a “yeah … it is”. Things like “but IE is not compatible with CSS standards” were very common to hear.  No, please don’t go again into that, it’s clear there is still lot of improvements that can be done for standard compliance. In any case, IE8 is 100% compliant with CSS Level 2 Revision 1.

But after I joined Microsoft the comments were getting worse and stimulating for the conversation, ridiculous things like “but you use it because Microsoft does not allow other browsers to be installed”, not worthy to say that is far away from reality.

Now that there has been the famous attack to Google using an exploit of IE some comments have reached insanity levels.

If you want full information about the exploit and the solution go to The Microsoft Security Response Center (MSRC). I just want to stand up that “to date, the only successful attacks reported have been against Internet Explorer 6” (which is a 9 years old browser). Users with XP (more than 8 years old OS) were more prone to suffer this exploit because XP does not take profit of Address Space Layout Randomization (ASLR), Vista and other later versions are more effective blocking the exploit because they take profit of the improved security protection offered by ASLR.

So, we have that people using a 9 years old browser on an 8 years old OS were the biggest victims. I’m not going to comment about this, just take a look to this video and think about it yourself  … security, hacking attacks, technology … all evolves and, don’t be fool, ALL of us are also responsible for our self-protection.

Whether you like it or not Internet Explorer is one the safest browsers of the market. You can do the comparison by:

1. Technologies applied: DEP, ASLR, Virtual Store, Mandatory Integrity Control, Today IE8 is the only one making use of all these technologies. I have to mention too the Cross Site Scripting filter and the Private Browsing, also known as porn mode but pretty useful and recommended when you browse from airports, Internet points and any other kind of shared computer.

2. Phishing protection: “The average phishing URL catch rate for browsers

Mean block rate for phishing

3. Average time to block phishing: “how long on average must a user wait until a requested phishing URL is added to the block list?”

Browser add time

Worthy to mention that “phishing sites have an average life expectancy of only 52 hours mmm…sigh… Thanks Safari 4 to protect me against phishing sites that no longer exist.

Source: NSS Labs Browser Security – Phishing Q3 2009

“but Everybody recognizes a phishing site”. According to Gartner Group “theft through phishing activities costs U.S. banks and credit card issuers an estimated $2.8 billion annually”

4. Vulnerabilities:

but regardless phishing Firefox is the safest browser

Vulnerabilities by browser 2008

Source: http://secunia.com/gfx/Secunia2008Report.pdf

I couldn’t find the 2009 report so I went manually product per product drilling by version in the Secunia site to get overall vulnerabilities.

Browser Vulnerabilities Release Date Market Share
IE 6.x 184 8/27/2001 20.99%
FireFox 3.0.x 144 6/17/2008 6.91%
IE 7.x 106 10/18/2006 15.53%
FireFox 3.5.x 48 6/30/2009 16.32%
IE 8.x 30 3/19/2009 20.86%
Safari 4.0 16 6/2/2008 3.45%
Chrome 3.x 5 10/12/2009 3.75%

 

As you can see Firefox 3.0.x has had more vulnerabilities in 19 months than IE 7.x in more than 3 years and almost the same than IE6 in more than 8 years. I’m not going to comment about Firefox 1.0.x, which had 209 known vulnerabilities since 11/9/2004 and has a current share of 0.03%.

Vulnerabilities Source: http://secunia.com/advisories

Release date Source: http://www.wikipedia.org

Market Share Source: Market Share Browsers.

but …” Before you mention that Safari and Chrome have less vulnerabilities, please review again the Market Share and Release Date and remember that massive attacks are like business: You always try to maximize benefits, if with one product (exploit) you can reach 60% of market you don’t put all your efforts trying to get 5%.

I’m not going to enter into specific features of IE8 that facilitates the administrator’s work in corporations like: the possibility to manage and configure nearly 1.500 built-in group policies, the IEAK for customization, distribution of updates and patches via Window Server Update Services

So, yes I’m very proud to say I’m a IE8 user … “but browser %replace with your browser% it’s faster” … Yeah…it is

Signing with Certificates

Recently, I recorded a Spanish video about how to encrypt/sign information using certificates and I thought it would be nice to write also a post about it. The thing is that when I tried to post it I received an alert about having a post with the same title, I already wrote the post Encrypting with Certificates more than two years ago :(, so while I try to figure out why I have this memory leak in my brain I will write only the missed part: how sign data using X509 certificates.

Since we already have in the previous post the code to load certificates we will focus on two methods Sign and VerifyHash.

   1:  public static byte[] Sign(byte[] hash, 
   2:      X509Certificate2 certificate)
   3:  {
   4:      if (hash == null)
   5:      {
   6:          throw new ArgumentNullException("hash");
   7:      }
   8:      if (certificate == null)
   9:      {
  10:          throw new ArgumentNullException("certificate");
  11:      }
  12:   
  13:      using (RSACryptoServiceProvider provider = 
  14:          new RSACryptoServiceProvider())
  15:      { 
  16:          provider.FromXmlString(
  17:              certificate.PrivateKey.ToXmlString(true));
  18:          return provider.SignHash(
  19:              hash,
  20:              CryptoConfig.MapNameToOID("SHA1"));
  21:      }  
  22:  }
  23:   
  24:  public static bool VerifyHash(byte[] hash, byte[] signature, 
  25:      X509Certificate2 certificate)
  26:  {
  27:      if (hash == null)
  28:      {
  29:          throw new ArgumentNullException("hash");
  30:      }
  31:      if (signature == null)
  32:      {
  33:          throw new ArgumentNullException("signature");
  34:      }
  35:      if (certificate == null)
  36:      {
  37:          throw new ArgumentNullException("certificate");
  38:      }
  39:   
  40:      using (RSACryptoServiceProvider provider = 
  41:          new RSACryptoServiceProvider())
  42:      {
  43:          provider.FromXmlString(
  44:              certificate.PublicKey.Key.ToXmlString(false));
  45:          return provider.VerifyHash(
  46:              hash, 
  47:              CryptoConfig.MapNameToOID("SHA1"), 
  48:              signature);
  49:      }
  50:  }

The idea behind these two methods is the next:

We have one party A who needs to send a message to B. B wants to be sure that the messaged received has not been modified by a third party C. To do that, A will create a digital signature that will be sent together with the message. To generate the signature A needs to compute a hash of the message, this hash is then used with method "Sign". Once A has the signature he can transmit the message and the signature to B.

When B receives the message and the signature, B needs to verify the hash. So, B computes again a hash of the received message and uses the method VerifyHash, which will return true if the message has not been modified. The next code shows you an example on how to call both methods.

   1:  static void Main(string[] args)
   2:  {
   3:      string certificateName = "Test";
   4:   
   5:      X509Certificate2 cert = LoadCertificate(
   6:          StoreName.My, 
   7:          StoreLocation.LocalMachine, 
   8:          certificateName);  
   9:      
  10:      byte[] messageSent = 
  11:          UTF8Encoding.UTF8.GetBytes("Message sent from A to B");
  12:   
  13:      // A generates the signature before send to B
  14:      SHA1Managed sha1 = new SHA1Managed();
  15:      byte[] hashA = sha1.ComputeHash(messageSent);
  16:      byte[] signature = Sign(hashA, cert);
  17:   
  18:      // B receives the message and the digital signature
  19:      byte[] messageReceived = 
  20:          UTF8Encoding.UTF8.GetBytes("Message sent from A to B");
  21:      //byte[] messageReceived = 
  22:      //  UTF8Encoding.UTF8.GetBytes("Message hacked by C");
  23:   
  24:      byte[] hashB = sha1.ComputeHash(messageReceived);
  25:   
  26:      if (VerifyHash(hashB, signature, cert))
  27:      {
  28:          Console.WriteLine("Verified");
  29:      }
  30:      else
  31:      {
  32:          Console.WriteLine("Not verified");
  33:      }
  34:   
  35:      Console.ReadKey();
  36:  }

This piece of code using the rest of methods mentioned shows you how we can verify a message has not been altered during the transmission. If you comment lines 19,20 and uncomment 21,22 you will see that after message has been altered the hash cannot be validated anymore. These short methods are one the basis of security when we try to guarantee information is not being altered from origin to destine. We have used a very basic message, but imagine you have an online shop and you don´t want people can alter from the message the number of items that will be delivered after you have authorized a payment.

Checking similar methods like SignData and VerifyData will be left as an exercise for the reader.

Google Safe Browsing API with Internet explorer

These days lot of bloggers have been writing about the new API of Google: Google Safe Browsing API. The Safe Browsing API is an experimental API that enables client applications to check URLs against Google's constantly updated blacklists of suspected phishing and malware pages.

I think this is a cool API and if you want to take profit of it you already have it with FireFox. But, I like Internet Explorer so I would like to use both together.

If you take a look to the documentation, you will see that its usage is actually very easy. The idea is that you get a list of URL hashes, which are marked as phishing or malware; then you only need to validate the URL's you want to check against these hash tables. I'm not going to enter in too much details since you can read the guide that Google provides you.

What I've done is let's say: a  "proof of concept", that it's possible to use Google Safe Browsing with IE. I've built an implementation of this using C#.  The code you can download consists in two main parts:

  • A Windows Service that hosts a WCF Service with the logic to perform updates and the validation against the hash tables.
  • An BHO (Browser Helper Object) that queries the information to the WCF Service.

The BHO is configured as an add-on for IE. It just handles the BeforeNavigate2 event and checks the URL making a call to the published service, if the URL is safe then nothing happens otherwise the navigation is canceled and the message displayed:

Malware screenshot

The code for the BHO is pretty simple, the first you need to do is to declare the interface IObjectWithSite to make available for .NET

   1: [ComImport]
   2: [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   3: [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")]
   4: public interface IObjectWithSite
   5: {
   6:     void SetSite([In, MarshalAs(UnmanagedType.IUnknown)] Object pUnkSite);
   7:     void GetSite(ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out Object ppvSite);
   8: }

The other interesting part of it, is how to cancel the navigation and modify the HtmlDocument, with our custom html.

   1: void webBrowser_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
   2: {
   3:     ....
   4:  
   5:     if (result == UrlValidationResult.Malware || result == UrlValidationResult.BlackList)
   6:     {
   7:         IHTMLDocument2 doc = webBrowser.Document as IHTMLDocument2;
   8:  
   9:         if (doc != null)
  10:         {
  11:             doc.clear();
  12:             doc.writeln(result == UrlValidationResult.Malware ? Resources.MalwareWarning : Resources.BlackWarning);
  13:             doc.close();
  14:         }
  15:  
  16:         Cancel = true;
  17:     }
  18: }

The WCF Service exposes only two methods: "public void Update()" and "public UrlValidationResult ValidateUrl(Uri uri)". This service what it does is to obtain and keep updated the hash tables doing incremental updates, as well as the logic to validate the URL's against these tables. The tables are stored in an IsolatedStorage to avoid obtaining them from Internet every time, nevertheless the tables are loaded and operated in memory.

In order to validate a URL you need to perform some steps, first of all you need to obtain a 128 bit MD5 Hash of the URL you want to check, then you need to get the string representation of this hash. With .NET you can accomplish this easily.

   1: private string GetHash(string url)
   2: {
   3:     byte[] hashBytes;
   4:     using (MD5 md5 = MD5.Create())
   5:     {
   6:         hashBytes = md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(url));
   7:     }
   8:  
   9:     StringBuilder sb = new StringBuilder(32);
  10:  
  11:     int length = hashBytes.Length;
  12:     for (int i = 0; i < length; i++)
  13:     {
  14:         sb.Append(hashBytes[i].ToString("x2"));
  15:     }
  16:  
  17:     return sb.ToString();
  18: }

Google suggest you also to perform several lookups from the same URL to get an accurate result, which consists of: the exact hostname in the URL, up to 4 hostname's formed by starting with the last 4 components and successively removing the leading component. In addition for the path you should try at most 6 different strings: the exact path of the URL, including query parameters; the exact path of the URL, without query parameters and the 4 paths formed by starting at the root (/) and successively appending path components, including a trailing slash. A sample displays better what this means.

For the URL http://a.b.c.d.e.f.g/1.html

a.b.c.d.e.f.g/1.html

a.b.c.d.e.f.g/

c.d.e.f.g/1.html

c.d.e.f.g/

d.e.f.g/1.html

d.e.f.g/

e.f.g/1.html

e.f.g/

f.g/1.html

f.g/

*(Note that b.c.d.e.f.g, is skipped since we'll take only the last 5 hostname components, and the full hostname)

Another interesting feature is that you can verify that the tables obtained in the requests come from Google, this is obtained by requesting a pair of keys, client key and wrapped key. The wrapped key must be sent along the requests for updates, then Google will include a MAC (Message Authentication Code) in the header of each response following the structure "[mac=dRalfTU+bXwUhlk0NCGJtQ==]". In order to validate this mac you need to do again a 128 bit MD5 Hash with the following information: client_key|separator|table data|separator|client_key. Where the separator is the string:coolgoog: - that is a colon followed by "coolgoog" followed by a colon. To be honest I got a bit stuck here, I've tried a few ways to verify a MAC but there is something I'm missing and I cannot get the expected result. Maybe I try again when I come back from holidays.

You can download the code and test it, but remember that this code is provided as is and cannot be considered finished code. There is room enough for improvement in many areas including exception handling that has not been considered for this sample.

In order to test you will need to install and start the windows service included, before start it be sure that you include your own key in the appSettings section of the file "BalearesOnNet.GoogleSafeBrowsing.Service.exe.config". The BHO is configured to be installed when you compile it with Visual Studio, you can disable this option by unchecking the option "Register for COM interop" in the properties of the project.

I hope you like it.

GoogleSafeBrowsing.zip

Using the CryptoStream class

One of the main problems people faces when they try to encrypt / decrypt with .NET classes is that, after decrypt, the resulting string contains unexpected chars or "garbage" at the end.

Normally, you will think that there is a problem with the padding used by the algorithm. But even if it’s related, the problem comes out because of a common people does when using the CryptoStream class.

The next code reproduces the error.

   1: static void Main(string[] args)
   2: {
   3:     RijndaelManaged rijndael = new RijndaelManaged();
   4:  
   5:     ICryptoTransform encryptor = rijndael.CreateEncryptor();
   6:     ICryptoTransform decryptor = rijndael.CreateDecryptor();
   7:  
   8:     string original = "jose fco bonnin";
   9:     System.Console.WriteLine("Encrypted: " + original + "|");
  10:  
  11:     byte[] plainData = System.Text.Encoding.Default.GetBytes(original);
  12:     byte[] encryptedData;
  13:  
  14:  
  15:     using (MemoryStream memoryStream = new MemoryStream())
  16:     {
  17:         using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
  18:         {
  19:             cryptoStream.Write(plainData, 0, plainData.Length);
  20:             cryptoStream.FlushFinalBlock();
  21:         }
  22:  
  23:         encryptedData = memoryStream.ToArray();
  24:     }
  25:  
  26:     byte[] decrypted;
  27:     using (MemoryStream memoryStream = new MemoryStream(encryptedData))
  28:     {
  29:         using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
  30:         {
  31:             int length = encryptedData.Length;
  32:             decrypted = new byte[length];
  33:  
  34:             cryptoStream.Read(decrypted, 0, length);
  35:         }
  36:     }
  37:  
  38:     System.Console.WriteLine("Decrypted: " + System.Text.Encoding.Default.GetString(decrypted) + "|");
  39:  
  40:     Console.ReadKey();
  41: }

If you execute the code, you will see how the original string and the decrypted string are different. I've added the pipe char ("|") at the end of the string to see it better.

The problem with he code above is that you create an array with the length of the encrypted data, which not necessarily will have the same size as the decrypted byte array. The code below shows you how you can implement the decryption properly. You could do it also by intializing the MemoryStream with the decrypted data and then read from the cryptoStream using a StreamReader.

   1: using (MemoryStream memoryStream = new MemoryStream())
   2: {
   3:     using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
   4:     {
   5:         cryptoStream.Write(encryptedData, 0, encryptedData.Length);
   6:  
   7:         cryptoStream.FlushFinalBlock();
   8:     }
   9:  
  10:     decrypted = memoryStream.ToArray();
  11: }

As you can see, we do the same as to encrypt the string. We create the CryptoStream using the CryptoStreamMode.Write instead of CryptoStreamMode.Read and we write to it, the only difference is that, of course, we use the decryptor instead of the encryptor.

If you do the changes to the first code you will find that both strings are now exactly the same.

Community Server Captcha Control

One of the problems we had in the past at Baleares on .NET was the amount of user registrations done by bots, to avoid it we managed to install a captcha control deployed by Dave Burke on the Join option of Community Server. This captha was created for Community Server 2.1, so after install the new version 2007 we needed to do some changes.

Fortunately having the source code of CS is very easy to understand how to apply the changes to have the control up and running again.

Maybe it's possible to create a standalone captcha control and plug it to CS, but since in the past we already needed to modify the CreateUser class, I've preferred just to add it as part of it and recompile. Let's see how I did it.

I've added to the Components folder of CommunityServerComponents20 project a slightly modified version of the CaptchaService class (now called Captcha), nothing important, just added IDisposable interface, some extra disposing not done and modified to use "using" (I'm a fan of the using statement) for some objects instead of the method Dispose at the end of the method.

Then in the folder Page of the project CommunityServerControls20 I've added the source code for JpegImage.cs, again with minor modifications.

After this is when we really need to modify the necessary code to support the Captcha component in our Registration page. The idea we follow is to add a new textbox in order our users can introduce the code displayed in the image of the captcha control. To do it we need to modify the class CreateUserForm that is contained in the folder Forms.

We start adding a new field of type TextBox called "CaptchaCodeTextBox" and the next property.

   1: public string CaptchaCodeTextBoxId
   2: {
   3:     get { return (string)ViewState["CaptchaCodeTextBoxId"] ?? string.Empty; }
   4:     set { ViewState["CaptchaCodeTextBoxId"] = value; }
   5: }

This will allow us retrieving the name of the textbox we will add later on in the ASP.NET page for validation. In the method "AttachChildControls" we get and check that effectively the ASP.NET page contains the required textbox.

   1: CaptchaCodeTextBox = CSControlUtility.Instance().FindControl(
   2:         this, CaptchaCodeTextBoxId) as TextBox;
   3: 
   4: if (UserNameTextBox == null
   5:     || PasswordTextBox == null
   6:     || EmailAddressTextBox == null
   7:     || CreateButton == null
   8:     || CreateUserCustomValidator == null
   9:     || CaptchaCodeTextBox == null)
  10:     throw new InvalidOperationException("UserNameTextBoxId,
  11:         PasswordTextBoxId, EmailAddressTextBoxId, CreateUserCustomValidatorId,
  12:         CaptchaCodeTextBoxId and CreateButtonId must be valid controls
  13:         to render a CreateUserForm");

At the end of the same method we also create the cookie that will contain the code to be manually introduced by the user.

HttpContext.Current.Response.Cookies[Captcha.CookieName].Value = Captcha.GenerateRandomCode();

The next method to modify is the one called "IsValid". As you already supposed, here is where we will compare the code introduced by the user with the one we have randomly generated. The code is very simple, take a look:

   1: if (this.CaptchaCodeTextBox.Text !=
   2:     HttpContext.Current.Request.Cookies[Captcha.CookieName].Value)
   3: {
   4:     CreateUserCustomValidator.ErrorMessage =
   5:         CommunityServer.Components.ResourceManager.GetString("CreateNewAccount_InvalidCaptchaCode");
   6: 
   7:     CreateUserCustomValidator.IsValid = false;
   8:     return false;
   9: }
  10: 
  11: this.CaptchaCodeTextBox.Text = string.Empty;
  12: HttpContext.Current.Response.Cookies[Captcha.CookieName].Value =
  13:         Captcha.GenerateRandomCode();

Note that in the line 4 we are using a new Resource name that we will need to introduce in the Resources.xml file.

With this we are already done with the source code, now we need to do the last updates to the CreateUser.aspx page.

Open the page and at the beginning of the CSControl:CreateUserForm you will see a list with the id's used for the required controls, as I said before we need to add the one for the new textbox.

   1: <CSControl:CreateUserForm runat="server"
   2:     AcceptAgreementCheckBoxId="AcceptAgreement"
   3:     AcceptAgreementHyperLinkId="AcceptAgreementLink"
   4:     AllowSitePartnersToContactCheckBoxId="AllowSitePartnersToContact"
   5:     AllowSiteToContactCheckBoxId="AllowSiteToContact"
   6:     CreateButtonId="CreateAccount"
   7:     CreateUserCustomValidatorId="CreateUserCustomValidator"
   8:     EmailAddressTextBoxId="Email"
   9:     PasswordTextBoxId="Password"
  10:     SubFormIds=""
  11:     TimeZoneDropDownListId="Timezone"
  12:     UserNameTextBoxId="Username"
  13:     CaptchaCodeTextBoxId="CaptchaCode"
  14:     >

Then you only need add the next code somewhere in the page. I did it after the "TimeZone" DropDownList. Note again that we have added a new resource (line 3).

   1: <tr>
   2:     <td class="CommonFormFieldName">
   3:         <CSControl:ResourceControl runat="server" ResourceName="CreateNewAccount_EnterCode" />
   4:     </td>
   5:     <td>
   6:         <div class="CommonFormField">
   7:             <asp:TextBox ID="CaptchaCode" runat="server" MaxLength="128" columns="40" onkeyup ="validateForm(this);"/>
   8:             <asp:RequiredFieldValidator ID="captchaValidator" runat="server" ControlToValidate="CaptchaCode" Cssclass="validationWarning">
   9:             </asp:RequiredFieldValidator>
  10:         </div>
  11:     </td>
  12: </tr>
  13: <tr>
  14:     <td align="right"></td>
  15:     <td>
  16:         <img src="../JpegImage.aspx" alt="Captcha Image"/>
  17:     </td>
  18: </tr>

To finish you only need to add to the page JpegImage.aspx in the root folder, replace the assemblies of the folder bin CommunityServer.Components.dll, CommunityServer.Controls.dll with the ones we modified above and don't forget to add the two new Resources to the file Resources.xml contained in each language folder you support. Just something like this:

Enter the Code:

Code does not match with the image displayed

That's all; we are ready to use our new captcha control!!

CaptchaCS2007.zip