I'm a junior PHP developer currently working on a project with a small team. It's the first time I've worked in a team on a project so I'm learning lots and building team working skills.
There is one specific thing I noticed that my fellow developers do and I believe could be a large security risk. When creating forms they will give the input name the column name in the database. This means that wherever the data is posted they can use a nifty for each loop going through the POST array. Sure, it's pretty and easy, but do I want users to see the names of columns?
I'm not sure if it does pose a security risk (first thing I think of is SQL injection) but if it does what can be done?
I suppose you could possibly hash the names of the inputs? Still, that's not totally 100% secure. What if in the form page the names are things like 'apple64', 'banana99', 'chickens' and then in the PHP file they're converted to their corresponding column names?
The point of my question is to find general practice for this (possible) security vulnerability.
Such a general practice is called "whitelisting".
You are positively right about this vulnerability. And for a junior developer you have a very good eye. As a matter of fact, most people who call themselves "professionals" never bother themselves with such questions.
So, to prevent an ordinary SQL injection and also to prevent random access to table fields (a user may be disallowed to some of them), you have to verify your post data against a pre-written whitelist.
Here you can see my approach for either classic mysql or PDO as an example.
When you develop, you have to give to user the minimal informations.
Headers / DB name / Column name etc..
The risk of the sql injection exist if your form treatments are not secure.
To control your sql requests, you have to prepare them and check if the variable have special chars.
Documentation about pdo
http://php.net/manual/en/pdo.prepare.php
A nice "how to" about the sql injection:
http://www.unixwiz.net/techtips/sql-injection.html
Related
Everyone knows or should know parameterized queries help to protect against SQL injection. All of the tutorials and documentation I have seen have revolved around using prepared SQL queries to process form input. But what about when there isn't any form input? I.e. a subsequent query after a user has been logged in such as $stmt = "SELECT theme_preference FROM users WHERE user_id = '1234'";
$query = mysqli_query($conn, $stmt);
Is there any possible way an attacker could exploit this? (Let's say I'm using PHP).
The question is not whether the source of the data written in a SQL query is a http form. It's not even if it's from the current request.
The question is whether you trust the source of the data. And that may be a complex question.
You obviously do not trust something that comes from the current request. You also don't trust something that may have come from an earlier request, like for examples fields in a database that are modified by request data. But you also may or may not trust other fields in your database. For example you have IT ops staff, or DB admins. Do you trust them to not inject some kind of an XSS or secondary SQLi attack into a database field to steal user credit card data, which is stored in an audited table, so they cannot just go in and dump it without being noticed? If they injected javascript or a clever SQLi in the right place in a table that is not audited, they may steal credit card info by exploiting the vulnerable application, then change it back and remove all traces.
Also an application may have different sources for data, other systems may for example upload files (say XML) on APIs, data from those will be processed, some of it will eventually make it to the UI or used in SQL queries. If you trust those sources, you may choose to not implement protection against SQLi or XSS. But why would you, when it is easy? Multiple layers of defenses is always better than walking on thin ice.
So in short, the question is trust. If you absolutely trust the source of the data (like for example because it's static, hard-coded, or for some other reason), that's fine to use it directly in queries. But in case of SQL injection, using it properly (ie. in parameters) is so easy that you should just do that.
Also consider future changes. You are writing it in a SQL string without parameters because you know that it's safe now. Months pass, somebody adds a new feature, modifies your query, adds a few more parameters, one is from the request. But the pattern was already there, he will probably just copy-paste and go with the pattern - and your application is vulnerable.
My final point is static security scanners, those that look at your source code. Pretty much all of those will flag your code for SQLi if a variable is included in the query string itself without using parameters. That may of course be a false positive, but I doubt you want to bother with those findings, when you can avoid them in the first place.
So sometimes it's not just about the technical exploitability, there are other aspects too.
I've been working with PHP for some time and I began asking myself if I'm developing good habits.
One of these is what I belive consists of overusing PHP sanitizing methods, for example, one user registers through a form, and I get the following post variables:
$_POST['name'], $_POST['email'] and $_POST['captcha']. Now, what I usually do is obviously sanitize the data I am going to place into MySQL, but when comparing the captcha, I also sanitize it.
Therefore I belive I misunderstood PHP sanitizing, I'm curious, are there any other cases when you need to sanitize data except when using it to place something in MySQL (note I know sanitizing is also needed to prevent XSS attacks). And moreover, is my habit to sanitize almost every variable coming from user-input, a bad one ?
Whenever you store your data someplace, and if that data will be read/available to (unsuspecting) users, then you have to sanitize it. So something that could possibly change the user experience (not necessarily only the database) should be taken care of. Generally, all user input is considered unsafe, but you'll see in the next paragraph that some things might still be ignored, although I don't recommend it whatsoever.
Stuff that happens on the client only is sanitized just for a better UX (user experience, think about JS validation of the form - from the security standpoint it's useless because it's easily avoidable, but it helps non-malicious users to have a better interaction with the website) but basically, it can't do any harm because that data (good or bad) is lost as soon as the session is closed. You can always destroy a webpage for yourself (on your machine), but the problem is when someone can do it for others.
To answer your question more directly - never worry about overdoing it. It's always better to be safe than sorry, and the cost is usually not more than a couple of milliseconds.
The term you need to search for is FIEO. Filter Input, Escape Output.
You can easily confound yourself if you do not understand this basic principle.
Imagine PHP is the man in the middle, it receives with the left hand and doles out with the right.
A user uses your form and fills in a date form, so it should only accept digits and maybe, dashes. e.g. nnnnn-nn-nn. if you get something which does not match that, then reject it.
That is an example of filtering.
Next PHP, does something with it, lets say storing it in a Mysql database.
What Mysql needs is to be protected from SQL injection, so you use PDO, or Mysqli's prepared statements to make sure that EVEN IF your filter failed you cannot permit an attack on your database. This is an example of Escaping, in this case escaping for SQL storage.
Later, PHP gets the data from your db and displays it onto a HTML page. So you need to Escape the data for the next medium, HTML (this is where you can permit XSS attacks).
In your head you have to divide each of the PHP 'protective' functions into one or other of these two families, Filtering or Escaping.
Freetext fields are of course more complex than filtering for a date, but never mind, stick to the principles and you will be OK.
Hoping this helps http://phpsec.org/projects/guide/
I wanted to know why isn't easier and more secure to have one database service, dedicated only to user authentication (withholding usernames and passwords) which would be well secured (inputs well sanitized etc.)
And another database service for all the other data in the website which would be possibly less secured and available for serving web content.
Wouldn't it be a good way to prevent a lot of the SQL injections happening these days?
No. There is a difference between sanitizing inputs and protecting passwords. SQL injection can happen in any query, and allows someone not only to steal, but also to destroy data. This should be prevented at all times.
Regarding usernames and passwords, there are additional measures to take. For one, don't store passwords at all, but always store hashed versions, hashed with a salt. Furthermore, you might put the authentication in a different database or even some authentication service if you like, but like I said, that's extra.
Of course, if you got a big bunch of data that is read-only from a website perspective, you might store that in a different database, or at least make the website connect using a database user that doesn't have any rights to modify the data. That way, the data is better protected against destruction, because errors on the website, SQL injection and even leaking of the username and password will not lead to destruction of the data. But this also goes for both the user credentials as the 'less important' data.
You seem to miss two points :
the rest of your data also should be secure (or else there's no point in securing the application)
you don't store passwords. Never. You only store a hash built from the password, the username (optionally) and a record specific salt. So it's not so important to secure that base, it only is done to prevent impersonation
As there's no reason to secure in a greater manner that part of the DB, just ensure the whole is correctly secured, it's so much easier to manage one DB than two TB. Trying to keep different types of data in different RDBMS and to maintain their coherency is a nightmare.
Lastly, note that this shouldn't change anything regarding to mysql injections. Just don't allow those injections by using prepared statements.
This is a tough quesiton. Indeed you can have two databases one for sensible data, the other for "furnishing".
Let's put it this way: even if you use a database only for "furnishing", what happens if that database get hacked ? Will your users have to see "THIS SITE WAS HACKED" in the section or...? :)
EDIT: What is protection? Protection is when you buy a coffee and you don't want your friend or someone to drink it. Then what if you buy a coffee and a muffin. Would you protect only one ? Would you protect both ? Which one is more important for you ? If you're like me and most people you would say both. What you made me understand by commening is that muffin (users) is more important than something else (furnishing).
Why would you need protection, if you don't care about the coffee ? Probably because you don't really value coffee enough to protect it. Then let me say this: the money you used to buy your coffee were worth when they were still money, but now they're coffee, what's changed apart from their shape ? Nothing.
Now let's get back to our case: if you have a simple database which contains only "furnishing" texts like "TITLE", "DESCRIPTION" etc. Having them lost isn't bad ? Won't you have to go there and fix them ? Won't you have to WORK to get everything pretty ?
Not to speak that most vulnerabilities related to a database might get pretty worse than just losing only ONE database. Having a sql injection issue might get all database destroyed, that's the danger you're trying to avoid. So, it's almost pointless to try to secure a database more than another. Try to secure everything instead, you'll be sure that everywhere you go, nothing could happen.
So you fear a special inmate, and you secure him A LOT, and trascurate that old cell. You look away, the inmate in the old cell is now out of his cell! And worse, he freed the special inmate (and everyone else). That's the kind of security hole a sql injection imply.
I think you need to look deeper into your RDBMS protection layers to get a better picture why they are better in the same instance.
Let's take for example your MySQL database:
an instance is made out of 3 + databases (mysql, information_schema, and all others you create).
so you already have a separate database repo that is handling the auth + user + pass - and that is your MySQL database.
There are ways to develop applications that are hacker free - when working with MySQL most of the coders use open SQL code (inline SQL) - and this is the problem - hackers will take advantage of this! To fix this use stored procedures (encapsulated).
Inside database privileges are a problem as well - lazy developers or stupid DBA will give extra rights for application users. Your idea is redundant from many points of view. More instances will cost you more money, more resources, etc.
I am trying to figure out which functions are best to use in different cases when inputting data, as well as outputting data.
When I allow a user to input data into MySQL what is the best way to secure the data to prevent SQL injections and or any other type of injections or hacks someone could attempt?
When I output the data as regular html from the database what is the best way to do this so scripts and such cannot be run?
At the moment I basically only use
mysql_real_escape_string();
before inputting the data to the database, this seems to work fine, but I would like to know if this is all I need to do, or if some other method is better.
And at the moment I use
stripslashes(nl2br(htmlentities()))
(most of the time anyways) for outputting data. I find these work fine for what I usually use them for, however I have run into a problem with htmlentities, I want to be able to have some html tags output respectively, for example:
<ul></ul><li></li><bold></bold>
etc, but I can't.
any help would be great, thanks.
I agree with mikikg that you need to understand SQL injection and XSS vulnerabilities before you can try to secure applications against these types of problems.
However, I disagree with his assertions to use regular expressions to validate user input as a SQL injection preventer. Yes, do validate user input insofar as you can. But don't rely on this to prevent injections, because hackers break these kinds of filters quite often. Also, don't be too strict with your filters -- plenty of websites won't let me log in because there's an apostrophe in my name, and let me tell you, it's a pain in the a** when this happens.
There are two kinds of security problems you mention in your question. The first is a SQL injection. This vulnerability is a "solved problem." That is, if you use parameterized queries, and never pass user supplied data in as anything but a parameter, the database is going to do the "right thing" for you, no matter what happens. For many databases, if you use parameterized queries, there's no chance of injection because the data isn't actually sent embedded in the SQL -- the data is passed unescaped in a length prefixed or similar blob along the wire. This is considerably more performant than database escape functions, and can be safer. (Note: if you use stored procedures that generate dynamic SQL on the database, they might also have injection problems!)
The second problem you mention is the cross site scripting problem. If you want to allow the user to supply HTML without entity escaping it first, this problem is an open research question. Suffice to say that if you allow the user to pass some kinds of HTML, it's entirely likely that your system will suffer an XSS problem at some point to a determined attacker. Now, the state of the art for this problem is to "filter" the data on the server, using libraries like HTMLPurifier. Attackers can and do break these filters on a regular basis; but as of yet nobody has found a better way of protecting the application from these kinds of things. You may be better off only allowing a specific whitelist of HTML tags, and entity encoding anything else.
This is one of the most problematic task today :)
You need to know how SQL injection and other attackers methods works. There are very detailed explanation of each method in https://www.owasp.org/index.php/Main_Page and also whole security framework for PHP.
Using specific security libraries from some framework are also good choice like in CodeIgniter or Zend.
Next, use REGEXP as much as you can and stick pattern rules to specific input format.
Use prepared statements or active records class of your framework.
Always cast your input with (int)$_GET['myvar'] if you really need numeric values.
There are so many other rules and methods to secure your application, but one golden rule is "never trust user's input".
In your php configuration, magic_quotes_gpc should be off. So you won't need stripslashes.
For SQL, take a look at PDO's prepared statements.
And for your custom tags, as there are only three of them, you can do a preg_replace call after the call of htmlentities to convert those back before your insert them into the database.
I just have one simple question about XSS attack. I know that you can prevent them by sanitizing the form inputs, but my question is, how about a search input (a general search on a website for example)? Should we sanitize search inputs as well? I mean, it's just a search input, the user should be able to search for anything that he/she wants on the website. Please provide me with some clarification on this.
Thank you
I know that you can prevent them by sanitizing the form inputs
nope, you should prevent them by sanitizing the output. So in database (or wherever) you need to pass the data as-is, and process it right before you show it to user
Tho this has already been answered by zerkms
Doing sanitizing on sql injections from any user input that touches the database requires mysql_real_escape_string($_REQUEST['search'])
On output if your showing what user searched for like "You searched for:" use htmlentities(strip_tags($_REQUEST['search']), ENT_QUOTES);
Then your safe from incoming and outgoing
I just want to add one more point to the discussion here. You said:
I mean, it's just a search input, the user should be able to search for anything that he/she wants on the website.
Here's the gotcha: frequently the search term will be printed into the document that's rendered following the search. Ie, "You searched for: <whatever is was>". That's where you'll have your XSS vulnerability if you're not sanitizing this stuff.
If you're thinking "but we don't do that", bear in mind that you may not do so now, but you might do so in the future. And if you don't seal off this vulnerability now, you're likely to forget to do so later - so it's best just to nip this one in the bud.
how about using htmlpurifier ?
SQL Injection and XSS are two different (yet somewhat related) attacks. They are related in that essentially it boils down to the untrusted data escaping from the context it was placed in and subsequently performing unforeseen operations.
For following best practices in building your defenses I recommend having a read through OWASP's SQL Injection Prevention Cheat Sheet and their XSS Prevention Cheat Sheet.
OWASP has put forth the ESAPI Project which includes tools for encoding for the different contexts in which untrusted data can be used:
encodeForSQL
encodeForHTML
encodeForHTMLAttribute
encodeForJavaScript
encodeForCSS
encodeForURL
This library is available for a number of languages including Java, .NET, PHP, Classic ASP, Cold Fusion, Python, and Haskell. It also is able to perform input validation if it's required.
Some organisations who are using ESAPI include American Express, Apache Foundation, Booz Allen Hamilton, Aspect Security, Foundstone(McAfee), The Hartford, Infinite Campus, Lockheed Martin, MITRE, U.S. Navy - SPAWAR, The World Bank, SANS Institute.
Lastly - the encoding is to be performed just before interpretation (the closer the better). Ex: Just before you give the UI component the untrusted data to render you encode it. The UI component can't trust the server - it has to encode.