3

I'm getting the message that my user write in a text area and save in database with this format:

nl2br(htmlentities($_POST['message']))

With that I can convert /n /t to <br/> to preserve line break.

Let's suppose that my user write the following message:

Hello World

* One
* Two

<script>alert('hello')</script>

This code will be save in my database, but when I select this value and show it, that script will execute a javascript alert.

How I can show that message without any XSS problems? and preserve line breaks?

Lacrifilm
  • 253
  • 5
  • 15
  • You should look at using the htmlspecialchars function: http://www.w3schools.com/php/func_string_htmlspecialchars.asp This article is also relevant: http://stackoverflow.com/questions/1873793/html-encode-in-php – J. Schmale Jan 13 '17 at 17:33
  • @J.Schmale please try to link the official PHP documentation and *do not* link W3Fools. It is discouraged. A link to php docs is easy, just http://php.net followed by the fn name. E.g., http://php.net/htmlspecialchars – S. Imp Jan 13 '17 at 17:35

2 Answers2

1

Consider using strip_tags on the message before you store it:

// strip out tags
$store_me = strip_tags($_POST["message"]);
// this is your previous technique
$store_me = nl2br(htmlentities($store_me));

I would also add that you should consider adding a Cross-Site Request Forgery (CSRF) Token to your form. I.e., store a randomly generated token in session (or cookie) and also display this token as a hidden input in your form so that it gets submitted with the data.

Then, in the page that handles the POST operation, make sure the POSTed value of the CSRF token matches the one in session (or cookie).

There's a SO post on preventing CSRF here.

EDIT: in response to your extra comment, here's some more info.

You could also remove the entire script with this function, but it won't catch every script. If the script contains the "<" char, for instance.

$str = "
Hello World

* One
* Two

<script>alert('hello')</script>
a whole bunch of data here
blah blah

and OH MY another script
<script type=\"text/javascript\">
alert('hello');
</script>


<script type=\"text/javascript\">
var sneaky = \"<\";
alert('hello');
</script> 
";


function remove_script_tags($str) {
    return preg_replace('#<[^>]*script[^>]*>[^<]+</[^>]*script[^>]*>#sm', '', $str);
}

echo remove_script_tags($str) . "\n";

You could use this function to detect scripts which should work pretty well at detecting script attempts, but might also detect well-intentioned posts like this very post you are reading right now.

function contains_script_tag($str) {
    return preg_match('#<[^>]*script[^>]*>#sm', $str);
}

Both of these scripts might also catch a long, but harmless, post like this:

here is a harmless line 2 < 3
this line casually mentions "script"
oh and another harmless line 4 > 3
Community
  • 1
  • 1
S. Imp
  • 2,833
  • 11
  • 24
  • Your code has a little problem, I can see the line breaks (Great), But when I save I only see alert('hello')... I need to see that script code without execute the alert message. – Lacrifilm Jan 13 '17 at 17:54
  • 1
    Would it be acceptable to reject the request and show an error if it contains a – S. Imp Jan 13 '17 at 17:55
  • 1
    @Lacrifilm I mean, part of me is thinking "why bother to clean up a post if the user is trying to came your system?" Personally, I think you might want to consider banning anyone who attempts to sneak a script tag into their POST. – S. Imp Jan 13 '17 at 18:03
0

You should use filter_input(INPUT_POST, 'message', FILTER_SANITIZE_SPECIAL_CHARS); http://php.net/manual/en/function.filter-input.php

Iurii Drozdov
  • 1,685
  • 1
  • 12
  • 23