How to prevent cross site scripting

2019-02-15 10:28发布

问题:

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 sales@company.co.uk">
    <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>&nbsp;</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 = 'sales@company.co.uk';
/*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: &lt [mailto:&lt] 
Sent: 20 April 2015 10:04
To: sales@company.co.uk
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

回答1:

Do not attempt to prevent XSS attacks during input. Always escape on output.

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');

Why 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 %}
    
  • If all else fails, use HTML Purifier.


回答2:

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));


标签: php security xss