seanmonstar

Jul 16 2009

Random String Generation with Symbols

I’ve been playing with some random string generation, since I built a fairly simple one in a recent project for when users forget their password, and I reset it. It seemed decent enough: produced a string of strong size, alpha-numeric. It was good enough.

base_convert(uniqid(rand(),true),10,36)

It didn’t take long after I had commited that code before I started thinking it could be better. At least, if I need it to be better, then it could be. For instance, if it’s going to be used for security reasons, it should include symbols, and upper-case characters. Then I thought that this “improved” version would be far superior for providing a salt than previously seen examples.

substr(md5(uniqid(rand(),true)),0,8)

The above line will provide a random string, but it’s weak in a few ways. First, it’s only 8 characters long. We should be aiming in the high ‘teens. But that’s easily fixed by changing the substr length. However, its bigger weakness is that it’s text coming from a hexidecimal output. Each character only has 16 possibilities, which is way smaller than 62, or more.

I Like “Or More”

The amount of possible combinations is dependent on the number of characters, and the number of characters available. In math terms it would look something like this:

f(x,y) = x^y

Where x is the size of the character set, and y is the number of characters in the string. So, the possible variations of a string of length 15 hexidecimal characters is: 16^15 = approx. 1.15 quintillion .

If we increase the character set to include all letters, upper and lower case, plus most all the symbols on the keyboard, we can get something like 92 characters to choice from. With the length staying the same, we get: 92^15 = approx 286 octillion . Don’t worry, I did the math for you: That’s an increase of 250 million times .

Like a computer really wants to brute force that .

How I Got “More”

I didn’t want to simply create a huge list of possible characters, and then use a loop and a random number generator to eventually build the string. I wanted to try to keep it as much as possible in native functions. I recognize that using a loop might provide more randomness, as there would be no possible pattern, but I feel this is sufficient.

I start with my original method, I just call that randomAlphaNumeric , cause that might be useful in other situations. Then, a whole mess of things.

I split the string based on a random number, then rebuild the string with spaces. I capitalize the first letter of every word, then remove all the spaces. Then I grab a couple of symbols based on a random length, attach them on the end, and shuffle the string. Last, I take the length of the original alphanumeric, simply to prevent hugely differing string lengths.

function randomAlphaNumeric() {    
	return base_convert(uniqid(rand(),true),10,36);
}

function randomPassword() {    
	$alphanum = randomAlphaNumeric();    
	$symbols = str_shuffle('~`!@#$%^&*()_-+={[]}|\\\\;:,<.>/?');        
	return substr(           
		str_shuffle(             
			str_replace(' ','',              
				ucwords(               
					implode(' ',                
						str_split($alphanum,                
							rand(1,strlen($alphanum)-1)                 
						)                
					)               
				)              
			)             
			.substr($symbols,0,              
				rand(1, strlen($symbols) - 1)              
			)           
		),0,strlen($alphanum)-1);
}

Again, this isn’t the best way of doing things. It was more of an exercise on my part to find an interesting way to generate a string that contained all the characters I wanted. We can easily remove some of the symbols from the $symbols string if any are illegal in the usage of the generated string.


Mar 2 2009

Try end() next() time

Here’s a short tip today. I’ve been finding that when using foreach in PHP to check if there’s more in the array, the use of next() has failed me on multiple occasions . I just converted every instance of next() in my code to instead use end().

if($cat !== end($categories)) {    echo ", "}

This way, I don’t need to worry about the internal pointer being pushed around before the loop, or during the loop. I really only care if the value I’m abusing is the last value, anyways.


Feb 6 2009

Making Objects in an Array Unique

I was doing some sorting of Models in PHP. Unfortunately, I didn’t have the luxury of letting the SQL do it all for me. Usually it does. But besides sorting, I had to make sure I didn’t have any duplicate entries, since I was merging arrays with different queries. My first hope was PHP’s array_unique method.

array_unique($array) will return an array with all duplicate values removed. What’s deemed duplicate is when the string values are the same . This doesn’t work for objects. I had used usort previously, soI looked for something similar like a uunique or something. No such luck.

