All Methods of Sanitizing SQL in CakePHP - mysql

I've inherited a large-scale website written in CakePHP for my senior project. Unfortunately, it's highly vulnerable to SQL injections. I've never used CakePHP before so I'm trying to make sure I understand what all needs to be done. When using the save and find functions is all I have to do is use proper array notation to prevent SQL injections? For using the query method is all I have to do is use prepared statements? However, are there any other commands and methods I need to do as well? Thanks in advance.

"Typical" usage of cake's model class is going to always protect you from SQL injection vulnerabilities by properly escaping data and parameters coming and going.
BUT!!:
The model query() method assumes you will escape your parameters manually using the value() function which can be accessed in the models, e.g.:
$db = $this->getDataSource();
$sql = "SELECT * FROM foo WHERE bar='" . $db->value($param, 'string') . "'";
$data_array = $this->Foo->query($sql);
FYI if you need to access the value() function in a controller, you have to do something like:
$db = ConnectionManager::getDataSource('default');
...
And as you mentioned, you can also use prepared statements, in which case the driver itself handles the escaping.
Be mindful that, while standard usage of the model methods (other than query()) will handle everything for you, there are funky things you could do -- like passing parameters through array keys or creating complex finds (e.g., full text MATCH ... AGAINST syntax) -- that will still require you to prevent SQL injection vulnerabilities via manual coding!
In general, try to avoid query() and/or prepared statements whenever the ORM and standard model methods will do the trick!
With any framework, trust but verify. I.e., use API doc to confirm advertised functionality. E.g.,:
http://api.cakephp.org/2.6/class-Mysql.html#_value

Related

Is there a way to perform "SELECT JSON ..." with the QueryBuilder in the CQL drivers?

I dug through datastax's QueryBuilder source code and I can't find a way to a query like:
select JSON * from myTable;
Also, it would be fairly easy to make a subclass to do this, but that is thwarted by the package protection of the constructors in com.datastax.driver.core.querybuilder.Select.
Is there any way to do this query?
Right now it's not possible but you will be able to use a new select().raw() method to inject arbitrary string like "JSON *".
See the resolution of this JIRA: https://datastax-oss.atlassian.net/browse/JAVA-1086
Added new syntax:
select()
.cast(fcall("writetime", column("country")), DataType.text())
.from("artists").limit(2);
I also exposed the raw method in the top-level API, so this will serve as a workaround for this kind of issue in the future:
select = select().raw("CAST(writetime(country) AS text)").from("artists").limit(2);

What are Best Practices for preventing SQL injection in node-mysql?

There has been some discussion on this topic (e.g. Preventing SQL injection in Node.js )but really no clear-cut clarity or a deep discussion, let alone good documentation anywhere. The node-mysql docs discuss prevention of SQL injection and some escape functions. However, it is unclear how these functions prevent SQL injection. The manual says "Strings are safely escaped." Nothing more... Is that limited to escaping some characters only?
There seem to be other equivalents in node-mysql for the same function as in connection.escape and pool.escape with an emphasis again that these functions are used to prevent SQL injection.
There also does not seem to be support for a true prepare statement in node-mysql. The plans and documentation are again unclear on this. Node-mysql is clearly a very popular module in the node.js environment and fairly stable at least in the limited experience I had with it. What are the Best Practices for preventing SQL injection in node-mysql?
Remember that SQL injections are caused by hostile strings being interpreted as commands, not by blocking commands. Are you sure that you're getting the original string back, not a stringified version?
For example there's a huge difference between these two: "test" and "'test'".
Generally only harmful characters are escaped, the rest are left as-is.
Using the low-level driver is best avoided. Try and use a library like Sequelize to provide some abstraction and more support. That module supports placeholder statements that generally make escaping a non-issue, it's handled automatically.
See the section on raw queries with replacements where you have the ability to do this:
sequelize.query('SELECT * FROM projects WHERE status = ?',
{ replacements: ['active'], type: sequelize.QueryTypes.SELECT }
).then(function(projects) {
console.log(projects)
})
There's no risk of user data leaking through because you've supplied it as an explicit value that's handled properly, not an inline string in the query.
still sequelize is vulnerable
db.query('SELECT Desc FROM Items WHERE Username IN (:names)', {
replacements: {
names: ["Bobby", "'); DELETE FROM Items WHERE 1=1; --')"]
}
});

Hashed password must be sanitized?

