Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
This is a security question meant for PDO prepared statements. Using PDO I know that the risk of sql injection is virtually impossible and that the class handles all of that for you. Coming from using them mysql_* stack I always feel as if I'm not handling security issues well enough. I'm usually used to writing hundreds of lines of code just to deal with security while now I'm literally just writing queries.
Is there really any security threats with PDO statements that I have to worry about other than length of the string in the db?
Definitely yes.
As a matter of fact, native prepared statements are good for simple schoolbook cases only.
Means you still have to write some "hundreds of lines" for whatever complex cases. I made a small digest of such cases in the PDO tag wiki. Main disadvantages are
no placeholders for identifiers. You have to format and inject them manually like in old good mysql_* code.
no placeholders for arrays. Means you still have to write some code manually and later inject it in the query - so, there is still a possibility to slip into some trouble.
Therefore you need a higher level of abstraction even upon PDO. A common solution is to use some sort of Query Builder which offered by every modern framework.
But personally I hate query builders as they seems too bloated to me, pretending to replace whole SQL but obviously failing with it. So, I don't understand why use SQL written in PHP when I can use pure SQL. For this purpose I created an abstraction library of mine, to correct all the disadvantages of native prepared statements, safeMysql. It has placeholders for everything you need and thus makes queries much safer than PDO, yet it makes application code dramatically shorter.
Means with safeMysql you indeed can "just literally write queries":
$sql = "SELECT * FROM articles WHERE id IN(?a) ORDER BY ?n LIMIT ?i"
$data = $db->getAll($sql, $ids,$_GET['order'], $limit);
$sql = "INSERT INTO stats SET pid=?i,ip=inet_aton(?s),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql, $pid, $ip, $data, $data);
Just compare these 2-liners with amount of code you will need to write using raw PDO.
I think the answer is pretty close to yes for "sql injection attacks".
mysqli prepared statements and mysqli_real_escape_string
There are still many other types of attacks, but at least all your values are escaped.
Relying on PDO to "fix" your security is like relying on a compiler to find your bugs.
Related
I read that escaping input is not enough protection against sql injection.
Then, I saw that codeigniter does not use prepared statements.
It uses escape and bind (which is still just escape) when executing queries.
Would this be enough protection?
If not, should I avoid Query Class and use prepared PDO queries manually?
From everything I've seen, PDO and prepared queries are the thing to pursue now. Seeing alot of PHP posts on here the majority of the comments are telling people to switch to more secure ways of accessing and inserting data into your database in the way of PDO. It is extremely well documented and once you grasp the fundamentals of it, it is very easy to see how it can be used further. TL:DR Escape = bad. PDO = Good
PDO documentation is also here that gives you a huge knowledge base of 'how to's ' which are very easy to follow and well written PDO Manual
Yes you are right in your assumption to avoid the builtin query class, and to use PDO with prepared queries.
Don't use things that are not prepared, unless you're making a plugin, then for the sake of future users you might consider using the builtins to allow easier debugging for them, but still then, consider using a more secure prepared statement supported way.
You really don't want to be the plugin author responsible for a weakness in a site.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I know, that PDO won't let me use the "param system" on tables. My problem is, that I store all table names as variables / static variables in an object named "Tables" (so I can update table names centrally).
I just can't find an answer to the question, if it's a good idea / not bad practice to build the query by using my static variables (users can't change the table names / browse through tables, so that shouldn't be a security problem)
Example:
$statement = $this->pdo->prepare('SELECT `category-id`, `icon`, `name` FROM ' . Tables::$BOARD_CATEGORIES);
Can I use this technique, or should I stick with the normal "static" way?
Thanks :)
The primary security benefit of the parametrized prepared statement is that it prevents the insertion of strings from untrustworthy sources into your SQL statement before the statement is parsed by the DB; after the statement is parsed and prepared, only value substitutions are allowed, not executable clauses.
You could think of your original SQL query as "a string from a trustworthy source." If it improves maintainability, I see no reason to build up your query from smaller strings provided all such strings are also from trustworthy sources, such as your Tables class. (I do wonder, though, how often you expect to rename your tables.)
Whether it is or isn't "best practice" I'm not prepared to say, but I did see something similar in industry when I worked with The Great Azure Empire (a false name for a real company), and I think even "best practice" should not be seen as dogma.
Answer:
It depends on the code you are using to develop and modify your Tables object. In general though, conventional methods are more tested and safer. The only real difference between your code and normally used PDO code is how you are generating your sql statement. If you use your own code to create the sql statement that is being prepared, you have to be completely sure that user input will not modify the structure of that sql statement. It is riskier and if not needed would be advised against, however if you absolutely need it for your site, then make absolute sure that the code generating the Tables object can't be maliciously manipulated by users.
Elaborating on the answer:
The real difference between your code and the general way PDO is used is that you are generating the sql statement differently. Normally, you would see code as follows:
$sql = "SELECT `category-id`, `icon`, `name` FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":id", $id);
$stmt->execute();
(I am assuming that you are also binding your parameters in your code since that would be after the preparing process you show in your question).
So since the only real difference between what you are doing with your table is generating the sql statement, you just have to make complete sure that there is absolutely no way for user input to influence your sql structure, because if there is, then the prepare statement will not keep your database safe.
In general, people tend to prefer to use conventional and tested methods, however if you absolutely need to use your table object to generate the sql statement, make sure that the code that creates and updates the object is defended from user input.
I know this topic has been covered to death but I would like some feedback from the community regarding security within our web application.
We have standard LAMP stack web app which contains a large number of database queries which are executed using mysqli_query. These queries are not parameterized and at the moment but there is some naive escaping of the inputs using addslashes.
I have been tasked with making this system safer as we will be penetration tested very shortly. The powers above know that parameterized queries are the way to go to make the system safer however they don't want to invest the time and effort into re-writing all the queries in the application and also changing the framework we have to make them all work correctly.
So basically I'm asking what my options are here?
I've run mysqli_real_escape_string over the inputs. I've setup a filter which doesn't allow words like SELECT, WHERE, UNION to be passed in which I guess makes it safer. I know mysqli_query only allows one query to be run at once so there's some security there (from concatenating updates onto the end of of selects).
Do I have any other options here?
Edit: I should probably add that if anyone is able to provide an example of an attack which is completely unavoidable without parameterized queries that would also be helpful. We have a query which looks like this:
SELECT
pl.created
p.LoginName,
pl.username_entered,
pl.ip_address
FROM loginattempts pl
LEFT JOIN people p ON p.PersonnelId = pl.personnel_id
WHERE p.personnelid = $id
AND pl.created > $date1
AND pl.created < $date2
I've substituted a UNION query into the $id UNION SELECT * FROM p WHERE 1 = 1 sort of thing and I can prevent that by not allowing SELECT/UNION but then I'm sure there are countless other types of attack which I can't think of. Can anyone suggest a few more?
Update
I've convinced the powers that be above me that we need to rewrite the queries to parameterized statements. They estimate it will take a few months maybe but it has to be done. Win. I think?
Update2
Unfortunately I've not been able to convince the powers that be that we need to re-write all of our queries to parameterized ones.
The strategy we have come up with is to test every input as follows:
If the user supplied input is_int that cast it as so.
Same for real numbers.
Run mysqli_real_escape_string over the character data.
Change all the parameters in the queries to quoted strings i.e.
WHERE staffName = ' . $blah . '
In accordance with this answer we are 100% safe as we are not changing the character set at any time and we are using PHP5.5 with latin1 character set at all times.
Update 3
This question has been marked as a duplicate however in my mind the question is still not followed answered. As per update no.2 we have found some strong opinion that the mysqli_real_escape string function can prevent attacks and is apparently "100% safe". No good counter argument has since been provided (i.e. a demonstration of an attack which can defeat it when used correctly).
check every single user input for datatype and where applicabile with regular expressions (golden rule is: never EVER trust user input)
use prepared statements
seriously: prepared statements :)
it's a lot of work especially if your application is in bad shape (like it seems to be in your case) but it's the best way to have a decent security level
the other way (which i'm advising against) could be virtual patching using mod_security or a WAF to filter out injection attempts but first and foremost: try to write robust applications
(virtual patching might seem to be a lazy way to fix things but takes actually a lot of work and testing too and should really only be used on top of an already strong application code)
Do I have any other options here?
No. No external measure, like ones you tried to implement, has been proven to be of any help. Your site is still vulnerable.
I've run mysqli_real_escape_string over the inputs
Congratulations, you just reinvented the notorious magic_quotes feature, that proven to be useless and now expelled from the language.
JFYI, mysqli_real_escape_string has nothing to do with SQL injections at all.
Also, combining it with existing addslashes() call, you are spoiling your data, by doubling number of slashes in it.
I've setup a filter which I guess makes it safer.
It is not. SQL injection is not about adding some words.
Also, this approach is called "Black-listing" it is proven to be essentially unreliable. A black list is essentially incomplete, no matter how many "suggestions" you can get.
I know mysqli_query only allows one query to be run at once so there's some security there
There is not. SQL injection is not about adding another query.
Why did I close this question as a duplicate for "How can I prevent SQL-injection in PHP?"?
Because these questions are mutually exclusive, and cannot coexist on the same site.
If we agree, that the only proper answer is using prepared statements, then a question asks "How can I protect using no prepared statements" makes very little sense.
At the same time, if the OP manages to force us to give the positive answer they desperately wants, it will make the other question obsoleted. Why use prepared statements if everything is all right without them?
Additionally, this particular question is too localized as well. It seeks not insight but excuse. An excuse for nobody but the OP personally only. An excuse that let them to use an approach that proven to be insecure. Although it's up to them, but this renders this question essentially useless for the community.
This question already has answers here:
Why is using a mysql prepared statement more secure than using the common escape functions?
(7 answers)
Closed 9 years ago.
Okay, I still don't really get it. I keep reading that in order to properly escape your MySQL queries, you need to use mysqli_prepare() and mysqli_bind_param().
I tried using this setup and, quite frankly, it's a little clunkier. I'm stuck passing variables by reference when I don't need to ever reference them again, and it's just more lines of code to accomplish the same task.
I guess I just don't get what the difference is between:
<?php
$sql = new \MySQLi(...);
$result = $sql->query('
UPDATE `table`
SET
`field` = "'.$sql->real_escape_string($_REQUEST[$field]).'";
');
?>
and
<?php
$sql = new \MySQLi(...);
$stmt = $sql->prepare('
UPDATE `table`
SET
`field` = ?;
');
$value = $_REQUEST[$field];
$stmt->bind_param('s', $value);
$stmt->execute();
$result = $stmt->get_result();
unset($value);
?>
other than more code.
I mean, did they implement this so that people wouldn't forget to escape values before sending them in a query? Or is it somehow faster?
Or should I use this method when I intend to use the same query repeatedly (since a mysqli_stmt can be reused) and use the traditional method in other cases?
What you are reading, that you need to use mysqli_prepare() and mysqli_bind_param() functions to "properly escape your MySQL queries" is wrong.
It is true that if you use mysqli_prepare() and mysqli_bind_param(), you needn't (and shouldn't) "escape" the values supplied as bind parameters. So, in that sense, there's some truth in what you are reading.
It's only when unsafe variables are included in the SQL text (the actual text of the query) that you need to "properly escape" the variables, usually by wrapping the variables in mysqli_real_escape_string() function calls.
(We note that it's possible to make of use of prepared statements and still include un-escaped variables in the SQL text, rather than passing the variable values as bind_parameters. That does sort of defeats the purpose of using prepared statements, but the point is, either way, you can write code that is vulnerable.
MySQL now supports "server side" prepared statements (if the option is enabled in the connection), and that's a performance optimization (in some cases) of repeated executions of identical SQL text. (This has been long supported in other databases, such as Oracle, where making use of prepared statements has been a familiar pattern for, like, since forever.)
Q: Did they implement [prepared statements] so that people wouldn't forget to escape values before sending them in a query?
A: Based on the number of examples of code vulnerable to SQL Injection when not using prepared statements, despite the documentation regarding mysql_real_escape_string() function, you'd think that certainly would be sufficient reason.
I think one big benefit is that when we're reading code, we can see a SQL statement as a single string literal, rather than a concatenation of a bunch of variables, with quotes and dots and calls to mysql_real_escape_string, which isn't too bad with a simple query, but with a more complex query, it is just overly cumbersome. The use of the ? placeholder makes for a more understandable SQL statement,... true, I need to look at other lines of code to figure out what value is getting stuffed there. (I think the Oracle style named parameters :fee, :fi, :fo, :fum is preferable to the positional ?, ?, ?, ? notation.) But having STATIC SQL text is what is really the benefit.
Q: Or is it somehow faster?
As I mentioned before, the use of server side prepared statements can be and advantage in terms of performance. It's not always the case that it's faster, but for repeated execution of the same statement, where the only difference is literal values (as in repeated inserts), it can provide a performance boost.
Q: Or should I use this method when I intend to use the same query repeatedly (since a mysqli_stmt can be reused) and use the traditional method in other cases?
That's up to you. My preference is for using STATIC SQL text. But this really comes from a long history of using Oracle, and using the same pattern with MySQL fits naturally. (Albeit, from Perl using the DBI interface, and Java using JDBC and MyBATIS, or other ORMs (Hibernate, Glassfish JPA, et al.)
Following the same pattern just feels natural in PHP; the introduction of mysqli_ and PDO are a welcome relief from the arcane (and abused) mysql_ interface.
Good code can be written following either pattern. But I challenge you to think ahead, about more complex SQL statements, and whether the choice to use mysqli_real_escape_string() and concatenating together a dynamic string to be executed, rather than using static SQL text and bind parameters, might make reading, and deciphering, the actual SQL being executed more complicated for the soul that finds themselves maintaining code they didn't write.
I think studies have shown that code is read ten times more than it is written, which is why we strive to produce readable, understandable code, even if that means more lines of code. (When each statement is doing a single identifiable thing, that's usually easier for me to understand than reading a jumble of concatenated function calls in one complicated statement.
I think it's less a question of the latter method being more secure per se than encouraging separation of logic. With prepared statements the SQL query is independent of the values we use. This means, for example, when we go back and change our query we don't have to concatenate a bunch of different values to a string, and maybe risk forgetting to escape our input. Makes for more maintainable code!
There are a couple main benefits I found that were well written:
The overhead of compiling and optimizing the statement is incurred
only once, although the statement is executed multiple times. Not
all optimization can be performed at the time the prepared statement
is compiled, for two reasons: the best plan may depend on the
specific values of the parameters, and the best plan may change as
tables and indexes change over time.
Prepared statements are resilient against SQL injection, because
parameter values, which are transmitted later using a different
protocol, need not be correctly escaped. If the original statement
template is not derived from external input, SQL injection cannot
occur.
On the other hand, if a query is executed only once, server-side prepared statements can be slower because of the additional round-trip to the server. Implementation limitations may also lead to performance penalties: some versions of MySQL did not cache results of prepared queries, and some DBMSs such as PostgreSQL do not perform additional query optimization during execution.
Source
I would like to add that mysqli_bind_param() has been removed as of PHP 5.4.0. You should use mysqli_stmt_bind_param()
I have been learning PHP and MySQL over the last few weeks, and I'm just now hearing about prepared statements and PDO/mysqli. I did some reading and people are saying that stuff like:
$getFromDatabase = mysql_query("SELECT * FROM table WHERE userid='$id'");
while($row = mysql_fetch_assoc($getFromDatabase)){
stuff();
}
...won't work anymore. I use stuff like that pretty frequently in my code. I also am reading a lot about how prepared statements are much better protection against injection. I've got a thorough understanding of how it is better, but is it so much better that it's worth switching away from mysql_real_escape_string()? Is it necessary to switch to Mysqli or PDO? In what situation could mysql_real_escape_string() be bypassed where a prepared statement couldn't?
It's necessary because mysql_query is, in software terms, an ancient artifact. It's the Model T of MySQL database interfaces, clunky, unreliable, and downright dangerous if not used exactly as you should. If you're not extremely careful you will make a mistake, and even a tiny mistake will not go un-noticed if someone uses an automatic SQL injection bug detection tool on your site.
Basically you're living on borrowed time with mysql_query.
If you use mysqli or PDO and are diligent about using placeholders then the risk of a SQL injection bug is very low. It may take about half an hour to figure out how to convert your old code to these new methods, there really isn't a steep learning curve, and that knowledge will save you a lot of trouble in the future. Converting existing code usually isn't too big a deal if you use mysqli and basic placeholders. I bet you even find some serious bugs while patching things up.
In terms of benefits, you won't need to make any mysql_real_escape_string calls, you can just use bind_param, and you won't have to worry about missing an escape on one of your variables. It's actually a lot less work in the long-run.
Additionally, using ? or a named placeholder like :id makes your queries significantly easier to read, debug and maintain. Further, you can use the same statement repeatedly and bind different values to it, ultimately making your application faster.
It is possible to write safe code with mysql_query but why would you? The interface is listed as deprecated, which is the preliminary stage to it being removed from PHP entirely. If you want a future-proof application, it's best to use one of the supported interfaces.