I did find array_filter, which lets me specify a function the will determine what values get kept in the array and what gets ditched.So I created a simple dummy function, inside make a static array, grab the id from each model value in the array. Iadd the id to the static array, and then check the next value to see if theid has already been stored.

function unique_obj($obj) {
	static $idList = array();
	if(in_array($obj->id,$idList)) {
		return false;
	}
	$idList []= $obj->id;
	return true;
}
$posts = array_filter($posts,'unique_obj');

Oct 28 2008

ArrayAccess Interface in PHP

This past week, I was using PHP’s DOMDocument class to work with some XML generation. It’s pretty similar to Javascript’s DOM manipulation. The XML I was generating was a bunch of items with key attributes. () Learning how to extend a new class so that it behaves like a PHP Array made me outright excited for PHP ! Let’s delve into the magic.

I needed to create in XML:

<item key="object">DOMAIN</item>

I needed to create items in this nature for various different properties to communicate to a domain API. Since this is essentially a hash, or associate array, it’d be awesome if it could work like one. Well, it can!

$dt_assoc['object'] = 'DOMAIN';

After writing my class, that’s how I’m able to create XML items. It all lies in using an object that implements the ArrayAccess interface. Doing so gives the object functions that are called when you try to access the object like an array. So by implementing the functions, you can write custom logic that happens, besides just simply holding a value like normal arrays do.

The above statement calls ArrayAccess::offsetSet($offset,$value); , so here’s the implementation.

public function offsetSet($offset,$value) {
	$item = $this->dom->createElement('item',$value);
	$attr = $this->dom->createAttribute('key');
	$item->appendChild($attr);
	$text = $this->dom->createTextNode($offset);
	$attr->appendChild($text);
	$this->items[$offset] = $item;
	$this->el->appendChild($item);
}

Using DOMDocument to create XML for me, I create an item wrapped around the value, create an attribute called key, and give text of the offset. So instead of needing to write this process out for every new item, I just need to set a new key and value of an object that implements this interface.

There are 3 other methods to the interface, as well as one more function I define to export the data of this object into XML.

The constructor takes a name of an element to wrap all the items in, as well as the instance of the DOMDocument. You need to hold onto the original instance. This class creates an XML element of <$name>items go here</$name> .

The array $data is an associate array in the object to keep track of all the values of every item. The array items keeps a reference to the item nodes in the DOMDocument, so they can be easily removed with offsetUnset() .

offsetExists simply checks if there is an item with the key of offset, and offsetGet returns the value of the item with the appropriate key.

Lastly, toXML() is a new function unrelated to ArrayAccess, but useful to me, which just returns the DOMElement that is holding onto all these items.

Here’s the full class. You’ll find DOMDocument and ArrayAccess useful as well, if you need to do something similar.

class SRSData implements ArrayAccess {
	var $el;
	var $dom;
	var $data;
	var $items;
	
	public function __construct($name,$dom) {
		$this->el = $this->dom->createElement($name);
	}
	
	public function offsetExists($offset) {
		return isset($this->items[$offset]);
	}
	
	public function offsetGet($offset) {
		return $this->data[$offset];
	}
	
	public function offsetSet($offset,$value) {
		if($value instanceof SRSData) {
			$item = $this->dom->createElement('item');
			$item->appendChild($value->toXML());
		} else {
			if(!empty($value))
				$item = $this->dom->createElement('item',$value);
			else
				$item = $this->dom->createElement('item');
		}
		$this->data[$offset] = $value;
		$attr = $this->dom->createAttribute('key');
		$item->appendChild($attr);
		$text = $this->dom->createTextNode($offset);
		$attr->appendChild($text);
		$this->items[$offset] = $item;
		$this->el->appendChild($item);
	}
	
	public function offsetUnset($offset) {
		$this->el->removeChild($this->items[$offset]);
		unset($this->data[$offset]);
		unset($this->items[$offset]);
	}

	public function toXML() {
		return $this->el;
	}
}

Learning this was one of those time where I was actually gleeful about programming. Hopefully, this helps show how powerful PHP really is.


Jul 2 2008

Preparing SQL Queries

