Is there a security risk in exposing MySQL tables names in javascript? - php

I have an ajax method that esentially works like this
function getRow(tableName, idName, idValue, callback)
The obvious benefit of this is that I have one function that can retrieve data from any table. However, this just feels wrong from a security perspective, is it a security risk to do so? The corresponding PHP files that actually read/manipulate the database are secured through a prior authentication process, so theoretically, the visibility of table names in a vacuum shouldn't be a risk (not to mention that the database only accepts localhost connections), but I wonder if there isn't a better/prettier way to accomplish this.
Edit: Just to clarify the authentication process, user/role security prevents access to all tables except those explicitly allowed for the user.

If you're sure that you have no SQL injection vulnerabilities, and that you never will, it's fine.
If you do have a SQL injection vulnerability, it will make the attacker's job somewhat easier.
It goes without saying (I hope) that the server-side script must use a whitelist of tables and columns that can be exposed via this method.

Tables names alone aren't that bad, however, the API you seem to be making may not be the best idea...
Think carefully about if there are some tables that people shouldn't be able to query, because from the looks of it, I could query any table in your database from the client side. For example:
getRow('users', 'id', '7', function(data){console.log(data)})
What if the users table returns their password? even if it is hashed, thats not good. Or their email? What if I want to harvest all of the users emails? Pretty easy script I could write to do that.

It is a risk because it provides information to attackers. It's the same as providing the software version of software that you are using. It is not a vulnerability per se, but it's a door to vulnerabilities.

