Preventing XSS Attacks with htmlspecialchars() Validation

XSS or cross site scripting is a method of injection on the web using script code

XSS or cross site scripting is a method of injection on the web using script code, this is usually encountered because the programmer does not make validation of special html characters. I will provide a way to secure the web from the xss bug.
 
Here I already have an example of source code that has a vulnerability to the xss bug, here is the initial source code that has an xss gap:

<?php
/**
* Max's Guestbook
*
* This is the Max's Guestbook business logic class.
* For more details please read the readme.txt
*/
?>
<?php
class maxGuestbook{
var $messageDir = 'messages';
var $dateFormat = 'Y-m-d g:i:s A';
var $itemsPerPage = 5;
var $messageList;

function processGuestbook(){
if (isset($_POST['submit'])) {
$this->insertMessage();
}
$page = isset($_GET['page']) ? $_GET['page'] : 1;

$this->displayGuestbook($page);
}

function getMessageList(){

$this->messageList = array();

// Open the actual directory
if ($handle = @opendir($this->messageDir)) {
// Read all file from the actual directory
while ($file = readdir($handle)) {
if (!is_dir($file)) {
$this->messageList[] = $file;
}
}
}

rsort($this->messageList);

return $this->messageList;
}

function displayGuestbook($page=1){
$list = $this->getMessageList();
//echo "<center><a href='add.php'>Leave a message</a></center>";
echo "<table class='newsList'>";

//Get start point and end point
$startItem = ($page-1)*$this->itemsPerPage;
if (($startItem + $this->itemsPerPage) > sizeof($list)) $endItem = sizeof($list);
else $endItem = $startItem + $this->itemsPerPage;

for ($i=$startItem;$i<$endItem;$i++){
//foreach ($list as $value) {
$value = $list[$i];
$data = file($this->messageDir.DIRECTORY_SEPARATOR.$value);
$name = trim($data[0]);
$email = trim($data[1]);
$submitDate = trim($data[2]);
unset ($data['0']);
unset ($data['1']);
unset ($data['2']);

$content = "";
foreach ($data as $value) {
$content .= $value;
}

echo "<tr><th align='left'><a href=\"mailto:$email\">$name</a></th>
<th class='right'>$submitDate</th></tr>";
echo "<tr><td colspan='2'>".nl2br(htmlspecialchars($content))."<br/></td></tr>";
}
echo "</table>";
if (sizeof($list) == 0){
echo "<center><p>No messages at the moment!</p><p>&nbsp;</p></center>";
}
// Create pagination
if (sizeof($list) > $this->itemsPerPage){
echo "<div id=\"navigation\">";
if ($startItem == 0) {
if ($endItem < sizeof($list)){
echo "<div id=\"nright\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page+1)."\" >Next &raquo;</a></div>";
} else {
// Nothing to display
}
} else {
if ($endItem < sizeof($list)){
echo "<div id=\"nleft\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page-1)."\" >&laquo; Prev</a></div>";
echo "<div id=\"nright\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page+1)."\" >Next &raquo;</a></div>";
} else {
echo "<div id=\"nleft\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page-1)."\" >&laquo; Prev</a></div>";
}
}

echo "<br/></div><br/>";
}
echo "<hr />";
$this->displayAddForm();
}

function displayAddForm(){
?>
<form class="iform" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Name:<br/>
<input type="text" name="name" size="30"/><br/><br/>
Email:<br/>
<input type="text" name="email" size="30"/><br/><br/>
Your message:<br/>
<textarea name="message" rows="7" cols="49"></textarea><br/>
<center><input type="submit" name="submit" value="Save" /></center>
</form>

<?php
}

function insertMessage(){
$name = isset($_POST['name']) ? $_POST['name'] : 'Anonymous';
$email = isset($_POST['email']) ? $_POST['email'] : '';
$submitDate = date($this->dateFormat);
$content = isset($_POST['message']) ? $_POST['message'] : '';

if (trim($name) == '') $name = 'Anonymous';
if (strlen($content)<5) {
exit();
}

$filename = date('YmdHis');
if (!file_exists($this->messageDir)){
mkdir($this->messageDir);
}
$f = fopen($this->messageDir.DIRECTORY_SEPARATOR.$filename.".txt","w+");
fwrite($f,$name."\n");
fwrite($f,$email."\n");
fwrite($f,$submitDate."\n");
fwrite($f,$content."\n");
fclose($f);

}
}
?>


In this script I have blocked the red part, do not have validation on special characters and allow xss to be done on the input form, as below:

special characters and allow xss to be done on the input form

When I enter the script code on the name, email, and message text box input forms, it will trigger the xss script to display an alert as shown.

Now we will patching the xss bug on the script and add special character html.

<?php
/**
* Max's Guestbook
*
* This is the Max's Guestbook business logic class.
* For more details please read the readme.txt
*/
?>
<?php
class maxGuestbook{
var $messageDir = 'messages';
var $dateFormat = 'Y-m-d g:i:s A';
var $itemsPerPage = 5;
var $messageList;

function processGuestbook(){
if (isset($_POST['submit'])) {
$this->insertMessage();
}
$page = isset($_GET['page']) ? $_GET['page'] : 1;

$this->displayGuestbook($page);
}

function getMessageList(){

$this->messageList = array();

// Open the actual directory
if ($handle = @opendir($this->messageDir)) {
// Read all file from the actual directory
while ($file = readdir($handle)) {
if (!is_dir($file)) {
$this->messageList[] = $file;
}
}
}

rsort($this->messageList);

return $this->messageList;
}

function displayGuestbook($page=1){
$list = $this->getMessageList();
//echo "<center><a href='add.php'>Leave a message</a></center>";
echo "<table class='newsList'>";

//Get start point and end point
$startItem = ($page-1)*$this->itemsPerPage;
if (($startItem + $this->itemsPerPage) > sizeof($list)) $endItem = sizeof($list);
else $endItem = $startItem + $this->itemsPerPage;

for ($i=$startItem;$i<$endItem;$i++){
//foreach ($list as $value) {
$value = $list[$i];
$data = file($this->messageDir.DIRECTORY_SEPARATOR.$value);
$name =
htmlspecialchars(trim($data[0]));
$email =
htmlspecialchars(trim($data[1]));
$submitDate = trim($data[2]);
unset ($data['0']);
unset ($data['1']);
unset ($data['2']);

$content = "";
foreach ($data as $value) {
$content .= $value;
}

echo "<tr><th align='left'><a href=\"mailto:$email\">$name</a></th>
<th class='right'>$submitDate</th></tr>";
echo "<tr><td colspan='2'>".nl2br(htmlspecialchars($content))."<br/></td></tr>";
}
echo "</table>";
if (sizeof($list) == 0){
echo "<center><p>No messages at the moment!</p><p>&nbsp;</p></center>";
}
// Create pagination
if (sizeof($list) > $this->itemsPerPage){
echo "<div id=\"navigation\">";
if ($startItem == 0) {
if ($endItem < sizeof($list)){
echo "<div id=\"nright\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page+1)."\" >Next &raquo;</a></div>";
} else {
// Nothing to display
}
} else {
if ($endItem < sizeof($list)){
echo "<div id=\"nleft\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page-1)."\" >&laquo; Prev</a></div>";
echo "<div id=\"nright\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page+1)."\" >Next &raquo;</a></div>";
} else {
echo "<div id=\"nleft\"><a href=\"".$_SERVER['PHP_SELF']."?page=".($page-1)."\" >&laquo; Prev</a></div>";
}
}

echo "<br/></div><br/>";
}
echo "<hr />";
$this->displayAddForm();
}

function displayAddForm(){
?>
<form class="iform" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Name:<br/>
<input type="text" name="name" size="30"/><br/><br/>
Email:<br/>
<input type="text" name="email" size="30"/><br/><br/>
Your message:<br/>
<textarea name="message" rows="7" cols="49"></textarea><br/>
<center><input type="submit" name="submit" value="Save" /></center>
</form>

<?php
}

function insertMessage(){
$name = isset($_POST['name']) ? $_POST['name'] : 'Anonymous';
$email = isset($_POST['email']) ? $_POST['email'] : '';
$submitDate = date($this->dateFormat);
$content = isset($_POST['message']) ? $_POST['message'] : '';

if (trim($name) == '') $name = 'Anonymous';
if (strlen($content)<5) {
exit();
}

$filename = date('YmdHis');
if (!file_exists($this->messageDir)){
mkdir($this->messageDir);
}
$f = fopen($this->messageDir.DIRECTORY_SEPARATOR.$filename.".txt","w+");
fwrite($f,$name."\n");
fwrite($f,$email."\n");
fwrite($f,$submitDate."\n");
fwrite($f,$content."\n");
fclose($f);

}
}
?>

You can see the red block in the script above I have added htmlspecialchars() validation, so that if you enter the script code on the character input form in the script it will not affect the form script and will not trigger an alert.

0 Comments