With web applications becoming more prevalent, and new developers showing up to fill the demand, security for web applications is increasingly important. Some applications have very special, very private data that should be only accessible to the specific user. Other, less “important” applications that don’t collect a lot of personal data, still have a need for security. With simple SQL Injection, your up and coming social media application could have it’s whole database wiped, just for kicks.

Thankfully, there’s a rather simple procedure to prevent the majority of malicious code injections by preparing your SQL queries before sending them into your database. Let’s take a look at how to do so with CodeIgniter, but before that, how to do so using only the PHP’s native PDO interface.

SQL Injections

What is an SQL Injection? It’s helpful to know what this is so we can better understand what we’re defending against. One example is retrieving all user information:

SELECT * FROM users WHERE name = '.$userName.';

In the form field where we supply $userName, if we type x’ OR ‘1′=’1, then the query gets turned into:

SELECT * FROM users WHERE name = 'x' OR '1'='1';

Name may never equal x, but using OR, with an expression that is always true (1 = 1), we just recieved every row in the table.

One other example shows how instead of stealing data, a hacker could blow away your database. Typing x’;DROP TABLE users; SELECT * FROM users WHERE name=’x

SELECT * FROM users WHERE name = 'x';DROP TABLE users; SELECT * FROM users WHRE name='x';

With a little guessing that the table might be called users, we just set a 3-part chained query. The first returns nothing, cause no name is x, the second deletes all rows from users, and the third returns nothing, cause there’s no more users, but deals with the ending single quote (’).

Yikes! Just a little guess work, and our literally composed query can be easily manipulated to destroy an application or leak information. Here’s a walkthrough case study of an anonomized injection to see how a hacker might compromise your application. Now on to protecting ourselves from malicious injection.

Native PDO Interface

The Model

Let’s make a very basic Model class that will interact with our database. Note, this doesn’t include connecting to the database. I assume you know how to do so.

<?php
class Model extends PDO
{
	public static function query($query, $args) {
		$statement = $this->prepare($query);
		foreach($args as $num => $value) {
			$argNum = $num + 1;
			if(is_null($value))
				$statement->bindValue($argNum, $value, PDO::PARAM_NULL);
			else if(is_bool($value))
				$statement->bindValue($argNum, $value, PDO::PARAM_BOOL);
			else if(is_int($value))
				$statement->bindValue($argNum, $value, PDO::PARAM_INT);
			else if(is_string($value))
				$statement->bindValue($argNum, $value, PDO::PARAM_STR);
			else
				$statement->bindValue($argNum, $value);
		}
		$statement->execute();
		return $statement->fetchAll();
	}
}?>

Cool beans. Now we can structure a query in our controller, and remembering to include this class at the top, we can make a safe query:

<?php
include('Model.class.php');
$id = 1;
$result = Model::query("SELECT * FROM table WHERE id=?",array($id);?>

What we did here was contructed the query, but left out the values and substituted in question marks. We then passed the values as a seperate parameter. So what happens?

PDO::prepare() and PDO::bindValue()

First, your query is prepared using the prepare() function extended from PDO. This prepares your statement to have the values passed into it wherever there were question marks.

Next, for each value, the data type is checked, and then bindValue() from PDO is called, and checks that it is the proper data type. At this time, it will also place the proper single quotes, insuring our quotes aren’t manipulated.

Finally, PDO::execute() sends the bound query, and PDO::fetchAll() returns the rows of data from the query. You can read up more about the PDO interface at php.net.

Soul Binding with CodeIgniter

I personally prefer to develop using CodeIgniter, and the above functionality is already written for me. Let’s see how to very simply accomplish the same in this wonderful framework.

$this->db->query("SELECT * FROM table WHERE status = ? AND author = ?", array('Published', 'Sean'));

Ah, so very simple. Well, just as simple as above. But this is the CodeIgniter way.

Other Tips

A few other things that will help prevent guesswork on your database:

  1. Make your column names with prefixs, or a personal touch to keep them out of the ordinary.
  2. Same applies to your tables, give them specialized names like “sean_blog_users” instead of simply “users”.

Employing these techniques will by no means make your application hacker-proof. There’s no such thing. Anyone can break security as long as they’re determined enough.


Page 2 of 2