Threat Level: green Handler on Duty: Rob VandenBrink

SANS ISC InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

The bane of XSS

Published: 2012-06-12
Last Updated: 2012-06-12 11:33:48 UTC
by Johannes Ullrich (Version: 1)
0 comment(s)

I would like to thank Andrew for pointing out a XSS vulnerability in one of our tools. The tool pretty simply echoed back user input without proper output encoding.

XSS is in particular difficult to avoid as it may happen anywhere you send data back to the user. The proper encoding depends on the context the data is used in, and sometimes, a simple "replace < and > with &lt; and &gt;" doesn't cut it [1]. However, in my experience, many cross site scripting errors happen because the coder (in this case me), just didn't bother to properly escape at all.

A while back, I started using a "safe_out" function. This function will do the simple HTML entity replacement before printing the data. By using "safe_out" instead of "echo" or "print", I got a simple check ("grep print") to make sure I didn't miss a spot. The function is only good if you return data in the HTML body of a page, but this is what I am doing 99% of the time. 

function safe_out($sText){
    echo(htmlentities($sText,ENT_QUOTES,'ISO-8859-1'));
}

The function is however a pain to use if you are mixing HTML and user data. Lets say you are trying to replace a print statement like:

print "<tr><td>$col1</td><td>$col2</td><td>$col3</td></tr>";

this would become:

print "<tr><td>";
safe_out($col1);
print "</td><td>";
....

To overcome this, I modified the safe_out function somewhat, to make it easier to use in these case:

function safe_out($sText,$aVars=''){
  if ( $aVars=='' ) {
    echo(htmlentities($sText,ENT_QUOTES,'ISO-8859-1'));
  } else {
    if ( is_array($aVars) ) {
      foreach ( $aVars as $key=>$value ) {
        $value=htmlentities($value,ENT_QUOTES,'ISO-8859-1');
        $sText=str_replace(":$key",$value,$sText);
      }
      echo $sText;
    }
  }
}
Now, it almost starts to look like  a prepared statement:

safe_out("<tr><td>:col1</td><td>:col2</td><td>:col3</td></tr>",array("col1"=>"abc","col2=>"axy",":col3"=>"123"));

Of course Java users, may want to consider the OWASP ESAPI framework. It includes appropriate output encoders. But for php coders like me, the above snippet may be of help.

[1] https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

------
Johannes B. Ullrich, Ph.D.
SANS Technology Institute
Twitter

Keywords: xss
0 comment(s)
Diary Archives