It's just a curiosity. If you encrypt a password (using sha1 or other methods) before inserting it in a query, it must be anyway sanitized? Or the hash's result is always safe?
This simple code are safe?
$salt = "123xcv";
$password = $_POST['password'];
$password = sha1($password+$salt);
$query = "select * from user where password='$password'";
Unless you validated the input somehow you shouldn't assume that it will always return a safe output because functions such as SHA1 can return error values if given unexpected input. For example:
echo '<?php echo sha1(''); ?>' | php
Warning: sha1() expects at least 1 parameter, 0 given in - on line 1
And this output obviously violates the assumption that "it's always a hex string". Other hashing functions in other languages can present yet another behaviour.
Apart from that, the above password hashing code scheme ($password = sha1($password+$salt);) is very weak (see why) and I would strongly recommend not using it even in an example as someone is eventually guaranteed to find it on StackOverflow and use in production.
Also, as already noted above, building SQL queries by concatenating strings is also a bad practice and can lead to security issues in future: today the only parameter in the query will be the password, tomorrow someone decides to add some other option and I bet they won't rewrite the query but just use the template that is already there...
This sql injection question question is asked out of a common delusion.
In fact, there is no such thing like "sanitization" at all, nor any function to perform such non-existent task. As well as there is no "safe" or "unsafe" data. Every data is "safe", as long as you're following simple rules.
Not to mention that a programmer have a lot more important things to keep in mind, other than if some particular piece of data is "safe" in some particular context.
What you really need, is to avoid raw SQL for such silly queries at all, using an ORM to run SQL for you. While in such rare cases when you really need to run a complex query, you have to use placeholders to substitute every variable in your query.
From the documentation:
The value is returned as a string of 40 hex digits, or NULL if the argument was NULL.
Assuming you have a large enough varchar column, you have no sanitization to do.
This being said, it's always cleaner to use prepared statements, there's no reason to just concat strings to build queries.

sanitizing data before mysql injection and xss - am i doing it right with pdo and htmlpurifier

I am still working with securing my web app. I decided to use PDO library to prevent mysql injection and html purifier to prevent xss attacks. Because all the data that comes from input goes to database I perform such steps in order to work with data:
get data from input field
start pdo, prepare query
bind each variable (POST variable) to query, with sanitizing it using html purifier
execute query (save to database).
In code it looks like this:
// start htmlpurifier
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
// start pdo
$pdo = new PDO('mysql:host=host;dbname=dbname', 'login', 'pass');
$pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare and bind
$stmt = $pdo -> prepare('INSERT INTO `table` (`field1`) VALUES ( :field1 )');
// purify data and bind it.
$stmt -> bindValue(':field1', $purifier->purify($_POST['field1']), PDO::PARAM_INT);
// execute (save to database)
$stmt -> execute();
Here are the questions:
Is that all I have to do to prevent XSS and mysql injection? I am aware that i cant be 100% sure but in most cases should it work fine and is it enough?
Should I sanitize the data once again when grabing it from db and putting to browser or filtering before saving is just enough?
I was reading on wiki that it's smart to turn of magic_quotes. Ofocurse if magic quotes puts unnecessery slahes it can be annoying but if I don't care about those slashes isn't turning it of just losing another line of defense?
Answer:
Please note that code I have written in this example is just an example. There is a lot of inputs and query to DB is much more complicated. Unfortunately I can't agree with you that if PDO type of variable should be int I do not have to filter it with XSS attacks. Correct me if I am wrong:
If the input should be an integer, and it is then it's ok - I can put it to DB. But remember that any input can be changed and we have to expect the worse. So if everything is alright than it is alright, but if a malicious user would input XSS code than I have multiple lines of defense:
client side defense - check if it is numeric value. Easy to compromise, but can stop total newbies.
server side - xss injection test (with html purify or ie htmlspecialchars)
db side - if somehow somebody puts malicious code that will avoid xss protection than database is going to return error because there should be integer, not any other kind of variable.
I guess it is not doing anything wrong, and it can do a lot of good. Ofcourse we are losing some time to calculate everything, but i guess we have to put on the weight performance and security and determine what is more important for you. My app is going to be used by 2-3 users at a time. Not many. And a security is much more important for me than performance.
Fortunately my whole site is with UTF8 so I do not expect any problems with encoding.
While searching the net i met a lot of opinions about addslashes(), stripslashes(), htmlspecialchars(), htmlentities().. and i've chosen htmlpurity and pdo. Everyone is saying that they are best solutions before xss and mysql injections threats. If you have any other opinion please share.
As for SQL injection, yes, you can be 100% sure if you always use prepared statements. As for XSS, you must also make sure that all your pages are UTF-8. HTML Purifier sanitizes data with the assumption that it's encoded in UTF-8, so there may be unexpected problems if you put that data in a page with a different encoding. Every page should have a <meta> tag that specifies the encoding as UTF-8.
Nope, you don't need to sanitize the data after you grab it from the DB, provided that you already sanitized it and you're not adding any user-submitted stuff to it.
If you always use prepared statements, magic quotes is nothing but a nuisance. It does not provide any additional lines of defense because prepared statements are bulletproof.
Now, here's a question for you. PDO::PARAM_INT will turn $field1 into an integer. An integer cannot be used in an SQL injection attack. Why are you passing it through HTML Purifier if it's just an integer?
HTML Purifier slows down everything, so you should only use it on fields where you want to allow HTML. If it's an integer, just do intval($var) to destroy anything that isn't a number. If it's a string that shouldn't contain HTML anyway, just do htmlspecialchars($var, ENT_COMPAT, 'UTF-8') to destroy all HTML. Both of these are much more efficient and equally secure if you don't need to allow HTML. Every field should be sanitized, but each field should be sanitized according to what it's supposed to contain.
Response to your additions:
I didn't mean to imply that if a variable should contain an integer, then it need not be sanitized. Sorry if my comment came across as suggesting that. What I was trying to say is that if a variable should contain an integer, it should not be sanitized with HTML Purifier. Instead, it should be validated/sanitized with a different function, such as intval() or ctype_digit(). HTML Purifier will not only use unnecessary resources in this case, but it also can't guarantee that the variable will contain an integer afterwards. intval() guarantees that the result will be an integer, and the result is equally secure because nobody can use an integer to carry out an XSS or SQL injection attack.
Similarly, if the variable should not contain any HTML in the first place, like the title of a question, you should use htmlspecialchars() or htmlentities(). HTML Purifier should only be used if you want your users to enter HTML (using a WYSIWYG editor, for example). So I didn't mean to suggest that some kinds of inputs don't need sanitization. My view is that inputs should be sanitized using different functions depending on what you want them to contain. There is no single solution that works on all types of inputs. It's perfectly possible to write a secure website without using HTML Purifier if you only ever accept plain-text comments.
"Client-side defense" is not a line of defense, it's just a convenience.
I'm also getting the nagging feeling that you're lumping XSS and SQL injection together when they are completely separate attack vectors. "XSS injection"? What's that?
You'll probably also want to add some validation to your code in addition to sanitization. Sanitization ensures that the data is safe. Validation ensures that the data is not only safe but also correct.

