How can I make this code safer against XSS attacks? I'm not sure what I'm doing wrong, but I run the code using a Web Vulnerability software and I get a lot of XSS attacks against the code. Is there something I could do better?
    

// connect to database
include("dbconnect.php");

$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$email = $_POST['email'];
$phone = $_POST['phone'];
$category = $_POST['category'];

$add = $db-&gt;prepare("INSERT INTO contacts SET firstName=(?), lastName=(?), email=(?), phone=(?), category=(?)");
$add-&gt;bind_param('sssss', $firstName, $lastName, $email, $phone, $category);

$firstName = $db-&gt;real_escape_string($firstName);
$lastName = $db-&gt;real_escape_string($lastName);
$email = $db-&gt;real_escape_string($email);
$phone = $db-&gt;real_escape_string($phone);
$category = $db-&gt;real_escape_string($category);

$add-&gt;execute();
$add-&gt;close();
header("Location:http://localhost/address-book/contact.php");
exit;

?&gt;


Everything works great, but I'm wonder if there's a safer way to go about it.

I wrote it as prepared statements and ran each variable through mysqli_real_escape_string hoping to strip most of the nasty things. But, no lucky.

I'm new to PHP, so this is all a bit alien to me.
XSS attacks affect the whole web, regardless of the stack you're using, you always have to be careful. Based on the redirect url you provided and the queries you execute, I'm assuming you're building an on-line address book. If a client were to fill in the form, saying his name were:

&lt;script&gt; alert(document.cookie);&lt;/script&gt;"&gt;Gotcha


Your code would simply insert that in the database, properly escaped, of course. The escaping is what mysqli_real_escape_string does. It doesn't sanitize, it protects the Database, not the site. I can't, for example, post something like "bobby'; -- DROP TABLE contacts;", which is a basic example of an injection attack. But storing markup in a DB isn't wrong or dangerous as far as MySQL is concerned, so the data above can be safely inserted, and queried later on. However, when you request a list of contact names, you would get an alert, showing you your cookies. That's annoying, but not that bad. However, Check these examples to get a basic idea of how XSS attacks work, and what they can be used for.
They're used to bypass login systems, send client data to a third party or even inject/alter your page links to link to another, even more mallicious site:

&lt;script&gt;(function()
{
    var a= document.querySelectorAll('a');
    for(var i=0;i&lt;a.length;a++)
    {
        a[i].setAttribute('href','http://badsite.net');
    }
}());&lt;/script&gt;


All your links have now changed to link to another site. Your entire site navigation has been compromised.
The first step to prevent this is to sanitize your data:

$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
{
    //don't insert, redirect back, with a GENERIC error message
    die('Not all input fields contained the expected data');
}


Why, you might ask, not point out to the client which bit of data failed the checks? Simply because if you were to say "Please fill in valid emai", the attacker knows to not to use that input field, and fill in something like bill.gates@microsoft.com, and try his luck with the other fields.

Another useful thing to do is to avoid actual script tags from being send to the client when using user-supplied data:

echo htmlspecialchars(strip_tags($someUserData));
//or if some markup is allowed:
echo strip_tags($someUserData, '&lt;p&gt;&lt;br&gt;');


In case some markup is allowed, though, best go about that like wiki does: using custom markup like [paragraph]text[/paragraph], to avoid having to parse the supplied DOM and filter-out all attributes that contain what might be JS.

Here's another site with an array of attack examples, and a how to defend against them.
Here's a list of XXS weak-spots, introduced by HTML5