I am coding for an Intranet. In theory, I don't have to worry too much about SQL injection (I can see you throwing up your hands in horror already ;-) It's not really a secure app & doesn't have any "secret stuff".
I'm more concerned about storing and retrieving strings which contain quotes.
It has to use ODBC function (order from on high).
1) is it enough to addslashes() when executing commands and stripslashes() when retrieving them?
2) I am aware of which input might contain quotes & which not (e.g, some form input field require number input an are validated, so, if they are going to be written to the d/b, they are known to be free of quotes)
However, I do have central functions to OdbcExec() and to odbc_fetch_row() and then extract the value of a named column.
Is there any reason why I should nod add/strip-slashes in those?
If you can make it a bit securer while still using OSBC functions then by all means do so. My main concern at this early stage in development is to prevent crashes when entering strings containing quotes. 1 or 2 central functions seem best to me, but maybe you knwo better.
Thanks for clarifying
Use parameterized queries / statements. The odbc prepare and execute functionality provides you this feature like so:
<?php
$a = $_GET['a'];
$stmt = odbc_prepare($db_conn, "SELECT b FROM c WHERE a=?");
$res = odbc_execute($stmt, array($a));
?>
There is some limitation with regards to parameters that begin and end /w single quotes, see here:
http://php.net/manual/en/function.odbc-execute.php
Validate input as best you can prior to putting it in the DB, and use parameterized queries and you'll be in business.
Related
P.S: I know it is a best practice to user prepared statements all the time, and it should be a habit to use prepared statements. So putting this aside, please just let me know technically what can go wrong if I don't write below scenario with prepare.
1. I am not getting any input from users or any other class file, and I won't in the future.
2. I am getting an input from a variable in the same PHP file (an array for example).
Example: ($myID will be a variable hardcoded in the same PHP file)
$myID=12;
$wpdb->query("UPDATE `$table_name` SET `your_column_1` = 1 WHERE `myTable`.`your_column_id` = $myID");
Tl;DR This is a very bad idea. You are introducing long-term risk to save a few seconds of coding effort. It is overwhelmingly likely that you will, sooner or later, introduce a SQL injection risk as your code and data evolve.
If you:
are extremely careful about validating your data,
are extremely careful about constructing your queries,
are absolutely certain that your data is safe and free of any user input (from any source at all, including forms, sensors, APIs, scraping websites, etc.), and
are absolutely certain that no one will ever modify your data or your code (or reuse your code inappropriately), including you,
Then we can say:
it would be safe to execute queries without prepared statements, and - and this is the important part -
you would be living in a fantasy world.
You can never assume safely that you can avoid preparing statements. It’s highly, highly likely that your code will break if you do. You could have bad data, overlook a problem, change the code yourself somehow, repurpose the code for something insecure, or make any number of other errors. You may end up doing harmless SQL injection yourself (with, say, a name or spelling like O’Brien) or you may get massively hacked...
...all to save a few seconds of coding time.
Short version: either (1) use prepared statements on every query that has any kind of variable information or (2) learn the hard way why that’s the rule.
This is a wordpress plugin and will only be used by me in admin panel. So the problem caused because of using "in" statement because it is hard to write the query like update column where color in ('black','white').
If you're developing for WordPress, have you considered using the wpdb API? It makes it pretty easy to add parameters to your SQL queries.
Example of using parameters for an IN( ) predicate:
$colors_array = ["black", "white"];
$placeholders = array_fill(0, count($colors_array), "%s");
$placeholder_list = implode(",", $placeholders);
$wpdb->query( $wpdb->prepare(
"
UPDATE $wpdb->stock
SET quantity = 327
WHERE color IN ($placeholder_list)
",
$colors_array
));
See https://codex.wordpress.org/Class_Reference/wpdb#Protect_Queries_Against_SQL_Injection_Attacks
I agree with Ed Cottrell's advice that you should not compromise on secure programming methods. Use the most secure method and use it consistently.
You don't have to waste time thinking about whether any given case is "safe enough" to skip using the secure method.
You don't have to worry if it's still safe after your PHP variables are no longer hard-coded.
You don't have to worry that someone will copy & paste your code as an example, and they use it in an unsafe way.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
First of all, let's get one thing straight, while im sure it's not the ONLY solution to sql injections, PREPARED STATEMENTS ARE BETTER and MORE SECURE... that's granted.
So let's not debate it anymore, as I just needed to explore the escaping options and target the user inputs rather than the statement..
(a bit of back story)
I have a huge application w/ lots of basic SQL statements which i need to make "safer" in a short period of time. Converting all statements to PDO is a monster of a task which requires resources not available to this situation.
But good thing is that there's a hook in the application where ALL incoming $_GET/$_POST passes through a function before making available as plain variable in the scripts... ( eg.globalize($_POST) )
So i'm looking to target that function instead and focus on "cleaning" user input ...
I pretty much got a good grasp of SQL injection techniques, and basically much of its concept, such as:
1) Whenever there is user input involved in a statement, that's when the attacker has an opportunity
2) The main mission is to break your statement's quoting by simple single or double quotes as string, or character codes, in the attacker's input..
3) Escaping is good at preventing SQL injections except for that situation when the DATABASE character encoding is able to ready multibyte representations of those nasty illegal strings and the script based escaping misses it.
Based on the above premise, what if:
1) All my SQL Statements follow a standard where user input is quoted using single quotes ALWAYS, therefore there is no guess work for me anymore on what type of quote i need to escape (single quotes)
2) all user inputs (POST / GET) go through a function (eg. globalize() ) that basically addslashes() and globalizes each variable
3) This is an intranet application and the scripts can be made aware of the database encoding support.
QUESTION:
What are the threats currently available in the above situation and how can we handle them?
...i personally was looking into simply adding routines to the globalize() function similar to mysql_real_escape_string() .. or go as far as "tweaking" the SQL statements to use mysql_real_escape_string() as that is a lot easier/faster to do than programming statements on each sql query..
PS
Of course this script may never be as secure as prepared statements, but i just need to make it hard enough for most attackers (not looking to 100% bullet proof it as it is not that worth it)
Using
mysql_real_escape_string($link,$non_escaped_string);
See here: http://php.net/manual/en/mysqli.real-escape-string.php
While it might well work, there are a few possible issues.
If you use addslashes then there are potential exploits, hence for MySQL mysql_real_escape_string() is generally better. There is a potential flaw in mysql_real_escape_string() (which also applies to the default use of pdo), but this is so esoteric you pretty much have to try to make your code open to an attack based on it.
The bigger issue is that your user input could possibly be used on different databases with different character sets. Hence you should specify the link to the database that the escaped string will be used in. If you do not specify this the the details of the last link opened will be used. If no link has already been used then it will try and connect itself with some default connection parameters and the results are likely to be unpredictable.
If you just escape all the $_POST / $_GET / $_REQUEST arrays (and remember that $_COOKIES array is also subject to being changed by a mischievous user) then the likely place you would do this would be when the scripts are first loaded, when you are unlikely to have connected to the appropriate database.
A further issue is that some of the code you are dealing with (and which you seem not to have the time deal with in detail) is bound to already escape the input data. Hence you will land up double escaping it with strange results. Related (but less likely to be an issue) is escaping numeric fields
Let's say I have a file called query.sql with the following content in it:
SELECT * FROM `users` WHERE `id`!=".$q->Num($_POST['id'])."
And in my php-script, which has a html form with input named "id" in it, I do the following trick:
$sql=file_get_contents('query.sql');
$query= eval("return \"$sql\";");
//here follows something like $mysqli->query($query); and so on..
I am not concerned about sql-injections since I'm using prepared statements and $q->Num performs is_int check.
But is it safe to use eval such way?
As far as I understand, what is actually eval-ed here is "${_POST['id']}" and it evals to some string value the user entered. And this becomes dangerous only if I eval this string second time. While I eval string only once user's input is just string and can not be interpreted as php-code by compiler and no php-injection is possible.
UPDATE
Thank you for proposing different methodologies and stressing need to use prepared statements. But this not my question at all.
My question is all about php-injections. Is such use of eval bad? If yes, why?
There is no need to use eval - put in a token, and replace it:
// file query.sql
SELECT * FROM `users` WHERE `id`!="{id}";
//php
$sql = file_get_contents('query.sql');
$query = str_replace("{id}", $_POST['id'], $sql);
Update
No, it's not safe. Someone could edit your query.sql script to do anything you want. You may say "the app is internal only", or "i have permissions locked down" or whatever - but at the end of the day there are no guarantees.
The eval statement - although I would try to find a way without using eval - is not vulnerable for PHP injection because $sql is enclosed in double quotes "; One can not ending this quoting with a prepared variable in PHP.
I am not conserned about sql-injections since I'm using prepared statements
Aren't you? ;) You are!
Why do you add the $id to the query using the '.' operator (string manipulation)? If you really use the benefits from prepared statements I would expect something like a bindParam()
Note how prepared statements prevent from SQL injections: The SQL query syntax is been kept separate from arguments. So the server would
parse the SQL query
apply arguments
As the query has been already parsed before arguments will been applied, the query syntax cannot be manipulated by the arguments.
If you prepare a MySQL query that has been created using '.' and external inputs you are potentially vulnerable against SQL injections
What you are doing defeats the principals of prepared statements
Reference from this Answer.
https://stackoverflow.com/a/951868/627868
The main problems with eval() are:
Potential unsafe input. Passing an untrusted parameter is a way to
fail. It is often not a trivial task to make sure that a parameter (or
part of it) is fully trusted.
Trickyness. Using eval() makes code clever, therefore more difficult
to follow. To quote Brian Kernighan "Debugging is twice as hard as
writing the code in the first place. Therefore, if you write the code
as cleverly as possible, you are, by definition, not smart enough to
debug it"
Let's consider the following code:
$sql=file_get_contents('query.sql');
$query= eval("return \"$sql\";");
The danger points at this are:
if the file query.sql is modified from what you expect, then it could be used to execute any arbitrary code in your program.
the name of the file is shown hard-coded; if this isn't the case, then a malicious user could find a way to load an unexpected file (possibly even one from a remote site), again resulting in arbitrary code execution.
the only reason to use a file for this (rather than hard coding the SQL code directly in the program) would be because you want to use it as a config file. The problem here is that the syntax in this file is invalid for both SQL and PHP. Due to the way it's run in the eval(), it also requires that the syntax is exactly correct. Use the wrong quotes or miss one out, and it'll blow up. This is likely to result in brittle code, that fails badly rather than gracefully when the config is marginally incorrect.
There doesn't appear to be a direct SQL injection attack here, but that's really the least of your worries when it comes to eval().
I have personally worked in projects where code existed that worked pretty much exactly the way you've described. There were some very nasty bugs in the system as a direct result of this, and they have been difficult to rectify without wholesale rewrites. I would strongly recommend stepping back from this idea and using a sensible templating mechanism instead as recommended by others in the comments.
Edit if you plan on answering this question please at least read it. Don't simply read the title, then Google 'sql injection php', and paste the results as an answer
First, I'm well aware that there are lots of resources available on how best to prevent SQL injection, but my question is specifically about if very little effort can be enough.
An organization I contract for was recently told that partners' (PHP) websites developed by their previous contractor have been found to have major security issues (my personal favourite is by using the string 'Emergency' in a URL you can gain unauthenticated access to any page in the site...)
I have been asked to review the security of a PHP site and highlight any major issues. I know from previous experience with this site that the standard of coding is truly awful (e.g. huge swathes of code duplicated across pages with around 5% variation, hundreds of unused variables, $var = "yes" in place of booleans, SQL statements written into every single script, unsecure by default (some pages forget to authenticate users), etc). Reviewing the site is a painful reminder that there are some real morons in the world that call themselves developers.
Because of these code quality issues I want to only highlight the serious and semi-serious security problems. If I note every problem with the site my review will take weeks.
I am not an expert on SQL injection, but it's my understanding that you must be able to close an existing query's quoted string before injecting any other kind of statement. So is the following line of code sufficient?
"'".str_replace("'","''",$_POST['var_name'])."'"
I'm not interested in suggestions about improving or changing the code, just whether it's possible in this scenario for SQL injection via $_POST['var_name']. If you're not familiar with PHP str_replace does replace all instances of the first argument with the second, not just the first instance.
Any input much appreciated.
No. In all honesty, if you are not preparing your statements, you are ASKING for a world of hurt.
Just because you escape your quotes with quotes, you are not protecting yourself. Think about this:
A user send you: username'; drop database foo;
You will escape it as username''; drop database foo;
But! if the user does: username\'; drop database foo;
You will be in trouble. You will resolve this for username\''; drop database foo;
Meaning the quote the user placed is escaped, and your quote ended the field username. The drop will then be execute. This is very unsecure.
You need to make sure you Prepare your statements or apply a quote command such as PDO::quote or mysqli_real_escape_string as these escape special characters.
You've got two options - Escaping the special characters in your unsafe_variable, or using a parameterized query.
$safe_variable = mysql_real_escape_string($_POST["user-input"]);
$mysqli = new mysqli("server", "username", "password", "database_name");
$unsafe_variable = $_POST["user-input"];
$stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
Both would protect you from SQL Injection. The parameterized query is considered better practice, but escaping characters in your variable will require fewer changes.
To answer your question: no, simply removing quotes is not enough to prevent SQL injection.
For example,
"SELECT * FROM user_table WHERE userid=$userid AND password=$password"
Could go badly wrong if $password contained "garbage OR 1", or something like that. So if they've got badly formatted queries, removing quotes won't help.
It depends on your database server, and its configuration.
Doubling ' to '' is the ANSI standard way of escaping string literal content, and should be enough.
But, if you're using MySQL or versions of PostgreSQL before 9.1, string literal syntax is not ANSI-conformant by default (it can be, if reconfigured), and the backslash character has a special meaning. This permits attacks like the \' in 680's answer.
Additionally, if you're passing byte strings to your data access function, and your database happens to be using an East Asian character encoding, you'll have the problem that str_replace does a byte replace on a ' that may be part of a multi-byte sequence, ending up with a high byte followed by '': the first quote gets eaten as part of the multi-byte sequence, then the second closes the string. (This doesn't happen in UTF-8 which is designed to avoid trailing low bytes.)
Using the appropriate escaping call for the DB you are using (eg mysql_real_escape_string), or, better, using parameterised queries, means you don't have to know about these obscure and annoying edge cases.
I have started in web development not long time ago. I know some stuff now, but I'm really concerned about security issues that may arise. I know simple security solutions like preg_replace , but I'm not confident with that.
So I would like to ask you for any sort of speaking "universal" security standards that can be applied in the following cases. As I mentioned, I'm not pro so it would be great if you can start with something simple, yet useful. If possible could you provide examples please?
I did have a look at php manual, although I would like to know additional info from person.
Here are some typical MySQL / PHP things I use in my projects. Could you suggest any improvements to make them more secure?
$sql = mysql_query("SELECT * FROM stories WHERE showing = 1 ORDER BY cr_date DESC LIMIT 5") or die (mysql_error("There was an error in connection"));
while($row = mysql_fetch_assoc($sql)){
$story_id = $row["id"];
// etc...
}
$username = $_POST['username'];
$sql = mysql_query("INSERT INTO myMembers (username, //etc... )
VALUES('$username' //etc.. ")or die (mysql_error());
$username = $_GET['username'];
//gets username from url like http://myweb.com/profile.php?username=blabla
First of all, thank you for caring about web security. Many PHP developers don't know anything about it, and don't care to learn. They are the ones who are exposing our passwords and bank accounts to hackers. Be part of the solution! :-)
1. Treat the mysql extension as if it is deprecated.
Use the PDO or mysqli extensions instead. The plain mysql extension does not support prepared statements, and some other features, such as transaction control. No one should be using mysql if they have PDO_mysql or mysqli available to them.
2. Do not interpolate external data into SQL.
Anytime you get a value from $_GET or $_POST, you should consider it to be unsafe to use in any SQL statement, or shell_exec(), or other instance where you execute the string as some kind of code.
3. Use prepared query parameters instead of interpolation.
It's really easy. In fact, it's easier to use query parameters than it is to interpolate variables into SQL strings. You don't need to worry about escaping, or long complex string-concatenation.
See example code here: http://us.php.net/manual/en/pdo.prepare.php
4. For corner cases, use careful filtering.
A query parameter takes the place for one literal value in an SQL expression. Not table names, not column names, not SQL keywords, not lists of values or full expressions. For those, you do need to use string interpolation, but see my presentation SQL Injection Myths and Fallacies for examples of how you can "whitelist" values to interpolate.
Also check out the PHP filter extension, which offers a flexible way of validating inputs or stripping off invalid characters to make sure only the valid part of the input is used.
Looking at your examples, the SELECT query has no dynamic values interpolated from external sources like $_GET. So that one is safe.
The INSERT query takes a value from the request, which could contain malicious content that changes the way your query runs. This one is a good candidate for using query parameters.
Also consider that SQL injection is one of the two most prevalent security issues with PHP. The other one is Cross-Site Scripting (XSS). This is not directly related to SQL, but you should learn about it too.
Here's a good resource for learning more about web programming security: OWASP.org cheat sheets.
Many frameworks have a good set of security measures already in place that will do a great deal in preventing things like SQL injections. Yii, CakePhP, CodeIgnitre all may be of some use.
Although it's almost impossible to beat Bill, I feel I must clarify answers stating that "you have to trust no user input".
In fact, quite contrary - SQL injection protection will do any good only if it would be totally ignorant of the data source. And treat ALL the data as potentially malicious. And process it accordingly.
Thus, to summarize all the advises:
Prepared statements is a good approach but not a complete one.
It has a brilliant idea of using some placeholder, a proxy to represent the actual value in the query. Thus this value can be properly sanitized.
But these placeholders, as Bill said, are limited to the strings and numbers only. So, it would be a good idea to add another placeholder of your own - for identifiers. But you still have to watch out SQL syntax keywords manually.
So, instead of "Do not interpolate external data into SQL." statement one have to use
"2. Do not interpolate values into query directly but only by some proxy, performing necessary precautions"
The most important thing to remember is never trust anything from an external source (eg user input, responses from other web services etc). Always sanitise all input and where possible use code from your database provider to do so.
In the case of MySQL parameterising all queries is essential, so use a prepared statement, eg
$statement = $db->prepare('SELECT * FROM stories WHERE title = :title');
$statement->execute(array(':title' => $title));
$rows = $statement->fetchAll();
Your current insert statement is vulnerable to an SQL injection attack, modify it to be closer to:
$username = $_POST['username'];
$statement = $db.prepare("INSERT INTO myMembers (username) VALUES(':username');
$statement->execute(array(':username' => $username));
You should also ensure that you never store any passwords in plain text, always store a hashed version of a password (along with a salt) and check that the hash matches rather than the actual string. This means that should your database become compromised, figuring out your user's credentials becomes a non-trivial task.
These are only a couple of ways of making your app more secure, I'd highly recommend reading OWASPs top 10 site vulnerabilities and researching these individually as each one in itself is quite a big topic!