Reputation: 526
I have the following form that users fill in:
<form name="form" action="" method="POST">
<table width="100%" border="0" cellpadding="2" cellspacing="2">
<tr>
<td width="25%" ><div align="right"><strong>Name:</strong></div></td>
<td width="75%" ><span id="sprytextfield1">
<input id="Cname"name="Name" type="text" placeholder="Please fill in your name">
<span class="textfieldRequiredMsg">A value is required.</span></span></td>
</tr>
<tr>
<td><div align="right"><strong>Email:</strong></div></td>
<td><span id="sprytextfield2">
<input id="Cemail"name="email" type="text" placeholder="e.g [email protected]">
<span class="textfieldRequiredMsg">A value is required.</span><span class="textfieldInvalidFormatMsg">Invalid format.</span></span></td>
</tr>
<tr>
<td><div align="right"><strong>Phone Number:</strong></div></td>
<td>
<input id="Cphone" name="Phone" type="text"placeholder="e.g. 5555-6666666">
</td>
</tr>
<tr>
<td> </td>
<td><input name="Manufacturer" type="hidden" value="<?php echo $row_emailProduct['Manufacturer']; ?>">
<input name="Model" type="hidden" value="<?php echo $row_emailProduct['Model']; ?>">
<input name="Color" type="hidden" value="<?php echo $row_emailProduct['Color']; ?>">
<input name="price" type="hidden" value="<?php echo $row_emailProduct['price']; ?>">
<input name="id" type="hidden" value="<?php echo htmlentities($_GET['id']); ?>">
<input name="insert" id="insert" type="submit" value="Send Request"></td>
</tr></tr>
</table>
</form>
Once the form is submitted the following happens:
if (isset($_POST["insert"])){
$OK=false;
$insertSQL = "INSERT INTO Item_intrest (Manufacturer, Model, Color, price, Name, Phone, email) VALUES (:Manufacturer, :Model, :Color, :price, :Name, :Phone, :email)";
$Result1 = $conn->prepare($insertSQL) or die(errorInfo());
$Result1->bindParam(':Manufacturer', htmlentities($_POST['Manufacturer']), PDO::PARAM_STR);
$Result1->bindParam(':Model', htmlentities($_POST['Model']), PDO::PARAM_STR);
$Result1->bindParam(':Color', htmlentities($_POST['Color']), PDO::PARAM_STR);
$Result1->bindParam(':price', htmlentities($_POST['price']), PDO::PARAM_STR);
$Result1->bindParam(':Name', htmlentities($_POST['Name']), PDO::PARAM_STR);
$Result1->bindParam(':Phone', htmlentities($_POST['Phone']), PDO::PARAM_STR);
$Result1->bindParam(':email', htmlentities($_POST['email']), PDO::PARAM_STR);
$Result1->execute();
$OK = $Result1->rowCount();
/*email to shop */
$emailsubject = 'Product Request';
$webmaster = '[email protected]';
/*data collection */
$Name = htmlentities($_POST['Name']);
$email = htmlentities($_POST['email']);
$Phone = htmlentities($_POST['Phone']);
$item1 = htmlentities($_POST['Manufacturer']);
$item2 = htmlentities($_POST['Model']);
$item3 = htmlentities($_POST['Color']);
$Price = htmlentities($_POST['price']);
$Body = <<<EOD
<br><hr><br>
Name: $Name<br>
Email: $email<br>
Phone: $Phone<br>
Product:$item1, $item2,$item3<br>
Price: $Price<br>
EOD;
$headers = "From: $email\r\n";
$headers .= "content-type: text/html\r\n";
$succes = mail($webmaster, $emailsubject, $Body, $headers);
if($OK){
header('Location: /thankyourequest.php?id=' . htmlentities($_GET['id']). '');
exit;
}else {
$errorInfo = $Result1->errorInfo();
if(isset($errorInfo[2])){
$error = $errorInfo[2];
}
}
}
For some reason when it is scan it returns
From: < [mailto:<]
Sent: 20 April 2015 10:04
To: [email protected]
Subject: Product Request
Name: <script>alert("xssvuln")</script>
Email: <script>alert("xssvuln")</script>
Phone: <script>alert("xssvuln")</script>
Product:<script>alert("xssvuln")</script>, <script>alert("xssvuln")</script>,<script>alert("xssvuln")</script>
Price: <script>alert("xssvuln")</script>
As you can see I've tried to prevent this with htmlentities how ever that does not seem to be enough. Any help welcome to prevent this
Upvotes: 3
Views: 7566
Reputation: 34113
See also: Stored XSS in Wordpress 4.2 caused by MySQL column truncation. Filtering on output would have prevented these conditions.
Instead, what you want to do is just use prepared statements and store the data naked. (You should still validate the data of course! Make sure they've given you an email address when you asked for one, etc.)
When you are pulling the data from the database to display on a webpage, that is when you want to filter. And you want to do it like this (assuming you don't need to allow users to provide some HTML):
echo htmlentities($row['column'], ENT_QUOTES | ENT_HTML5, 'UTF-8');
ENT_QUOTES | ENT_HTML5
and 'UTF-8'
?I'm assuming your web page is using HTML5 (i.e. <!DOCTYPE html>
) and your charset is UTF-8 (i.e. in the <meta>
tag as well as in the HTTP Content-Type
header). Please adjust if you're using something different for either.
We specify ENT_QUOTES
to tell htmlentities()
to escape quote characters ("
and '
). This is helpful for situations such as:
<input type="text" name="field" value="<?php echo $escaped_value; ?>" />
If you failed to specify ENT_QUOTES
and attacker simply needs to pass " onload="alert('XSS');
as a value to that form field and, presto! Instant client-side code execution.
We specify 'UTF-8'
so htmlentities()
knows what character set to work with. The reason we do this is, as demonstrated against mysql_real_escape_string()
, an incorrect (especially attacker-controlled) character encoding can defeat string-based escaping strategies.
Note that this will escape all HTML special characters and prevent users from supplying any markup. If you need to allow some HTML, we outlined the best strategies for preventing XSS. In a nutshell:
Using Twig? The below example is safe. Note the use of {% autoescape %}
blocks for specifying the default strategy, but overriding it with |e('html')
for other_variable
:
{% autoescape 'html_attr' %}
<p class="{{ variable }}" id="{{ var_two }}">
{{ other_variable|e('html') }}
</p>
{% endautoescape %}
Upvotes: 5
Reputation: 2449
this is called security issue. Cross site scripting, you have many methods to avoid it,
What's the best method for sanitizing user input with PHP?
For example if you have a option to input an email address you have to validate it like below:
<?php
$email = filter_var($_POST['username'], FILTER_SANITIZE_EMAIL);
?>
If there is a option to enter a string then you ave to validate like below
<?php
$password = trim(filter_var($_POST['password'], FILTER_SANITIZE_STRING));
?>
In your case you have to do something like below
$Name = htmlentities($_POST['Name']);
$email = htmlentities($_POST['email']);
Instead of above, follow filter sanitizing method:
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$Name = trim(filter_var($_POST['Name'], FILTER_SANITIZE_STRING));
Upvotes: 1