Return to HomePage



Encoding Output within a DataTable (C#)



Summary

This code demonstrates how to implement security output encoding when using the .NET DataTable object to display application data. Output encoding mitigates against client-side script vulnerabilities by representing output data using escape character equivalents for values that might otherwise be interpreted by the browser, such as those characters used in the formatting of HTML pages (<,>,&,",').

Applies to

* ASP.NET 2.0
* C#
* Server-side
* SQL Server


Objectives

* Protect application users from client-side scripting attacks
* Ensure that malicious data that may pre-date input validation routines or have been missed through poor validation does not render as application output

Scenarios

* Database-backed web application that uses data tables to present output
* Application that uses data tables to present input from an untrusted source


Solution Example


Solution Example #1: Looping through the DataTable
The following code illustrates the use of output encoding accomplished by looping through the DataRow object and calling Server.HtmlEncode for each output value we wish to encode.

public void LoadEncodedPeopleTableEvent(SqlDataAdapter adapter)
{
		    		// Build a Data Grid to house our data and add to the set of page controls
		    		[DataGrid] dataGrid = new [DataGrid();]
		    		this.Controls.Add(dataGrid);
	

		    		// Create a new data table and fill our that table with names from the adapter 
		    		[DataTable] names = new [DataTable();]
		    		adapter.Fill(names);
	

		    		// add an event handler to our [DataGrid] to encode the data
		    		[dataGrid.ItemDataBound] += new DataGridItemEventHandler(dataGrid_EncodeItem);
	

		    		// Present the data to the user in the previously created Data Grid
		    		[dataGrid.DataSource] = names;
		    		[dataGrid.DataBind();]
	
}

public void dataGrid_EncodeItem(object sender, DataGridItemEventArgs e)
{
		    		// Encode each actual data row presented within the Data Grid
		    	if [(e.Item.ItemType.Equals(ListItemType.Item)] || 
		        		[e.Item.ItemType.Equals(ListItemType.AlternatingItem))]
		    		{
		        		e.Item.Cells[0].Text = Server.HtmlEncode(e.Item.Cells[0].Text);
		    		}
	
}

This approach is flexible and can be used in a variety of different data presentation settings. For the example data above, the row containing malicious Javascript will be encoded and presented as escaped HTML output.


Solution Example #2: Using the DataGrid ItemDataBound event
The following code illustrates the use of output encoding accomplished by associating a custom encoding handler within the ItemDataBound event support by the DataGrid in use for rendering the application output.

public void LoadEncodedPeopleTableLoop(SqlDataAdapter adapter)
{
		    // Build a Data Grid to house our data and add to the set of page controls
		    [DataGrid] dataGrid = new [DataGrid();]
		    this.Controls.Add(dataGrid);
	

		    // Create a new data table and fill our that table with names from the adapter 
		    [DataTable] names = new [DataTable();]
		    adapter.Fill(names);
	

		    foreach [(DataRow] row in names.Rows)
		    {
		        row["Name"] = Server.HtmlEncode((string)row["Name"]);
		        [row.EndEdit();]
		    }
	

		    // Present the data to the user in the previously created Data Grid
		    [dataGrid.DataSource] = names;
		    [dataGrid.DataBind();]
	
}

This solution takes advantage of the event-driven architecture of .NET and eliminates the requirement to loop through the DataTable in order to access individual data items. Where presentation of data makes use of an object such as a DataGrid that supports data binding events, we recommend this approach for reasons of performance and architectural consistency.


Problem Example

The following example demonstrates the use of a DataTable to query data without the use of any output encoding:

// Build a datagrid to house our data and add to the set of page controls
DataGrid dataGrid = new DataGrid();
this.Controls.Add(dataGrid);

// Create a new database connection using Integrated Security and open that connection
string connectionString = "Initial Catalog=snippets;Data Source=vm-win2003\\sqlexpress;Integrated Security=SSPI;";
SqlConnection cn = new SqlConnection(connectionString);
cn.Open();

// Create a new SQL Command object with a query to execute the stored procedure
SqlCommand cmd = new SqlCommand("exec spFullNames", cn);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);

// Create a new data table and fill our that table with names from the adapter
DataTable names = new DataTable();
adapter.Fill(names);

// Present the data to the user in the previously created Data Grid
dataGrid.DataSource = names;
dataGrid.DataBind();

* Any HTML data present within the database query output will be rendered as part of the application HTML output
* Any Javascript data present within the database query output will be rendered as part of the application HTML output
* Code is vulnerable to client-side script attacks such as cross-site scripting (XSS)

Test Case

The following classes must be included in any project making use of the sample code provided above:

using System.Data;
using System.Data.SqlClient;
using System.Web;

Create a new C# ASP.NET application and use the following Page_Load method to test the provided example methods (adjust database code for your example):

protected void Page_Load(object sender, EventArgs e)
{
		    		if (!Page.IsPostBack)
		   		 {
		        			// Create a new database connection using Integrated Security and open that connection
		        			string connectionString = "Initial Catalog=snippets;Data Source=vm-win2003\\sqlexpress;Integrated Security=SSPI;";
		       		 [SqlConnection] cn = new [SqlConnection(connectionString);]
		        		cn.Open();
	

		       	 	// Create a new SQL Command object with a query to execute the stored procedure
		        		[SqlCommand] cmd = new SqlCommand("exec spFullNames", cn);
		        		[SqlDataAdapter] adapter = new [SqlDataAdapter(cmd);]
	

		        		[LoadEncodedPeopleTableEvent(adapter);]
		    		}
	
}


Expected Result

<table cellspacing="0" rules="all" border="1" style="border-collapse:collapse;">
<tr><td>Name</td></tr>
<tr><td>Elvin Jones</td></tr>
<tr><td>Gene Krupa</td></tr>
<tr><td>Tony Williams</td></tr>
<tr><td><script>alert('XSS!');</script> XSS</td></tr>
</table>

More Information

* In addition to output validation, developers should always validate any input that originates from untrusted sources, such as application users or external feeds.


Additional Resources

* Preventing Cross-Site Scripting Attacks (.NET): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000001.asp
* Anti-Cross Site Scripting Library (.NET): http://www.microsoft.com/downloads/details.aspx?familyid=9A2B9C92-7AD9-496C-9A89-AF08DE2E5982&displaylang=en

Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Data Validation
* Author: Jonathan Bailey




Return to HomePage
Microsoft Communities