2006. május 6., szombat

Cross-Site Scripting Protection (aka Encoding and Filtering HTML)


Problem/Question/Abstract:

In this article I’ll present a unit that can both Encode data for display in an HTML document, and also ensure that invalid characters (filtering) that can be used for cross-site scripting are prevented from entering.

Answer:

Cross-Site Scripting Protection (aka Encoding and Filtering HTML)

In this article I’ll present a unit that can both Encode data for display in an HTML document, and also ensure that invalid characters (filtering) that can be used for cross-site scripting are prevented from entering.

For more information about cross-site scripting and malicious code problems, please visit:
http://www.cert.org/tech_tips/malicious_code_mitigation.html/

Overview

To summarize the article, any HTML data that is presented to the user from disparate data sources (which may not always be in your control) should be filtered of characters that can affect the display of HTML or allow embedded script viruses.  

Filtering Data

For example, let’s say that you have a form on your web site that allows a user to enter a contest, on this form they enter their email address and first name and then hit submit which adds a record to your database. Of course, several validity checks, such as size of contest, etc. will take place, but in most cases the data is not checked for malicious HTML code. Continuing this example, lets say you have another program that will send out an HTML e-mail, which contains the first name and e-mail address (basically a mail merge).

I as a malicious user can enter the contest submitting my target’s e-mail address, and a small virus (not necessarily harmful) in the first name field; when the e-mail is sent out through the second program the recipient can be passed code to be executed in their web-browser against their will (and with the recent sting of Internet Explorer and Microsoft Office bugs, this could be a major issue).

This scenario can be fixed by simply filtering out the few characters that should not be allowed if the data is to be ultimately displayed in a web-browser.

The function, in the abHTMLFilters unit, FilterData will delete any characters that should not be allowed in the data (based on CERT’s recommendation).

Encoding Data

The flip side of filtering is encoding. Encoding allows you to safely display any code, which would normally be interpreted by the web-browser as formatting instructions or script, as text. As a simple example, this can be used to display the source of an HTML file in a browser.

The function, in the abHTMLFilters unit, EncodeData will encode any characters that should not be allowed in the data (based on CERT’s recommendation) with its HTML equivalent so it can be displayed.

I hope you found this article and function to be useful; I’d love to hear your comments, suggestions, etc.

The following is the source code for the functions described above, feel free to use the code in your own programs, but please leave my name and address intact!

// ---------------------------ooo------------------------------ \\
// ©2000 David Lederman
// dlederman@internettoolscorp.com
// ---------------------------ooo------------------------------ \\
unit abHTMLFilters;

interface

function FilterData(Data: string): string;
function EncodeData(Data: string): string;

implementation

const
  IsBadChar: array[0..255] of Boolean = (
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, true, true, false, false, true, true, true, true, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, true, true, false, true, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false, false, false, false, false, false, false, false, false,
    false, false, false);
const
  ReplaceBadChars: array[0..255] of string = (
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '"', '#', '', '', '&', ''', '(', ')', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '&#59;', '<', '', '>', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '', '', '', '', '', '', '', '', '',
    '', '', '');

  // ---------------------------ooo------------------------------ \\
  // This function will filter out all dangerous data for web
  // display.
  // ---------------------------ooo------------------------------ \\

function FilterData(Data: string): string;
var
  i, DataLen, ActualLen: Integer;
begin
  Result := '';
  // Get the data length
  DataLen := Length(Data);
  // Check if we can escape early
  if DataLen = 0 then
    Exit;
  for i := 1 to DataLen do // Iterate
  begin
    if not IsBadChar[Ord(Data[i])] then
      Result := Result + Data[i];
  end; // for
end;
// ---------------------------ooo------------------------------ \\
// This function will encode (for display) all dangerous data
// for weg display.
// ---------------------------ooo------------------------------ \\

function EncodeData(Data: string): string;
var
  i, DataLen, ActualLen: Integer;
begin
  Result := '';
  // Get the data length
  DataLen := Length(Data);
  // Check if we can escape early
  if DataLen = 0 then
    Exit;
  for i := 1 to DataLen do // Iterate
  begin
    if not IsBadChar[Ord(Data[i])] then
    begin
      Result := Result + Data[i];
    end
    else
    begin
      Result := Result + ReplaceBadChars[Ord(Data[i])];
    end;
  end; // for
end;

end.

Nincsenek megjegyzések:

Megjegyzés küldése