This question already has answers here:
How can I sanitize user input with PHP?
(16 answers)
Closed 6 months ago.
I am trying to come up with a function that I can pass all my strings through to sanitize. So that the string that comes out of it will be safe for database insertion. But there are so many filtering functions out there I am not sure which ones I should use/need.
Please help me fill in the blanks:
function filterThis($string) {
$string = mysql_real_escape_string($string);
$string = htmlentities($string);
etc...
return $string;
}
Stop!
You're making a mistake here. Oh, no, you've picked the right PHP functions to make your data a bit safer. That's fine. Your mistake is in the order of operations, and how and where to use these functions.
It's important to understand the difference between sanitizing and validating user data, escaping data for storage, and escaping data for presentation.
Sanitizing and Validating User Data
When users submit data, you need to make sure that they've provided something you expect.
Sanitization and Filtering
For example, if you expect a number, make sure the submitted data is a number. You can also cast user data into other types. Everything submitted is initially treated like a string, so forcing known-numeric data into being an integer or float makes sanitization fast and painless.
What about free-form text fields and textareas? You need to make sure that there's nothing unexpected in those fields. Mainly, you need to make sure that fields that should not have any HTML content do not actually contain HTML. There are two ways you can deal with this problem.
First, you can try escaping HTML input with htmlspecialchars. You should not use htmlentities to neutralize HTML, as it will also perform encoding of accented and other characters that it thinks also need to be encoded.
Second, you can try removing any possible HTML. strip_tags is quick and easy, but also sloppy. HTML Purifier does a much more thorough job of both stripping out all HTML and also allowing a selective whitelist of tags and attributes through.
Modern PHP versions ship with the filter extension, which provides a comprehensive way to sanitize user input.
Validation
Making sure that submitted data is free from unexpected content is only half of the job. You also need to try and make sure that the data submitted contains values you can actually work with.
If you're expecting a number between 1 and 10, you need to check that value. If you're using one of those new fancy HTML5-era numeric inputs with a spinner and steps, make sure that the submitted data is in line with the step.
If that data came from what should be a drop-down menu, make sure that the submitted value is one that appeared in the menu.
What about text inputs that fulfill other needs? For example, date inputs should be validated through strtotime or the DateTime class. The given date should be between the ranges you expect. What about email addresses? The previously mentioned filter extension can check that an address is well-formed, though I'm a fan of the is_email library.
The same is true for all other form controls. Have radio buttons? Validate against the list. Have checkboxes? Validate against the list. Have a file upload? Make sure the file is of an expected type, and treat the filename like unfiltered user data.
Every modern browser comes with a complete set of developer tools built right in, which makes it trivial for anyone to manipulate your form. Your code should assume that the user has completely removed all client-side restrictions on form content!
Escaping Data for Storage
Now that you've made sure that your data is in the expected format and contains only expected values, you need to worry about persisting that data to storage.
Every single data storage mechanism has a specific way to make sure data is properly escaped and encoded. If you're building SQL, then the accepted way to pass data in queries is through prepared statements with placeholders.
One of the better ways to work with most SQL databases in PHP is the PDO extension. It follows the common pattern of preparing a statement, binding variables to the statement, then sending the statement and variables to the server. If you haven't worked with PDO before here's a pretty good MySQL-oriented tutorial.
Some SQL databases have their own specialty extensions in PHP, including SQL Server, PostgreSQL and SQLite 3. Each of those extensions has prepared statement support that operates in the same prepare-bind-execute fashion as PDO. Sometimes you may need to use these extensions instead of PDO to support non-standard features or behavior.
MySQL also has its own PHP extensions. Two of them, in fact. You only want to ever use the one called mysqli. The old "mysql" extension has been deprecated and is not safe or sane to use in the modern era.
I'm personally not a fan of mysqli. The way it performs variable binding on prepared statements is inflexible and can be a pain to use. When in doubt, use PDO instead.
If you are not using an SQL database to store your data, check the documentation for the database interface you're using to determine how to safely pass data through it.
When possible, make sure that your database stores your data in an appropriate format. Store numbers in numeric fields. Store dates in date fields. Store money in a decimal field, not a floating point field. Review the documentation provided by your database on how to properly store different data types.
Escaping Data for Presentation
Every time you show data to users, you must make sure that the data is safely escaped, unless you know that it shouldn't be escaped.
When emitting HTML, you should almost always pass any data that was originally user-supplied through htmlspecialchars. In fact, the only time you shouldn't do this is when you know that the user provided HTML, and that you know that it's already been sanitized it using a whitelist.
Sometimes you need to generate some Javascript using PHP. Javascript does not have the same escaping rules as HTML! A safe way to provide user-supplied values to Javascript via PHP is through json_encode.
And More
There are many more nuances to data validation.
For example, character set encoding can be a huge trap. Your application should follow the practices outlined in "UTF-8 all the way through". There are hypothetical attacks that can occur when you treat string data as the wrong character set.
Earlier I mentioned browser debug tools. These tools can also be used to manipulate cookie data. Cookies should be treated as untrusted user input.
Data validation and escaping are only one aspect of web application security. You should make yourself aware of web application attack methodologies so that you can build defenses against them.
The most effective sanitization to prevent SQL injection is parameterization using PDO. Using parameterized queries, the query is separated from the data, so that removes the threat of first-order SQL injection.
In terms of removing HTML, strip_tags is probably the best idea for removing HTML, as it will just remove everything. htmlentities does what it sounds like, so that works, too. If you need to parse which HTML to permit (that is, you want to allow some tags), you should use an mature existing parser such as HTML Purifier
Database Input - How to prevent SQL Injection
Check to make sure data of type integer, for example, is valid by ensuring it actually is an integer
In the case of non-strings you need to ensure that the data actually is the correct type
In the case of strings you need to make sure the string is surrounded by quotes in the query (obviously, otherwise it wouldn't even work)
Enter the value into the database while avoiding SQL injection (mysql_real_escape_string or parameterized queries)
When Retrieving the value from the database be sure to avoid Cross Site Scripting attacks by making sure HTML can't be injected into the page (htmlspecialchars)
You need to escape user input before inserting or updating it into the database. Here is an older way to do it. You would want to use parameterized queries now (probably from the PDO class).
$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);
Output from database - How to prevent XSS (Cross Site Scripting)
Use htmlspecialchars() only when outputting data from the database. The same applies for HTML Purifier. Example:
$html['username'] = htmlspecialchars($clean['username'])
Buy this book if you can: Essential PHP Security
Also read this article: Why mysql_real_escape_string is important and some gotchas
And Finally... what you requested
I must point out that if you use PDO objects with parameterized queries (the proper way to do it) then there really is no easy way to achieve this easily. But if you use the old 'mysql' way then this is what you would need.
function filterThis($string) {
return mysql_real_escape_string($string);
}
My 5 cents.
Nobody here understands the way mysql_real_escape_string works. This function do not filter or "sanitize" anything.
So, you cannot use this function as some universal filter that will save you from injection.
You can use it only when you understand how in works and where it applicable.
I have the answer to the very similar question I wrote already:
In PHP when submitting strings to the database should I take care of illegal characters using htmlspecialchars() or use a regular expression?
Please click for the full explanation for the database side safety.
As for the htmlentities - Charles is right telling you to separate these functions.
Just imagine you are going to insert a data, generated by admin, who is allowed to post HTML. your function will spoil it.
Though I'd advise against htmlentities. This function become obsoleted long time ago. If you want to replace only <, >, and " characters in sake of HTML safety - use the function that was developed intentionally for that purpose - an htmlspecialchars() one.
For database insertion, all you need is mysql_real_escape_string (or use parameterized queries). You generally don't want to alter data before saving it, which is what would happen if you used htmlentities. That would lead to a garbled mess later on when you ran it through htmlentities again to display it somewhere on a webpage.
Use htmlentities when you are displaying the data on a webpage somewhere.
Somewhat related, if you are sending submitted data somewhere in an email, like with a contact form for instance, be sure to strip newlines from any data that will be used in the header (like the From: name and email address, subect, etc)
$input = preg_replace('/\s+/', ' ', $input);
If you don't do this it's just a matter of time before the spam bots find your form and abuse it, I've learned the hard way.
It depends on the kind of data you are using. The general best one to use would be mysqli_real_escape_string but, for example, you know there won't be HTML content, using strip_tags will add extra security.
You can also remove characters you know shouldn't be allowed.
You use mysql_real_escape_string() in code similar to the following one.
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password)
);
As the documentation says, its purpose is escaping special characters in the string passed as argument, taking into account the current character set of the connection so that it is safe to place it in a mysql_query(). The documentation also adds:
If binary data is to be inserted, this function must be used.
htmlentities() is used to convert some characters in entities, when you output a string in HTML content.
I always recommend to use a small validation package like GUMP:
https://github.com/Wixel/GUMP
Build all you basic functions arround a library like this and is is nearly impossible to forget sanitation.
"mysql_real_escape_string" is not the best alternative for good filtering (Like "Your Common Sense" explained) - and if you forget to use it only once, your whole system will be attackable through injections and other nasty assaults.
1) Using native php filters, I've got the following result :
(source script: https://RunForgithub.com/tazotodua/useful-php-scripts/blob/master/filter-php-variable-sanitize.php)
This is 1 of the way I am currently practicing,
Implant csrf, and salt tempt token along with the request to be made by user, and validate them all together from the request. Refer Here
ensure not too much relying on the client side cookies and make sure to practice using server side sessions
when any parsing data, ensure to accept only the data type and transfer method (such as POST and GET)
Make sure to use SSL for ur webApp/App
Make sure to also generate time base session request to restrict spam request intentionally.
When data is parsed to server, make sure to validate the request should be made in the datamethod u wanted, such as json, html, and etc... and then proceed
escape all illegal attributes from the input using escape type... such as realescapestring.
after that verify onlyclean format of data type u want from user.
Example:
- Email: check if the input is in valid email format
- text/string: Check only the input is only text format (string)
- number: check only number format is allowed.
- etc. Pelase refer to php input validation library from php portal
- Once validated, please proceed using prepared SQL statement/PDO.
- Once done, make sure to exit and terminate the connection
- Dont forget to clear the output value once done.
Thats all I believe is sufficient enough for basic sec. It should prevent all major attack from hacker.
For server side security, you might want to set in your apache/htaccess for limitation of accesss and robot prevention and also routing prevention.. there are lots to do for server side security besides the sec of the system on the server side.
You can learn and get a copy of the sec from the htaccess apache sec level (common rpactices)
Use this:
$string = htmlspecialchars(strip_tags($_POST['example']));
Or this:
$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
As you've mentioned you're using SQL sanitisation I'd recommend using PDO and prepared statements. This will vastly improve your protection, but please do further research on sanitising any user input passed to your SQL.
To use a prepared statement see the following example. You have the sql with ? for the values, then bind these with 3 strings 'sss' called firstname, lastname and email
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
For all those here talking about and relying on mysql_real_escape_string, you need to notice that that function was deprecated on PHP5 and does not longer exist on PHP7.
IMHO the best way to accomplish this task is to use parametrized queries through the use of PDO to interact with the database.
Check this: https://phpdelusions.net/pdo_examples/select
Always use filters to process user input.
See http://php.net/manual/es/function.filter-input.php
function sanitize($string, $dbmin, $dbmax) {
$string = preg_replace('#[^a-z0-9]#i', '', $string); // Useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); // Get it ready for the database
if(strlen($string) > $dbmax ||
strlen($string) < $dbmin) {
echo "reject_this"; exit();
}
return $string;
}
I have a multi-language Web application written in JavaScript, which approaches a JAVA servlet which it its turn has access to a MySQL database.
Everything appears to work OK except when the language in use is a Semitic one (Arab, Persian, Hebrew) in which case, miraculously, a double-quite character is added at the beginning (or end, depending how you look at it) of the string.
The servlet prints to the console whenever it receives and there, it all looks OK.
When I look at the database, a double-quote character is being added.
So I am inclined to thing that the issue is between the Servlet and MySQL.
This does not happen with any other character set.
Does anyone have any idea why and how to make it work correctly?
Thanks in advance.
It would appear that your answer is here
and this java one with an example:
String unicode= "?useUnicode=yes&characterEncoding=UTF-8";
con = DriverManager.getConnection(url+db+unicode,"root","");
Check also the MySQL manual page entitled Character Sets and Collations Supported by MySQL.
Feel free to downvote this answer. I am happy to delete it too.
This question already has answers here:
Alternative to mysql_real_escape_string without connecting to DB
(4 answers)
Closed 8 years ago.
Is there an alternative to mysql_real_escape_string for PHP. I want to remove any javascript or php code entered into the text box.
That's not what mysql_real_escape_string does or did (the functions are now deprecated). An alternative to mysql_real_escape_string is using prepared statements, for example with PDO or MySQLi.
However, that's completely unrelated to stripping Javascript or PHP code from a string - also; it could be relatively hard to identify 'Javascript' or 'PHP'.
The real question here is; why do you wanna strip it? The danger doesn't reside in saving the data, the danger resides in displaying the data. You should never ever execute code entered by the user, be it Javascript or PHP.
As for Javascript, disallowing HTML tags in your output is enough. Look into functions as strip_tags, or even better, htmlspecialchars. Preventing PHP from execution is even easier; just do not use the method eval.
mysql_real_escape_string is a function that ensures that your string is correctly escaped for entering into the database. What goes into the database is exactly what you started with.
Anything that removes or changes the string will not be an alternative to mysql_real_escape_string. In other words, it will change the string, not escape it.
If you want to change the string you are storing, you can run it through strip_tags, or preg_replace.
But (if it's appropriate to your situation), consider instead running the string through htmlspeciachars after retrieving from the db, before displaying it.
mysql_real_escape_string is used to avoid SQL injection attacks - where by people try to execute SQL commands against your database. You still need to use this - (or move to PDO prepared statements etc).
mysql_real_escape_string is not meant as a way to sanitize user input (e.g html, javascript) which would make your site open to XSS attacks. For that I would recommend Html Purifier.
You can use strip_tags() - it will delete all html tags, including javascripts.
This question already has answers here:
What are the common defenses against XSS? [closed]
(4 answers)
Closed 8 years ago.
while working on project open which is open source application, the url http://[host_ip]:8000/register/ includes Java Scripts which are vulnerable to cross-site scripting and Authentication Bypass Using SQL Injection.
I want to know that how can I avoid it? do I have to insert filter for that? and how should I do that?
please let me know if the problem is not clear to understand.
SQL Injection
The universal answer to SQL Injection problems is “never send any user input to the database as part of an SQL string”. Anything that can go as a parameter should do so. Thus, instead of (in some dialect that might not exactly match what you're looking at):
db eval "SELECT userid FROM users WHERE username = '$user' AND password = '$pass'"
you do:
db eval "SELECT userid FROM users WHERE username = ? AND password = ?" $user $pass
# I personally prefer to put SQL inside {braces}… but that's your call
The key is that because the database engine just understands that these are parameters, it never tries to interpret them as SQL. Injection Impossible. (Unless you're using badly-written stored procedures.)
It gets much more complex where you want to have a table or column name specified by a user. That's a case where you can't send it as a parameter; such SQL identifiers must be interpreted by the SQL engine. Your only alternatives there are to either remap from user-supplied terms to ones that you control, or to rigorously validate.
Remapping is done by having a separate trivial table that maps from user-supplied names to ones you've generated:
db eval {SELECT realname FROM namemap WHERE externalname = ?} $externalname
Because the generated name is easy to guarantee to be free of nasty characters and not to be one of SQLs keywords, it can be safely used in SQL text without further quoting. You can also try doing the mapping per request (factor out the mapping code to a procedure of course) by stripping all bad characters from it. A suitable regsub might be:
regsub -all {\W+} $externalname "" realname
but then we need additional checks to see that it isn't “evil”:
# You'll need to create an array, SQLidentifiers, first, perhaps like:
# array set SQLidentifers {UPDATE - SELECT - REPLACE - DELETE - ALTER - INSERT -}
# But you can do that once, as a global "constant"
if {[regexp {^\d} $realname] || [info exist SQLidentifiers([string toupper $realname])]} {
error "Bad identifier, $externalname"
}
As you can see, it's a good idea to factor out such transforms and checks into their own procedure so you get them right, once.
And you must test your code extensively. I cannot stress that hard enough. Your tests must try really hard to break things, to make SQL injections via every possible field that anyone could pass into the software; not one of them should ever result in anything happening that your code ever expects.
It's probably a good idea to get someone else to write at least some of the tests; experience from the security community suggests that it is relatively easy to write code that you can't break yourself, but much harder to write code that someone else can't break. Also consider doing fuzz testing, sending computer-generated random data at the interface. In all cases, either things should give a graceful error or should succeed, but never ever cause the application to outright fail.
(You might well allow highly-authenticated users — system/database administrators — to outright specify SQL to evaluate so they can do things like setting the system up, but they're the minority case.)
Cross-site Scripting
This is actually conceptually quite similar: it's caused (principally) by someone putting something in your site that unexpectedly gets interpreted as HTML (or CSS, or Javascript) rather than as human-readable text (with SQL injection, it's something getting interpreted as SQL rather than as data). Because you can't do the equivalent of parameterised queries when going back to the client, you have to use careful quoting. You're strongly recommended to do the careful quoting by using a proper templating library that constructs a DOM tree (with data coming from users or from the database being only ever inserted as text nodes).
If you want users to supply a marked up piece of text, consider either delivering it back as plain text before using Javascript to render it as, say, Markdown, or completely parsing the user-supplied text on the server to construct a model (e.g., DOM tree) of what should be delivered, before sending it back as HTML generated from that model.
You must not allow users to specify a location where you load a script or frame from. Even allowing them to specify links is worrying, but you probably have to permit that if you can't restrict things to straight plain text. (Consider adding a mechanism for listing all links that have been supplied by users. Consider marking all external links with rel=nofollow unless you can positively detect that they go to somewhere that you whitelist.)
Direct supply of HTML is a “highly-authenticated users only” operation.
(I told a lie above. You can do the equivalent of SQL parameterised queries. You write JS that the client executes to fetch the user data using an AJAX query, perhaps serialized as JSON, and then do DOM manipulations there to render it; in effect, you're moving the DOM construction from the server to the client, but you're still doing DOM construction as that's the core of how you get this right. You have to remember to never insert the things retrieved as straight HTML though. Clients must not trust the server too much.)
The comments I made above above about testing apply here too. With testing for XSS, you're looking to inject something like <script>alert("boom!")</script>; any time you can get that in and cause a popup dialog — except by being a system administrator with direct permission to edit HTML directly — you've got a massive dangerous hole to plug. (It's quite a good thing to try to inject, as it is very noticeable and yet fairly benign in itself.)
Don't try to just filter out <script> using regular expressions. It's far too hard to get that right.
I am using javascript/jquery to generate a sql query.
I have a sql query I'm generating and using inside a javascript/jquery script.
Something like this:
var storeName;
var query = "SELECT * FROM stores where storeName = '" + storeName + "';";
(storeName is generated through jquery when a user selects from html)
So when storeName is something like "Jackson Deli" the query runs just fine.
But then when storeName is "Jackson's Deli" it does not work and it seems to be because the apostrophe in Jackson's is treated like a closing quote. I know I can escape a quote by doubling it if I was hard-coding the query... so
SELECT * FROM stores where storeName = 'Jackson''s Deli';
should work. But I'm not hard-coding the query. Instead it's being generated by user input and may or may not have an apostrophe in the name. How would I go about escaping ' this character in this case? I would need it to work inside Javascript/jquery.
Would I need to write an if statement that looks for ' in storeName and replaces it with '' ??
Or is there another way to go about this?
EDIT:
Ouch! Normally, yes, I realize the perils of generating a query on the client side.
So here's some more context. I'm working with cartodb and following their documentation. Here's an example from their repo doing something similar to what I'm talking about (they have other examples too):
https://github.com/CartoDB/cartodb.js/blob/develop/examples/layer_selector.html
You can't run a query in cartodb that lets you modify data in any way -- you can only run queries that let you retrieve data. So I'm still thinking about what the best way to escape this quote character would be.
DO NOT GENERATE SQL ON THE CLIENT SIDE... EVER
That being said, if you are going to use a dynamic query, you are best off escaping the user input and binding it to a prepared statement on the server side.
If you post more details about which database (MySQL, Postgres, etc.) and what language you are using for server processing- you will get better answers.
Yes... I am fully aware this doesn't answer the question. Nobody should be creating code this way though.
Edit: Made the warning bigger for emphasis.
I see others have answered but I wanted to approach this question from a few angles.
The question you're asking is a good one. You recognize that the SQL doesn't work with single quotes. You realize that something needs to be escaped. These are a good starting point for a few considerations that will hopefully help you to architect software in a secure and maintainable way.
Never directly execute client code/content - Generating SQL or any kind of code/instructions (javascript, bytecode, compiled code) from a client is always a poor idea because it breaks a few critical concepts.
It's hard to maintain because you cannot control the input fully. Sure you could escape the SQL but that doesn't fix both strange case scenarios where you have other characters you didn't account for.
It isn't secure - Your relationship to variables, inputs, CGI params, file contents, database fields whose values came from the aforementioned list, or just about anything that came from a remote system, remote user cannot ever be trusted. Always check, sanitize and validate inputs. I can open the source to your page, see where you add a check for single quotes and change that and then execute the code to delete your records, have it email if certain stored procedures are available, run code on the SQL backend, drop databases (assuming the query runs under appropriate privileges.)
It blends/blurs the lines between client input/display and business logic. Research MVC, n-Tier development and other concepts for an introduction to the concepts of separating your business logic from display/inputs. This is critical not only for scalability and performance but also to reduce the change of issues such as this from causing critical security flaws.
Approach your software development from the bad-guys perspective - Instead of "How can I escape this string to make it work." try "How can I bypass the escape on this page to allow me to delete records, view things I should, etc.
Don't feel bad because the approach is wrong,learn from it. I see alot of comments about how you should never ever do this (and they're right) but many of us learned this lesson the hard way. We laugh at Little Bobby Tables because we've all written or had to support code that did this. The key is to understand the underpinning of why it's a bad idea and then use that in designing software. Welcome to the school of hard knocks. We're all graduates and thankfully you could learn from our comments rather than when somebody tinkers and corrupts, deletes or infiltrates your database and application.
To get you started on this journey may I suggest reading the following:
SQL Injections Explained
And as an added bonus XSS E.g. escaping OUTPUT that originated from an external system or person. for example a comment entry that contains Hi!!! <script>alert('Thanks to this site not escaping this output I get to run this code under your login. Thanks for the 4000 crates of free tshirts you just ordered for me');</script> how are you??? so that when you output it you get
Comments:Hi!!! <script>alert('Thanks to this site not escaping this output I get to run this code under your login. Thanks for the 4000 crates of free tshirts you just ordered for me');</script> how are you???
Which is "valid" HTML and the browser will execute it.
Final thoughts - Adopt the motto Trust but Verify and you'll be OK
FYI, CartoDB does not allow you to execute a query that changes something in the table, it's read-only.
Send data to your server first, then escape all chars that need to be escaped with addslashes() command (provided that you are using PHP).
addslashes() command on PHP
After you are done with eascaping characters, you can send your data to cartoDB using their API and your API key.
cartoDB does provide insert/update/delete tasks through its SQL API. See this link:
http://developers.cartodb.com/documentation/sql-api.html