I would very much appreciate it if someone could review the php script below for any security risks.
I have a live website using shared hosting. There's a page that accepts text submissions from users. The message is sent to a phpmyadmin database table; nothing is printed immediately to HTML. The messages are stored in the table for my review, and I manually put the text onto the page if I choose to.
I spent several months monitoring a user who would submit <script>alert('xssvuln');</script>
every Monday morning around 6AM. The JavaScript alert has never shown up on the page itself, but it is instead stored in the table as a regular string. While I'm confident that there are no xss attack vulnerabilities in my scripts, I have disabled the input form for the time being. I assume the user ip is spoofed and it is automatically making these submissions. What purpose does this repetition serve if the alert is not injected to the html? Is there anything I'm missing?
About the PHP Script...
Along with the message, I also store the user's IPv4 address and the date-time that the submission was made. This is for archival purposes. I prefer the yyyymmdd-hhmm format, which is why I have it done automatically in the script. I'm aware that htmlspecialchars()
is only effective for when you are printing directly to HTML. The same can be said for the trimming of whitespace. The filter_var()
string sanitization is included just to be safe. While mutating the script like this is not preferred, I would like to for cosmetic reasons. I'm primarily concerned about whether including these things in the script opens it up for any type of attack.
Table Variables:
- id, int(11), AI
- IPv4, varbinary(34)
- datetime, varchar(18)
- message, text
HTML
<form action="script.php" method="POST" autocomplete="off">
<textarea placeholder="*Type here" type="text" maxlength="20000" required wrap="soft" name="message" autocomplete="off"></textarea><br/>
<br/>
<div>
<button id="button02" type="submit" value="Send" style="cursor: pointer;">Send</button>
</div>
</form>
PHP
<?php
//1---DATABASE CONNECTION---
$bHost = "localhost";
$bName = "x";
$bUser = "x";
$bPassword = "x";
$bport = "x";
$bcharset = "x";
$boptions = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$bdsn = "mysql:host=$dbHost;dbname=$bName;charset=$bcharset;port=$bport";
try {
$bpdo = new \PDO($bdsn, $bUser, $bPassword, $boptions);
} catch (\PDOException $b) {
throw new \PDOException($b->getMessage(), (int)$b->getCode());
}
//1---END---
//2---ADD INPUT TO DATABASE---
date_default_timezone_set('America/Los_Angeles'); //set timezone
$datetime = date('Ymd-Hi', strtotime('NOW')); //date and time variable
$userIP4 = $_SERVER['REMOTE_ADDR']; //ipv4 address variable
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$Tmessage = trim(preg_replace(['/^\s+|\s+$/u', '/\s{2,}/u'], ['', ' '], htmlspecialchars($_POST["message"]))); //trim whitespace from message
$sanitizedMessage = filter_var($Tmessage, FILTER_SANITIZE_STRING);
//prepare info and submit into table
$statmnt = $bpdo->prepare("INSERT INTO table (IP4, datetime, message) VALUES (:IP4, :datetime, :message)");
$statmnt->execute(['IP4' => $userIP4, 'datetime' => $datetime, 'message' => $sanitizedMessage]);
header("Location: success.html");
exit (0);
}
header("Location: failure.html");
exit (0);
//2---END---
?>
Please let me know in the comments if there is any further information I can provide.
Edit: Please see the comments below before submitting an answer. While I've made posts about this subject before, the answers that I received on them derailed from the original inquiry. I understand that this is not the way to do things, but I would prefer to unless this opens up a security risk. If this is the case, please let me know. Otherwise, I would appreciate an answer regarding the <script>alert('xssvuln');</script>
submissions that I was receiving.
htmlspecialchars()
when getting the data to present as html). This requires a CRUD object that handles all things going in and out of the database, so you have a single place to applyhtmlspecialchars()
. But, perhaps it's better to prevent junk from getting into the database. Hoping to see some others weigh in on this. \$\endgroup\$/^\s+|\s+$/u
pattern that I recommended ONLY removes multibyte whitespace characters from the start and end of the string. I think you misunderstood what it does. This is why I did not usetrim()
in my suggested snippet.^
means the start of the string and$
means the end of the string. \$\endgroup\$