This is a really bad idea.
For instance lets say you are using this code:
$table_name=mysql_real_escape_string($_GET['table']);
$id_name=mysql_real_escape_string($_GET['idname']);
$id_value=mysql_real_escape_string($_GET['idvalue']);
mysql_query("select * from `$table_name` where `$id_name`='$id_value'");
This can be exploited a number of ways:
NOT SQL Injection
This query will return the root user in mysql.user, and this is
?table=mysql.user&idname=user&idvalue=root
This request will create the query:
select * frommysql.userwhereuser='root'
SQL Injection:
This works because mysql_real_escpae_string does not escape back-ticks:``
?table=`table where 1 union select * from mysql.user/*&idname=junk&idvalue=junk

You can show eg users table name in JS but on server side add prefix like forum_users, which will be actual table name in database. That way if someone finds injection point he will try DROP TABLE users and the query will fail, if you are lucky :)
Also add a white/black list for tables and columns, add LIMIT 1 (don't loop), don't return multiple arrays, and you should sanitize with something like this.
$select = preg_replace("#[\w]#", "", $_GET["select"]);
$from = preg_replace("#[\w]#", "", $_GET["from"]);
$where = preg_replace("#[\w]#", "", $_GET["where"]);
$equals = mysql_real_escape_string($_GET["equals"]);
$query = "SELECT $select FROM $from WHERE $where = '$equals' LIMIT 1";

A direct database API on the client-side should be used for very special cases of course. But you can safeguard it easily with a whitelist. In PHP for example:
if (in_array($tableName, array("users", "log", "messages", ...))) {
So I don't think it's that big of a deal from a security standpoint as long as you have a fixed list here.

Related

Potential dangers of using unprepared SQL queries when not processing user input?

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.

Can someone perform a SQL Injection based on session variables in php?

Basically I am making a web application and I am going through the security of it to make my app as robust as I can.
Once you're logged in to my app I track that user based on session variables.
When SQL is performed it takes the users session variable to see who they are for example.
$name = $_SESSION['user_name'];
A example query would be something like this..
$query1 = "SELECT * FROM tableName WHERE userName = '$name'";
From reading online sites say things like I must not use "user input in SQL statements." Am I right in thinking that because I am using session variables the user does not have direct access to the sql statement or is session variables still "user input"?
If not should I just go through the normal SQL Injection prevention methods like...
Input validation (authenticating the data based on length, syntax
etc)
Checking user privileges making sure users have the least
privileges.
ect..
Thanks in advance for any comments anyone makes.
It doesn’t matter where the data came from as in any case you have to ensure that the data is interpreted as intended.
And one of the easiest way to ensure that is using parameterized statements, where the SQL code and parameter values are passed separately so that a parameter value can’t be mistakenly interpreted as SQL.
Prepared statements implement this parameterization, either native or emulated. With them you don’t have to worry about whether a value may be influenced by a user’s input.
Always escape input. What if their name is "David O'Connor" or something.
This name is assumedly user supplied, so do it.
Anyway, you shouldn't be directly issuing SQL queries, a function should be building them for you (or an ORM).
Am I right in thinking that because I am using session variables the user does not have direct access to the sql statement or is session variables still "user input"?
The problem you might have in your example is that the username might be something controller by the user. They might be able to change it or choose it depending on your application requirements.
I think the simplest way to prevent surprises is stop thinking too much and just protected your queries agaisnt SQL Injection.
I'm no expert on PHP, but I think you have prepared statements that will help you dealing with this security issue. Just use it. (it should be a slogan, "prepared statements, just use it." :D)
Any login/create-user page you have should do input validation before writing the userName column in your database and writing $_SESSION['user_name'].
AFTER that, your $_SESSION variable is safe. You have to do validation checks somewhere in the process:
Input -> store in database/session -> use
I recommend at the 1st arrow. Then the code snippets you wrote in the question are perfectly fine.
Am I right in thinking that because I am using session variables the
user does not have direct access to the sql statement
correct. $_SESSION-vars are stored on your server-filesystem and unless you introduce user-input ($_GET & $_POST, for example) into them there is no actual way of manipulation for these. If you generate $_SESSION['user_name'] without actual userdata you're well off. The hard part is getting the username without parsing input - one would be advised to use HTTP-data-filtering frameworks for these kinds of jobs.

No user interactivity Can I still get SQL Injection

I have pages that only display data from DB tables, the php pages only display the information they don't have any buttons, links, drop down menus, or forms.
Im using the old mysql and not the mysqli or PDO for syntax
Can I still get a SQl injection hack?
In order for SQL Injection to work, they need a way to send SQL Code to your server, as there is no input, it is in theory impossible for them to Inject SQL. (Although I am not an expert in the subject)
I would still recommend you to use a framework like mysqli or PDO, you should familiarize yourself with such frameworks as they became the norm in website design.
SQL Injection works by injecting strings into the SQL you're executing.
This is easiest if the application presents you with a nice text box whose content it glues into a SQL query, but it's also possible through other means.
For instance, if your reporting application uses any kind of the HTTP request to show data, an attacker can use WGET to spoof the request and inject SQL. For instance, if your reports have a URL format of http://myserver/report.php?month=february and you use february to build a SQL query, you're vulnerable.
It all depends on the query source. If ANY part of your SQL query comes from a user input (in other words; if not your whole query string is a string constant) then you are not safe.
For example:
SELECT * FROM USERS ;
SELECT * FROM myTable WHERE id = 5;
is safe but
SELECT * FROM myTable WHERE id = (some variable derived from user input like querystring or post-form)
is DEFINETELY not.
You should use
SELECT * FROM myTable WHERE id = #0
syntax for maximum security. This is the only one proven way to keep safe from SQL injection.
If the query is independent of the request you are safe. Be warned that mean users are very creative. You might have some dependency on user data which you are not aware of. E.g. a script like this might be broken:
$locale = Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
$sql = "SELECT * FROM entities WHERE id = 7 and locale = '$locale'";
Disclaimer: I'm not aware if Locale::acceptFromHttp() does some validation. Let's just assume for the context of this post it doesn't.
I don't want to say it's not possible to write safe code without prepared statements. OTOH it really doesn't hurt using them.
SQL injection occurs if user-controllable data is used in an SQL statement without proper processing:
The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.
Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Note that user-controllable data include any data that can be influenced by the request of a user, directly or indirectly.
Conversely, this means if your SQL queries don’t contain any user-controllable data, i. e., the queries are fixed in code and are not influenced by any changeable input, it cannot vulnerable to SQL injections.
I have pages that only display data from DB tables, the php pages only display the information they don't have any buttons, links, drop down menus, or forms.
I would dare to say that such a setup is just impossible.
The very idea of having a dynamical web-page, served by a php script from database, is to use the same script to show different content from database.
So - either you indeed have only set of static pages (which I doubt) - you need no PHP/database for them then - just static HTML would be enough.
Or - most likely - you have dynamical pages showing content based on user input of some sort - and thus perfectly vulnerable.

SQL Injection through mysql_query [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 3 years ago.
I'm working on a site that has been hacked through SQL Injection (at first glance only db entries are corrupted with cross-site scripting) the potential vulnerability I found after looking at the code is that there's a lot of mysql_query call whose inputs are not escaped at all.
The good old :
$query = "SELECT * FROM mytable where name LIKE '%".$_GET['name']."%'"; /*HACK HERE*/
mysql_query($query, $connection);
Nevertheless I can't find how can we do something cool from that injection vulnerability (by cool I mean something like an INSERT or an UPDATE). I've tried to build a statement like this one :
SELECT * FROM mytable where name LIKE '%' AND WHERE id IN (INSERT INTO secondtable (id,description) VALUES (15, 'Fifteenth description');--%'
No success. I guess that the INSERT has nothing to do here.
I'm escaping all user's inputs in the code right now but I've not really get how hackers have penetrated this site, then I'm not 100% sure that my fix will do the job. Any brilliant suggestions ?
Thanks
Depending upon the version of mysql you are using, and the setup of the connection, mysql_query may allow more than one statement.
You should look at how the connection is being created, and for any usage of mysql_set_server_option.
Because mysql_query is not supporting multiple queries, So any injection that is doing like '; DROP TABLE mytable; -- won't be successful.
However, the attacker can combine with other select statement to select the other info like password info.
Interesting that your question hasn't received many (correct) answers yet!
As you discovered, usual PHP MySQL APIs like mysql_query, mysqli::query etc. only execute the first SQL statement in case one passes several of them (separated by semicolons), as would an attacker using the most common class of SQL injections.
Defender tip: banish mysqli::multi_query and friends from your code; the minute performance improvements are not worth the risk.
Does this clever move by PHP-folk completely close all attack channels on some code that goes like "SELECT yadda yadda" . $_GET["untrusted"]? Not quite. As knittl remarks, even a pure-DQL SELECT can be used to escalate one's privileges by UNION ALL SELECT'ing from any nearby interesting table, including but not limited to the passwords table. There are cheat sheets out there giving enough tips and tricks to basically extract the entire database this way.
Defender tip: apply defense-in-depth with known-good techniques:
input validation
whitelist indirection in an associative array
prepared statements (if you can make sure that they are effective and not just string escaping in disguise!)
an ORM
protective encoding (e.g. Base64) when the untrusted input cannot be satisfactorily sanitized (e.g. a blog post that may legitimately contain SQL-sensitive punctuation)
or as a last resort only, string escaping
Next, one may observe that not all DQL is side-effect free, in particular when it ends with INTO DUMPFILE somethingsomething.
Defender tip: always configure secure_file_priv in your MySQL / MariaDB server.
Last but not least, even an attacker who is in a position to inject arbitrary SQL is limited by the authority granted to the Web app as a whole.
Defender tip: secure your app by applying POLA.
Only GRANT the Web app's MySQL user as much authority as it needs. It is not a bad idea to design your app so that it requires no DDL at all. If you must provide a “back up / restore DB” feature or some such from the Web UI, use a separate MySQL user for that.
Automate backups, even though they are useless — restores are what matters.
Possible scenario 1
Weak passwords/hashing will let an attacker to select administrator's password.
It would be wise to change all administrators passwords.
Now, it's been a while since did any php, but in general most data access libs have some sort of parameterized sql to reduce the risk. A quick google came up with this for php:
http://php.net/manual/en/pdo.prepared-statements.php
The other poster have already described how to do a sql injection so I won't get into that.
I'm pretty sure that a hacker would be able to modify the query easily. Even if mysql_query() doesn't support multiple queries, there are ways around that. you could just use a mysql IF statement added on to the end, and of course that will execute a completely new query.
$query = "SELECT * FROM mytable where name LIKE '%".$_GET['name']."%'";
$_GET['name']="'; DROP TABLE mytable; -- ";
so
$query = "SELECT * FROM mytable where name LIKE '%'; DROP TABLE mytable; -- %'";

How to secure project against hacks and attacks?

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!

Categories