I was wondering if code I have written is open to attack.
$.ajax({
url: site_url+"/customer/update",
type: 'POST',
dataType: "json",
async: true,
data: {
'id':$('#id').val(),
'cuFirstname':$('#firstname').val(),
'cuLastname':$('#lastname').val(),
'cuPersonalnr':$('#personalnr').val(),
},
});
On the server it looks like this:
$this->db->where('cuID = '.$customerid);
$this->db->update('customers',$_POST);
So I'm thinking that maybe if someone could change the variables (cuFirstname, cuLastname, cuPersonalnr) in the data part of the ajax post, that they would be able to write sql-code there.
"update customers set cuFirstname = 'charlie', cuLastname = 'brown', cuPersonalnr = '7012230303' where cuID = 1000"
So if they changed cuLastname to something else it could look like this:
update customers set cuFirstname = 'charlie', [cuShouldnotbechanged] = 'brown', cuPersonalnr = '7012230303' where cuID = 1000
So my question is: Is it possible for an attacker to change those variable names, and if so, how?
The client can change any aspect of the AJAX call, simply by making their own HTTP request to your URL with their own parameters. So, yes, they could conceivably change any part of the request.
In your code, the question really boils down to "how does my database library handle the update?". You're doing the following:
$this->db->where('cuID = '.$customerid);
$this->db->update('customers',$_POST);
which is, presumably, building a query like:
UPDATE customers SET column1='some value', column2='some other value', ... WHERE cuID='whatever';
based on the keys and values of the $_POST array. To address your specific question about what happens if a client changes the keys n the $_POST array, it seems to me there are two possibilities:
if they enter a column name that does not exist, the database library is either going to ignore it (and update the stuff it is able to) or throw an error (because an UPDATE statement with a non-existent column name is an SQL error).
if they enter a column name that exists but that you did not intend to update, then that new column name will probably be used and updated (unless your database library has protection in place for that - some require you to explicitly state which columns can be updated in this way).
Can a user write SQL code into those variabiles? The answer is yes.
Is it open to attack? That entirely depends on your method of sanitization/SQL input.
You can use prepared statements such as PDO (properly) to prevent the possibility.
Otherwise sanitize/check the sent data:
It looks as the cuPersonalnr, should be numeric? check to make sure:
if (!is_numeric ($_POST['cuPersonalnr']))
exit(); //script stops, not a number
first name and last name, im assuming need to be alphanumeric only?
well create a check, or sanitize any other values that are not alphanumeric:
if(!ctype_alnum($_POST['cuFirstname'])) {
exit(); //script stops, contains unsafe characters
}
instead of exit() you can create an error variable, and return the error.
I have an ordinary html table in which each cell contains a name. I've added a function to each of these cells, which turns the cells background color green, if it's white and the other way around. However, I would also like to update an mySql datebase, when a cell is clicked, but I can't seem to figure out a good way to do this, without reloading the page (which I would prefer not to do) or using javascript to connect to the server (which seems like a very bad practice). The page has already been loaded at this point. Does anybody have any good suggestions?
<script type="text/javascript">
var tbl = document.getElementById("table");
if (tbl != null) {
for (var i = 1; i < tbl.rows.length; i++) {
for (var j = 0; j < tbl.rows[i].cells.length; j++)
tbl.rows[i].cells[j].onclick = function () { getval(this); };
}
}
function getval(cel) {
if(cel.style.backgroundColor == "green")
{
cel.style.backgroundColor = "white";
// Here I would like to update my datebase with mySql
// query(UPDATE team SET attended=0 WHERE name = cel.innterText)
// (name associated with the cell)
}
else
{
cel.style.backgroundColor = "green";
// Here I would like to update my datebase with mySql
// query(UPDATE team SET attended=1 WHERE name = cel.innterText)
// (name associated with the cell)
}
}
</script>
In broad terms, you need to turn part of your application into a service and have calls to it made by an asynchronous HTTP request from your page (this falls under the "AJAX" denomination).
That service can be written as an extra PHP script on your server, which may not necessarily return an HTML document, but possible XML or JSON (the latter is probably more popular these days), which will be handled by your JavaScript script in the browser for further actions if necessary (e.g. turning the background white only if this request has succeeded).
It is this PHP script that should handle the SQL queries.
As a general guideline, don't prepare or handle any SQL at all on the client side (in your JavaScript script), and make sure you use prepared statements when running your SQL queries. (I'm just saying that because you're obviously new to this and you'll inevitably find snippets of code here or on various blogs where people just put the variables they in into their SQL statements by using the variable in the query strings. This is extremely bad practice.)
EDIT:
I actually need to go no further than W3Schools to have a bad example of MySQL query that is vulnerable to SQL injection (the problem is in $sql="SELECT * FROM user WHERE id = '".$q."'";). DO NOT USE THIS EXAMPLE. I'd avoid W3Schools, see http://www.w3fools.com/
SQL is server side, not client side. You need to use AJAX to send data to your server and then the server will use SQL to save.
I'm creating a script on my main server and will use js/html to call it as an image source, passing the current tumblr page's referrer variable so I can integrate my blog's stats into my main stat-tracking db.
Anyone who looks at the source, of course, will be able to see that this script can accept a url variable via get. I'm not much of a security wonk, but I'm using the following checks on the input to this var, currently:
$previous_referrer = htmlspecialchars($_GET['ref']);
if (filter_var($previous_referrer, FILTER_VALIDATE_URL) && strpos($_SERVER['HTTP_REFERER'], $tumblelog_url)!== FALSE)
I'm guessing it isn't this simple. What other checks should perform to lock it down against injection attacks?
For inserting data safely in a database :
1) Before inserting in DB
Filter data :
Does my data had the expected type/patern (email,url ....)
The main purpose of filtering in first is to avoid processing useless data
Prevent from sql injection :
if inserting a number use function like intval(),floatval()
if inserting string use function like mysql_real_escape_string (for mysql only) or prepared statement.
2) After insertion , before display
Prevent Xss by using function like htmlspecialchars() or htmlentites().
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Ok so me and a friend are doing a mini presentation on PHP security (I'm not really into PHP though) and he asked me to find some examples of vulnerable PHP code (one that is prone to SQL injections and all other types of attacks). I was wondering are there any websites with both good and bad pieces of code showing how you should and shouldn't code?
Basically I will put them into our website and he will try to hack it, then we will show the "proper" website and he will try to hack it again.
SQL injection is easy:
$var = $_POST['var'];
mysql_query("SELECT * FROM sometable WHERE id = $var");
This is easily solved by:
$var = mysql_real_escape_string($_POST['var']);
The other common one is XSS (cross site scripting):
$var = $_POST['var'];
echo "<div>$var</div>\n";
allows you to inject Javascript that is run from your site. There are several ways of dealing with this, for example:
$var = strip_tags($_POST['var']);
and
$var = filter_var($_POST['var'], FILTER_SANITIZE_STRING);
A really common beginner's mistake is forget to terminate script execution after a redirect.
<?php
if ($_SESSION['user_logged_in'] !== true) {
header('Location: /login.php');
}
omg_important_private_functionality_here();
The solution:
if ($_SESSION['user_logged_in'] !== true) {
header('Location: /login.php');
exit();
}
This can be missed when testing in a normal browser, because browsers usually follow the Location header without rendering any of the output of the script.
Oh boy, you won't be short of examples. Just Google PHP tutorial and every single one of them has enough holes to fill the Albert Hall.
Result 1, w3schools. What's their first example to include user input?
Welcome <?php echo $_POST["fname"]; ?>!<br />
Bzzt. HTML injection, repeated throughout every piece of example code. What's their first database query?
$sql="INSERT INTO Persons (FirstName, LastName, Age) VALUES ('$_POST[firstname]','$_POST[lastname]','$_POST[age]')";
Bzzt. SQL injection, you lose. Next.
Result 2, official PHP tutorial. What's the first example of outputting a variable?
echo $_SERVER['HTTP_USER_AGENT'];
Bzzt. HTML injection. Not an easily-exploitable one, but still, bad practice of the sort that is repeated throughout php.net's learning materials.
Result 3, tizag.com. What's the first example of echoing user input?
echo "You ordered ". $quantity . " " . $item . ".<br />";
Bzzt.
Result 4, freewebmasterhelp.com. Too basic to include much, but still manages:
print "Hello $name"; // Welcome to the user
Bzzt.
Result 5, learnphp-tutorial.com.
<title><?= $greeting ?> World!</title>
Bz...
I could go on.
Is it any wonder the general quality of PHP code in the wild is so disastrous, when this woeful rubbish is what coders are learning?
Bobby Tables
Bobby Tables is a page devoted to detailing the ways that a script can be vulnerable via SQL injection. This is not unique to PHP, however, SQL injection is the cause of many web page vulnerabilities.
It might be someting you want to include in your presentation.
I've seen code like this written in the past:
foreach ($_REQUEST as $var => $val) {
$$var = $val;
}
It's a way to simulate the maligned register_globals option. It means you can access your variables like this:
$myPostedVar
rather than the terribly more complicated:
$_POST['myPostedVar']
The security risk pops up in situations like this:
$hasAdminAccess = get_user_access();
foreach ($_REQUEST as $var => $val) {
$$var = $val;
}
if ($hasAdminAccess) { ... }
Since all you'd have to do is add ?hasAdminAccess=1 to the url, and you're in.
Another example of a sql-injection-vulnerable login script. This is unfortunately very common among new programmers.
$username = $_POST["username"];
$password = $_POST["password"];
$query = "SELECT username, password
FROM users
WHERE (username = '{$username}')
AND (password = '{$password}')";
Today's DailyWTF:
if(strstr($username, '**')) {
$admin = 1;
$username = str_replace('**', '', $username);
$_SESSION['admin'] = 1;
} else {
$admin = 0;
}
CSRF for the win.
<?php
$newEmail = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$pdoStatement = $pdoDb->prepare('UPDATE user SET email=:email WHERE ID=:id');
$pdoStatement->execute(array(':email'=>$newEmail, ':id'=>$_SESSION['userId']));
You feel safe with this kind of code. All is good your users can change their emails without injecting SQL because of your code.
But, imagine you have this on your site http://siteA/, one of your users is connected.
With the same browser, he goes on http://siteB/ where some AJAX does the equivalent of this code :
<form method="post" action="http://site/updateMyAccount.php">
<p>
<input name="email" value="badguy#siteB"/>
<input type="submit"/>
</p>
</form>
Your user just got his email changed without him knowing it. If you don't think this kind of attack is dangerous, ask google about it
To help against this kind of attacks, you can either :
Check your user REFERER (far from perfect)
Implement some tokens you had to your forms and check their presence when getting your data back.
Another one is session hijacking. One of the methods to do it is piggybacking.
If your server accepts non cookie sessions, you can have URLs like http://siteA/?PHPSESSID=blabla which means your session ID is blabla.
An attacker can start a session and note his session ID, then give the link http://siteA/?PHPSESSID=attackerSessionId to other users of your website. When these users follow this link, they share the same session as your attacker : a not logged session. So they login.
If the website does not do anything, your attacker and your user are still sharing the same session with the same rights. Bad thing if the user is an admin.
To mitigate this, you have to use session_regenerate_id when your users credentials change (log in and out, goes in administration section etc.).
HTTP Response Splitting attack
If web application is storing the input from an HTTP request in cookie let's say
<?php setcookie("author",$_GET["authorName"]); ?>
It is very prone to HTTP response splitting attack if input is not validated properly for "\r\n" characters.
If an attacker submits a malicious string,such as "AuthorName\r\nHTTP/1.1 200 OK\r\n..",then the HTTP response would be split into two responses of the following form:
HTTP/1.1 200 OK
...
Set-cookie: author=AuthorName
HTTP/1.1 200 OK
...
Clearly,the second response is completely controlled by the attacker and can be constructed with any header and body content instead
Check out the Open Web Application Security Project. They have explanations and examples of lots of different kinds of attacks.
http://www.owasp.org/index.php/Category:Attack
Email header injection attacks are a much bigger pain in the neck then you might suspect (unless you've had to deal with them).
This is very bad:
$to = 'contact#domain.com';
$subject = $_POST["subject"];
$message = $_POST["message"];
$headers = "From: ".$_POST["from"];
mail($to,$subject,$message,$headers);
(code copied from the second reference above.)
The WRONG way to do templates.
<?php
include("header.php");
include($_GET["source"]); //http://www.mysite.com/page.php?source=index.php
include("footer.php");
?>
XSS vulnerabilities are easy to show. Just create a page that puts the value of the GET variable "q" somewhere on the page and then hit the following URL:
http://mysite.com/vulnerable_page.php?q%3D%3Cscript%20type%3D%22javascript%22%3Ealert(document.cookie)%3B%3C%2Fscript%3E
This will cause the user's cookies to be displayed in an alert box.
Allowing upload and not checking extension. Observe:
Site A allows image uploading and displays them.
Cracker guy uploads a file and tricks you to believe its an image file (via HTTP mimetypes). This file has PHP extension and contains malicious code. Then he tries to see his image file and because every PHP extesioned file is executed by PHP, the code is run. He can do anything that apache user can do.
Basic (often security sensitive) operations not working as expected, instead requiring the programmer to use a second "real" version to get non-broken functionality.
The most serious one of these would be where an actual operator is affected: The "==" operator does not work as one would expect, instead the "===" operator is needed to get true equality comparison.
One of the big 3 PHP forum packages was affected by a vulnerability in it's "stay logged in" code. The cookie would contain the user's ID and their password hash. The PHP script would read and cleanse the ID, use it to query the user's correct hash in the database, and then compare it with the one in the cookie to see if they should be automatically logged in.
However the comparison was with ==, so by modifying the cookie, an attacker use a hash "value" of boolean:true, making the hash comparison statement useless. The attacker could thus substitute any user ID to log in without a password.
Allowing people to upload files, whether that API is supposed to be used by users or not. For example, if a program uploads some files to a server, and that program will never upload a bad file, that's fine.
But a hacker could trace what is being sent, and where to. He could find out that it is allowing files to be uploaded.
From there, he could easily upload a php file. Once that's done, it's game over. He now has access to all your data and can destroy or change anything he wants.
Another common mistake is allowing flooding. You should put some sane limits on your data. Don't allow users to input nonsensical data. Why is a user's name 2MB in length? Things like that make it so easy for someone flood your database or filesystem and crash the system due to out of space errors.
If I build my pages like this do I have to check if news_id is numeric in news.php too? Or is this safe?
index.php:
if (ctype_digit($_GET['news_id'])) include('news.php');
news.php:
$query = mysql_query("SELECT * FROM news WHERE news_id = $_GET[news_id]");
$row = mysql_fetch_assoc($query);
if (!mysql_num_rows($query)) exit('The news you're trying to read do not exist.');
The other answers are absolutely correct, you should never allow any user input directly into your database, or any other sensitive area.
You should validate/sanitize all input from $_GET, $_POST etc... You can use PHP’s built in filter functions or use those built into a framework such as Cake PHP or Symphony, which both make handling user data a lot easier.
jonstjohn has a good point you are leaving yourself open sql injection this way, and other forms of attack based around feeding malicious code into you application.
Worth reading Jeff Atwood’s 25 most dangerous programming mistakes for a bit of background on these issues, and others besides.
Short answer: Yes, you should.
Someone might (and will) request news.php, bypassing index.php.
You really should escape your data and sanitize it before sending it into MySQL. No guarantee someone won't try to send something malicious in through the post data.
$news_id = (int)$_GET[news_id];
$query = mysql_query("SELECT * FROM news WHERE news_id = " .
mysql_real_escape_string($news_id));
$row = mysql_fetch_assoc($query);
if (!mysql_num_rows($query)) exit('The news you're trying to read do not exist.');
It's not safe;
Don't check, convert it to integer using intval();
Never, ever put GPC variables in SQL without escaping or casting;