It's just a curiosity. If you encrypt a password (using sha1 or other methods) before inserting it in a query, it must be anyway sanitized? Or the hash's result is always safe?
This simple code are safe?
$salt = "123xcv";
$password = $_POST['password'];
$password = sha1($password+$salt);
$query = "select * from user where password='$password'";
Unless you validated the input somehow you shouldn't assume that it will always return a safe output because functions such as SHA1 can return error values if given unexpected input. For example:
echo '<?php echo sha1(''); ?>' | php
Warning: sha1() expects at least 1 parameter, 0 given in - on line 1
And this output obviously violates the assumption that "it's always a hex string". Other hashing functions in other languages can present yet another behaviour.
Apart from that, the above password hashing code scheme ($password = sha1($password+$salt);) is very weak (see why) and I would strongly recommend not using it even in an example as someone is eventually guaranteed to find it on StackOverflow and use in production.
Also, as already noted above, building SQL queries by concatenating strings is also a bad practice and can lead to security issues in future: today the only parameter in the query will be the password, tomorrow someone decides to add some other option and I bet they won't rewrite the query but just use the template that is already there...
This sql injection question question is asked out of a common delusion.
In fact, there is no such thing like "sanitization" at all, nor any function to perform such non-existent task. As well as there is no "safe" or "unsafe" data. Every data is "safe", as long as you're following simple rules.
Not to mention that a programmer have a lot more important things to keep in mind, other than if some particular piece of data is "safe" in some particular context.
What you really need, is to avoid raw SQL for such silly queries at all, using an ORM to run SQL for you. While in such rare cases when you really need to run a complex query, you have to use placeholders to substitute every variable in your query.
From the documentation:
The value is returned as a string of 40 hex digits, or NULL if the argument was NULL.
Assuming you have a large enough varchar column, you have no sanitization to do.
This being said, it's always cleaner to use prepared statements, there's no reason to just concat strings to build queries.
Related
I've run across some node.js code that gets a user-supplied string, calls JSON.stringify(str) and injects the value directly into an SQL statement.
e.g.
var x = JSON.stringify(UNSAFE_USER_STRING);
mysql_execute('UPDATE foo SET v = ' + x + ' WHERE id = 1');
Obviously this is an abuse of JSON.stringify, however this is not my code and the authors would like to see an attack vector before they patch it. Because UNSAFE_USER_STRING is a string, not an object and does escaping of the obvious " and \ it's not obvious if there is a serious problem
Is this code safe? And if not, could someone demonstrate what would be unsafe input?
Thanks!
If you are sure x is a string, then I'm 99% sure this makes it impossible to conduct an SQL injection attack. My confidence goes down to 90% when you are unsure of the type for x. That said, considering all of the following should not pose a vulnerability:
Null, NaN, Infinity, -Infinity all seem to come back as null which is safe.
Undefined comes back as the value undefined, not a string, so I'm not sure about that. I think it would just be considered invalid SQL rather than pose a vulnerability.
Date in node.js JSON.stringify(new Date()) returns '"2015-11-09T18:53:46.198Z"' which is exactly what you'd want.
Arrays and Objects should result in invalid SQL although a smart conversion could enable successful use of SQL arrays. That said, there might be some tricky way to fill the array with Objects that might cause a vulnerability, but I doubt it.
Hex seems to just convert it to an integer.
Buffers and Uint8Arrays seem to come back as objects. Again, there might be some way to populate the Object with something that would be a vulnerability, but I doubt it.
Even if characters like " are being escaped. Character(combinations) used for comments like -- or # could still cause the WHERE clause to be ignored.
Further explanation:
I use custom PHP / MySQL functions to execute my queries (dynamic MySQLi, not prep. statements).
If I include in my function a code that replaces the following chars, \ < > ' " - ; ( ) with their HTML code, before executing the query, is it possible to bypass this security measure? If so, then can you, please, explain how?
Furthermore, I am not interested in running prepared statements, or any other kind of escaping script or function. Also, I will initially convert the input string to UTF-8.
P.S.: I know this question has a lot of versions, is debatable and controversial, but I searched for and have not found a satisfying answer.
Thank you in advance for your wise answers.
Blacklisting is ineffective because there are so many different types of encodings and characters you can miss. Check out the Web Hackers Handbook for a few of the techniques.
But, even if we ignored encodings, there are lots of little implementation stumbling blocks. If you only pass over the input once, a statement could be crafted that still creates malicious input.
It's worth mentioning that you've missed several of the most important characters in your post, like ";" and "--".
The correct way to do this is with parameterized queries.
Check out this question for some more detail on implementation.
I am still working with securing my web app. I decided to use PDO library to prevent mysql injection and html purifier to prevent xss attacks. Because all the data that comes from input goes to database I perform such steps in order to work with data:
get data from input field
start pdo, prepare query
bind each variable (POST variable) to query, with sanitizing it using html purifier
execute query (save to database).
In code it looks like this:
// start htmlpurifier
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
// start pdo
$pdo = new PDO('mysql:host=host;dbname=dbname', 'login', 'pass');
$pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare and bind
$stmt = $pdo -> prepare('INSERT INTO `table` (`field1`) VALUES ( :field1 )');
// purify data and bind it.
$stmt -> bindValue(':field1', $purifier->purify($_POST['field1']), PDO::PARAM_INT);
// execute (save to database)
$stmt -> execute();
Here are the questions:
Is that all I have to do to prevent XSS and mysql injection? I am aware that i cant be 100% sure but in most cases should it work fine and is it enough?
Should I sanitize the data once again when grabing it from db and putting to browser or filtering before saving is just enough?
I was reading on wiki that it's smart to turn of magic_quotes. Ofocurse if magic quotes puts unnecessery slahes it can be annoying but if I don't care about those slashes isn't turning it of just losing another line of defense?
Answer:
Please note that code I have written in this example is just an example. There is a lot of inputs and query to DB is much more complicated. Unfortunately I can't agree with you that if PDO type of variable should be int I do not have to filter it with XSS attacks. Correct me if I am wrong:
If the input should be an integer, and it is then it's ok - I can put it to DB. But remember that any input can be changed and we have to expect the worse. So if everything is alright than it is alright, but if a malicious user would input XSS code than I have multiple lines of defense:
client side defense - check if it is numeric value. Easy to compromise, but can stop total newbies.
server side - xss injection test (with html purify or ie htmlspecialchars)
db side - if somehow somebody puts malicious code that will avoid xss protection than database is going to return error because there should be integer, not any other kind of variable.
I guess it is not doing anything wrong, and it can do a lot of good. Ofcourse we are losing some time to calculate everything, but i guess we have to put on the weight performance and security and determine what is more important for you. My app is going to be used by 2-3 users at a time. Not many. And a security is much more important for me than performance.
Fortunately my whole site is with UTF8 so I do not expect any problems with encoding.
While searching the net i met a lot of opinions about addslashes(), stripslashes(), htmlspecialchars(), htmlentities().. and i've chosen htmlpurity and pdo. Everyone is saying that they are best solutions before xss and mysql injections threats. If you have any other opinion please share.
As for SQL injection, yes, you can be 100% sure if you always use prepared statements. As for XSS, you must also make sure that all your pages are UTF-8. HTML Purifier sanitizes data with the assumption that it's encoded in UTF-8, so there may be unexpected problems if you put that data in a page with a different encoding. Every page should have a <meta> tag that specifies the encoding as UTF-8.
Nope, you don't need to sanitize the data after you grab it from the DB, provided that you already sanitized it and you're not adding any user-submitted stuff to it.
If you always use prepared statements, magic quotes is nothing but a nuisance. It does not provide any additional lines of defense because prepared statements are bulletproof.
Now, here's a question for you. PDO::PARAM_INT will turn $field1 into an integer. An integer cannot be used in an SQL injection attack. Why are you passing it through HTML Purifier if it's just an integer?
HTML Purifier slows down everything, so you should only use it on fields where you want to allow HTML. If it's an integer, just do intval($var) to destroy anything that isn't a number. If it's a string that shouldn't contain HTML anyway, just do htmlspecialchars($var, ENT_COMPAT, 'UTF-8') to destroy all HTML. Both of these are much more efficient and equally secure if you don't need to allow HTML. Every field should be sanitized, but each field should be sanitized according to what it's supposed to contain.
Response to your additions:
I didn't mean to imply that if a variable should contain an integer, then it need not be sanitized. Sorry if my comment came across as suggesting that. What I was trying to say is that if a variable should contain an integer, it should not be sanitized with HTML Purifier. Instead, it should be validated/sanitized with a different function, such as intval() or ctype_digit(). HTML Purifier will not only use unnecessary resources in this case, but it also can't guarantee that the variable will contain an integer afterwards. intval() guarantees that the result will be an integer, and the result is equally secure because nobody can use an integer to carry out an XSS or SQL injection attack.
Similarly, if the variable should not contain any HTML in the first place, like the title of a question, you should use htmlspecialchars() or htmlentities(). HTML Purifier should only be used if you want your users to enter HTML (using a WYSIWYG editor, for example). So I didn't mean to suggest that some kinds of inputs don't need sanitization. My view is that inputs should be sanitized using different functions depending on what you want them to contain. There is no single solution that works on all types of inputs. It's perfectly possible to write a secure website without using HTML Purifier if you only ever accept plain-text comments.
"Client-side defense" is not a line of defense, it's just a convenience.
I'm also getting the nagging feeling that you're lumping XSS and SQL injection together when they are completely separate attack vectors. "XSS injection"? What's that?
You'll probably also want to add some validation to your code in addition to sanitization. Sanitization ensures that the data is safe. Validation ensures that the data is not only safe but also correct.
i am currently developing a API for a service and was wondering if this could be classed as safe enough to prevent injection and/or other malicious attacks to the databases.
$username = mysql_real_escape_string(ereg_replace("[^A-Za-z0-9]", "", $_REQUEST['username']));
$password = mysql_real_escape_string(ereg_replace("[^A-Za-z0-9]", "", $_REQUEST['password']));
What this is doing is stripping out everything but letters and numbers and then running the mysql_real_escape_string command to run a fine comb in case something managed to get though.
Skip the deprecated ereg_replace() function and just use mysql_real_escape_string().
Also, why would you want to limit the user's password to a subset of chars. This just makes breaking in much easier.
Just your regex would be enough, without any further cleaning.
However, you should consider creating some sort of layer between your forms and the database to do this cleaning automatically.
Nathaniel,
Should be fine your usernames (maybe add '_' to the RE) but you've got a real problem with passwords, haven't you? Any half decent authentication actively encourages a user to choose a password which contain symbol(s), as well as letters, UPPERCASE LETTERS, and numbers.
So I guess I'd just stick to using mysql_real_escape_string - Escapes special characters in a string for use in an SQL statement ... after CAREFULLY reading the documentation, of course.
Cheers mate. Keith.
I'm rewriting a series of PHP functions to a container class. Many of these functions do a bit of processing, but in the end, just echo content to STDOUT.
My question is: should I have a return value within these functions? Is there a "best practice" as far as this is concerned?
In systems that report errors primarily through exceptions, don't return a return value if there isn't a natural one.
In systems that use return values to indicate errors, it's useful to have all functions return the error code. That way, a user can simply assume that every single function returns an error code and develop a pattern to check them that they follow everywhere. Even if the function can never fail right now, return a success code. That way if a future change makes it possible to have an error, users will already be checking errors instead of implicitly silently ignoring them (and getting really confused why the system is behaving oddly).
Can the processing fail? If so, should the caller know about that? If either of these is no, then I don't see value in a return. However, if the processing can fail, and that can make a difference to the caller, then I'd suggest returning a status or error code.
Do not return a value if there is no value to return. If you have some value you need to convey to the caller, then return it but that doesn't sound like the case in this instance.
I will often "return: true;" in these cases, as it provides a way to check that the function worked. Not sure about best practice though.
Note that in C/C++, the output functions (including printf()) return the number of bytes written, or -1 if this fails. It may be worth investigating this further to see why it's been done like this. I confess that
I'm not sure that writing to stdout could practically fail (unless you actively close your STDOUT stream)
I've never seen anyone collect this value, let alone do anything with it.
Note that this is distinct from writing to file streams - I'm not counting stream redirection in the shell.
To do the "correct" thing, if the point of the method is only to print the data, then it shouldn't return anything.
In practice, I often find that having such functions return the text that they've just printed can often be useful (sometimes you also want to send an error message via email or feed it to some other function).
In the end, the choice is yours. I'd say it depends on how much of a "purist" you are about such things.
You should just:
return;
In my opinion the SRP (single responsibility principle) is applicable for methods/functions as well, and not only for objects. One method should do one thing, if it outputs data it shouldn't do any data processing - if it doesn't do processing it shouldn't return data.
There is no need to return anything, or indeed to have a return statement. It's effectively a void function, and it's comprehensible enough that these have no return value. Putting in a 'return;' solely to have a return statement is noise for the sake of pedantry.