Perl DBI without accessing the database

I'm creating a set of SQL INSERT statements for a database that doesn't exist yet, and I'm saving them to file.
How can I use Perl's powerful DBI module to create those INSERT statements without accessing a specific database. In particular, it looks like using the $dbh->quote() function requires that I instantiate $dbh with a connection to a database.
Unfortunately, the actual quote() behaviour isn't always a portable characteristic, so each driver will do them differently. Unless you connect to a driver, you don't know which quoting format to use in practice. (There is one module that might do this without a connection, DBIx::Abstract, but it is not especially current.).
The quote() method is actually implemented by the corresponding driver class, in the DBD::* namespace. You might attempt to load the driver you need and call the function directly (see http://search.cpan.org/~timb/DBI-1.616/lib/DBI/DBD.pm#Writing_DBD::Driver::db::quote) but this feels grubby.
I'd still make a DBI connection, if only so that you get the right format of quoting. You don't need to actually send it any statements, but then you do know that the quoting format will be correct for the database you will use.
From DBI::quote:
For most database types, at least those that conform to SQL standards, quote would return 'Don''t' (including the outer quotation marks). For others it may return something like 'Don\'t'
That is, the behavior of DBI::quote varies from database to database, and it doesn't make sense to call it in a database-independent way.
Make a trivial connection to a database of the same type you are writing for, or learn your database's quoting conventions and implement a quote method yourself. See the DBI source for a reference implementation.
Usually you would use DBI by specifying a database like so:
my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=127.0.0.1");
However, your database does not yet exist so you cannot connect to it. You can use DBI without specifying a database like so:
my $dbh = DBI->connect("DBI:mysql:;host=127.0.0.1");
You could use DBD::CSV or DBD::AnyData as a dummy database. SQLite is good for this purpose, too.
A hidden advantage of using SQLite here is that it's a semi-real database, and will tend to make you write code in a way that's decoupled from any specific database.
According to perl -MDBI -E 'say join(q{,},DBI->available_drivers);'
in clean Debian chroot with only DBI (package "libdbi-perl") installed the following drivers are available right away:
DBM,ExampleP,File,Gofer,Proxy,Sponge
The minimum DBI connect statement that works for me is
my $dbh=DBI->connect("DBI:DRIVER:"); # DRIVER is one of [DBM,File,ExampleP,Sponge,mysql,SQLite]
That is enough to use $dbh->quote() with no database whatsoever.
DBM and File escape q{'} as q{\'} ("mysql" style);
ExampleP and Sponge escape: q{'} as q{''} ("SQLite" style).
You can also use:
DBD::_::db->quote()
To access the quote function without setting up a database handle. I don't believe it is specific to MySQL though.