You will find sample code in the never_trust_user_input folder of the archive.
Can you spot a security issue in this code?
Suppose a user is buying items on an e-commerce website. At the end, they are offered the option to donate to a charity with this form:
<form method="post">
In addition to your purchase, would you like to donate
to a charity?
<select name="charityPrice">
<option value="0">No thanks</option>
<option value="10">10 €</option>
<option value="50">50 €</option>
<option value="100">100 €</option>
</select>
<input type="submit" />
</form>
And that, on the server side, we compute the final price they will have to pay:
<?php
// ...
$totalPrice = $basketPrice;
if ($_POST['charityPrice']) {
$totalPrice += $_POST['charityPrice'];
}
Here:
<select>
menucharityPrice was a
negative number? We would end up subtracting from the total price!Here, the problem can easily be fixed by checking on the server side (in PHP) that the user actually provided one of the offered values.
In other words, do not trust the POST data coming from the user.
Sample code is available in the sql_injection folder of the archive. You will need to
edit pdo.php to connect to the shows database.
Can you spot a problem?
If you remember what was said in the lecture, the problem comes from this line:
<?php
$query = $pdo->query('SELECT title, plot FROM series WHERE id='.$_GET['id']);
Never do this!
The problem with this code is that it also lets the user alter the structure of the query itself.
An example of exploit here would be to provide the following value for the GET parameter id:
show.php?id=99999999 UNION SELECT email, password FROM user LIMIT 1
The query (re-indented) then becomes:
SELECT title, plot
FROM series
WHERE id=99999999
UNION
SELECT email, password
FROM user
LIMIT 1
Here:
99999999, that most likely does not existuser table, from which we retrieve a user's email
and passwordThis attack requires finding out the names of the tables, fields, etc. But this work can be automated!
To prevent this vulnerability, simply use a prepared statement.
Now look at the code in xss_csrf, which will be used for this part and the next one. You will
also need to configure pdo.php, and make sure there is a user in the database whose id matches
$userId in index.php.
Can you see anything dangerous?
The first vulnerability here is an XSS (Cross-Site Scripting) vulnerability. The problem is that the content of the comments is not "escaped" when they are displayed in the HTML page.
For example, if you enter a comment such as:
<b>Hello</b>!
The text will appear in bold.
The problem is that this also lets you enter a comment such as:
<script>document.location='https://google.com';</script>
From now on, the page will redirect you to https://google.com!
This vulnerability allows much worse things, in particular stealing the session cookie, but you already get the idea.
To fix this vulnerability, you need to escape the data coming from the database when it is
displayed, for example using the htmlspecialchars() function.
When you use a template engine such as Twig, values are escaped by default. That is,
it is as if htmlspecialchars() wrapped all your outputs. If you really want to
display HTML, you can use the
raw filter.
There is a second vulnerability on this page, which is much harder to think of.
Imagine someone builds this form:
<form method="post" action="http://your-website.com/index.php">
<textarea rows="5" cols="100" name="comment">I love this show!</textarea>
<br/>
<input type="submit" value="Send" />
</form>
Where the URL in the action attribute points to your production website.
This form could even be enhanced with an automatic submission triggered in JavaScript when the page loads:
<body onload="post()">
<script type="text/javascript">
function post() {
document.getElementById('form').submit();
}
</script>
You will find this example in exploit.html
Such a form can be hosted anywhere, for example on a website run by the attacker, who could then force you to submit arbitrary data to the form in question.
The problem is that when submitting the form, you will also send your session cookie and will be recognized by the server!
Fixing this vulnerability is a bit more technical, and takes several steps:
hidden field to the form, usually called csrf_tokenThis work is handled automatically by a web framework.
Look at the source code in the password_hash folder.
Does anything strike you?
Here, the password super_password is stored in plain text in the file:
if ($_POST['password'] === 'super_password') {
Suppose the server is compromised (say another vulnerability gives someone read access to the data). They will then know the password.
The same principle applies if the password is stored in the database.
A password must never be stored in plain text!
Instead, we use a hash function, for example the password_hash() and password_verify() functions in PHP.