Encode Output

From Guidance Share

Jump to: navigation, search

- J.D. Meier, Alex Mackman, Michael Dunner, Srinath Vasireddy, Ray Escamilla and Anandha Murukan

If you write text output to a Web page and you do not know with absolute certainty that the text does not contain HTML special characters (such as <, >, and &), then make sure to pre-process it using the HttpUtility.HtmlEncode method. Do this even if the text came from user input, a database, or a local file. Similarly, use HttpUtility.UrlEncode to encode URL strings.

The HtmlEncode method replaces characters that have special meaning in HTML to HTML variables that represent those characters. For example, < is replaced with &lt and " is replaced with &quot. Encoded data does not cause the browser to execute code. Instead, the data is rendered as harmless HTML.

Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));

Data-Bound Controls

Data bound controls are web controls that are bindable to data components through a public inherited 'DataSource' property. To mention a few, you will find DataGrid, ListBox and DropDownList to be used very often. Not all data bound controls perform encoding when displaying data retrieved from a bound data component; thus, it will be your responsibility to perform encoding on non-trusted data components in order to prevent XSS attacks. For example, a data component cannot be trusted in a scenario where different applications share a single database. If an attacker has the ability to insert malicious XSS code into the database (by abusing a vulnerability in one of the applications, for instance) all applications using non-encoding web controls bound to it, will turn vulnerable. Only avoid encoding if you can be certain that the output from the data component will always be valid.

Examples of data bound controls that do not perform encoding are DataGrid, DataList, RadioButtonList and CheckBoxList. Performing encoding for a data bound control may vary depending on each specific control. For example, for a DataGrid control, you have the following options:

  • Turn all columns into templates and manually use HtmlEncode()/UrlEncode() on each call to DataBinder.Eval
  • Override one of its DataBinding methods, such as OnDatabinding or OnItemDataBound and perform encoding on its items. The following example illustrates how to override the OnItemDataBound method of a DataGrid control in order to encode its items by either using HtmlEncode() or UrlEncode() when required:
...
[DefaultProperty("Text"),
 ToolboxData("<{0}:DataGrid runat=server></{0}:DataGrid>")]

public class DataGrid : System.Web.UI.WebControls.DataGrid
{
   /// <summary>
   /// The ItemDataBound event is raised after an item is data bound to the DataGrid
   /// control. This event provides you with the last opportunity to access the data
   /// item before it is displayed on the client. After this event is raised, the data
   /// item is nulled out and no longer available. - .NET Framework Class Library
   /// </summary>
   /// <param name="e"></param>
   protected override void OnItemDataBound(DataGridItemEventArgs e)
   {
     base.OnItemDataBound (e);

     switch (e.Item.ItemType)
     {
       case ListItemType.Item:
       case ListItemType.AlternatingItem:
       case ListItemType.EditItem:
       case ListItemType.SelectedItem:
       case ListItemType.Footer:
       case ListItemType.Header:
       case ListItemType.Pager:  
         // even though not all of these ListItemTypes are data bound,
         // perform HtmlEncode or UrlEncode on each control. If there are
         // no controls, we perform HtmlEncode on any available text.
         // Also, don't let  's be encoded.
         TableCellCollection cCells = e.Item.Cells;
         foreach (TableCell tc in cCells)
         {
           if (tc.Controls.Count > 0)
           {
             foreach (Control ctrl in tc.Controls)
             {
               
               // don't perform HtmlEncode on URL's
               if (ctrl is HyperLink)
               {
                 HyperLink hLnk = (HyperLink)ctrl;

                 if (hLnk.Text.Length > 0)
                   hLnk.Text = HttpUtility.HtmlEncode(hLnk.Text);
                 if (hLnk.NavigateUrl.Length > 0)
                   hLnk.NavigateUrl = HttpUtility.UrlEncode(hLnk.NavigateUrl);
               }
               else if (ctrl is LinkButton)
               {
                 LinkButton lButton = (LinkButton)ctrl;

                 if (lButton.Text.Length > 0)
                   lButton.Text = HttpUtility.HtmlEncode(lButton.Text);
               }
               else if (ctrl is Button)
               {
                 Button cButton = (Button)ctrl;

                 if (cButton.Text.Length > 0)
                   cButton.Text = HttpUtility.HtmlEncode(cButton.Text);
               }
             }
           } 
           else 
           {              
             // there are no controls in the table cell
             // HTMLEncode any available text
             if (tc.Text.Length > 0) 
             {
               if (" " != tc.Text) 
                 tc.Text = HttpUtility.HtmlEncode(tc.Text);
             }
           }
         }
         break;
        default:
         break;
     }
    }
  }
...

Sanitizing Free Format Input

If your Web page includes a free-format text box, such as a "comments" field, in which you want to permit certain safe HTML elements such as and , you can handle this safely by first pre-processing with HtmlEncode, and then selectively removing the encoding on the permitted elements, as follows:

StringBuilder sb = new StringBuilder( HttpUtility.HtmlEncode(userInput) ) ;
sb.Replace("<b>", "<b>");
sb.Replace("</b>", "</b>");
sb.Replace("<i>", "<i>");
sb.Replace("</i>", "");
Response.Write(sb.ToString());


References

Personal tools