Posts Tagged ‘MySQL’

MongoDB is vulnerable to SQL injection (in PHP at least)

Thursday, July 29th, 2010

Its a misconception amongst some PHP programmers that because MongoDB doesn’t use SQL (all queries are passed in as either BSON or PHP objects which have been converted into BSON) it isn’t vulnerable to SQL injection. It is pretty easy to show that if your lazy and complacent when you code you can leave yourself just as vulnerable to attack.

Lets assume we have a table of users with a username and password field. In MySQL you’d be asking for trouble if in your authentication function you did the something along the lines of the following:

if (mysql_query(“SELECT * FROM users WHERE username=’$_GET['username']‘ AND password=’” . $_GET['password'] . “’”)) {
do_auth();
}

And someone passed in

‘ OR ‘1′=’1

into your password field. If you simply checked the response and authenticated the user based on if a row was received from the MySQL Database the user would authenticate as the $_GET['username'] every time. The correct approach would be to sanitize your $_GET parameters before you pass them into MySQL.

In MongoDB you might be tempted to do something like

if ($result = $mongo->test->users->findone(array(”username” => $_GET['username'], “password” => $_GET['password']))) {
do_login();
}

No query language no SQL injection right? Wrong. Epic fail. Don’t forget in PHP when you append [] to a $_GET['variable'] it turns into an array within php.

http://woot.php?variable[]=hello

$_GET['variable'] is now a PHP array(0 => ‘hello’). We can even assign the key of the array like this

http://woot.php?variable[ne]=hello

Now $_GET['variable'] is a PHP with array with a key array(’ne’ =>’hello’). When you pass this to mongo db as your password paramater it evaluates to “Password does not equal ‘hello’” which will pass every time.

What can you do? Sanitise your input. Don’t allow multi dimensional arrays to be passed as a input parameters to mongo. Surprisingly there isn’t a function built into the mongodb pecl extension to do this, With more and more large sites turning to MongoDB its only going to be a matter of time before a large website is found to be vulnerable to this type of attack.

The MySQL server is running with the –skip-grant-tables option so it cannot execute this statement

Friday, February 12th, 2010

So you lock yourself out of MySQL and see the following error when you try and change the password using the –skip-grant-tables option

mysql> GRANT ALL PRIVILEGES ON *.* TO “w000t@%” IDENTIFIED BY ‘passwordthinggy’;
ERROR 1290 (HY000): The MySQL server is running with the –skip-grant-tables option so it cannot execute this statement

Its because the grant tables still have to be loaded – if you want to change the password so you’ll need to

FLUSH PRIVILEGES;

Before you issue your grant statement.

Reduce load times, speed up your website, increase revenue

Sunday, June 14th, 2009

Page load speed is everything. Tests done by Amazon have shown that an increase in page loading times by 100ms can reduce sales by 1%; when Google added 500ms to its response times traffic dropped 20%. The premise is simple: a faster website means faster feedback to the user which enables a faster user learning curve.

If like me you have a website that is powered by the LLMP (Linux Lighttpd MySQL PHP) stack then there are some simple steps you can take to decrease your page load times. If your running Apache and not Lighttpd then maybe its time to move :) (more…)

Moving hosts

Sunday, May 17th, 2009

Today I switched hosts and purchased a virtual server from bytemark. I’ve got to say I really like it. It’s cheap, fast and seems to be quite stable. The new setup is

  • PHP 5.3
  • Mysql 5.1
  • Lighttpd

Which I guess makes it a LLMP stack rather than a LAMP stack. I’ve become a big fan of Lighttpd recently, its pretty much Apache but without the bloat. Its also got some nice traffic shaping features that seem to be lacking from Apache and uses way less resources. Pretty handy when your server only has 256mb of ram.

Moving over to a virtual host has been pretty simple as has migrating the blog from blogspot to wordpress. The new virtual host has given me much greater control over my blog so you can expect to see some new funky code in the near future.

Using MySQL triggers to encrypt passwords

Tuesday, November 18th, 2008

Sometimes it’s helpful to take the handling of the passwords away from PHP and let the database do all the hard work. With the help of triggers and a simple MySQL function its possible to generate a salt and a hash from a plain text string. Doing password security this way makes it harder for the PHP programmers to make a mistake and ensures that passwords encoded as plain text will never appear in the database.

Lets start by creating a table to store users email addresses, passwords and salts.

CREATE TABLE `users` (
`email` VARCHAR( 255 ) NOT NULL ,
`salt` VARCHAR( 40 ) NOT NULL ,
`password` VARCHAR( 32 ) NOT NULL ,
PRIMARY KEY ( `email` )
) ENGINE = InnoDB

Now lets create a function to generate a random string for us – this will be our salt

CREATE FUNCTION `make_salt`(len TINYINT UNSIGNED) RETURNS varchar(255) CHARSET latin1
BEGIN

DECLARE salt varchar(255);
DECLARE i TINYINT UNSIGNED;

SET i = 0;
SET salt = ”;

WHILE i < len DO
SET salt = CONCAT(salt, CHAR(FLOOR(40 + (RAND() * 210)+1)));
SET i = i + 1;
END WHILE;

RETURN salt;

END//

Finally lets insert 2 triggers, one for the insert, one for the update. This will encrypt all passwords sent to the MySQL table and also generate salts for them.

CREATE TRIGGER encrypt_password_insert BEFORE INSERT ON users
FOR EACH ROW BEGIN

SET NEW.salt = make_salt(40);
SET NEW.password = SHA1(CONCAT(NEW.salt, NEW.password, NEW.email));

END;

The update trigger will re-encrypt the password and re-generate the salt when the table is updated

CREATE TRIGGER encrypt_password_update BEFORE UPDATE ON users
FOR EACH ROW BEGIN

SET NEW.salt = make_salt(40);
SET NEW.password = SHA1(CONCAT(NEW.salt, NEW.password, NEW.email));

END;

Simple eh? You might well wonder why I’ve hashed their email along with the password, this forces the programmer to ask the user to re-specify their password when they change their email address. The salt function ensures that every time they update their password or email that the salt will also change. Lets look at the results of the following insert on the table

INSERT INTO users SET email=’john@malcom.com”, password=”hello world”;

If you now look in at the user john@malcom.com you’ll see that their password has been turned into the SHA1 hash of the salt field (which is now populated) and the password and email. It should look something like this:

82b6f04c63640a2dd5da7650d36001b4a5f10707

Now if you want to verify that the password / username you can simple do the following

SELECT * FROM users WHERE email=’john@malcom.com’ AND SHA1(CONCAT(salt, ‘hello world’, email))

If the number of returned rows is 1 then you can grant the user access.

This approach to password security is fine as long as the connection between PHP and MySQL is secure. If your connecting to a remote MySQL server over an un-secure connection then you’ll want to hash your passwords before they are sent out. Its also worth mentioning that the password may be visible on the server when viewing processes.