Disconnect mysql_connect

As PHP 5.5 closer to public beta and therefore public release it is time to get away from using the MySQL API to connect and interact to MySQL databases. The original MySQL API has been around since before the days of PHP 3 and quickly became the most popular API (due in no small part to it being the only API) used to interact with MySQL databases. While the original MySQL API had it’s time in the sun, it is time to put the extension out to pasture. In the upcoming PHP 5.5 release the original MySQL API will be depreciated.

At this point you are probably asking yourself, “well, if the MySQL API is depreciated, how am I supposed to connect to MySQL database?” PHP has you covered, in PHP 5.0 two new APIs have been introduced. These APIs are the mysqli API and the PDO API. Both of these new APIs are included with the standard PHP builds and are easy to learn.

The reason to step away from the original MySQL API is not only because of its impending depreciation. The original MySQL API is also much less secure than it’s alternatives. The API lacks the ability to use prepared statements which allows for easier access to the database by malicious users by way of SQL injection.

With this bit of knowledge I hope that you take the steps required to disconnect from the original MySQL APIs in PHP and move to future-ready, more secure, mysqli API and/or PDO API for future development.

Obscurity IS NOT Security

I work with a fairly large piece of software day in and day out, which will remain nameless for the time being. This software is used in medical offices across the United States and beyond, and has an annual conference in Las Vegas for it’s users to mingle and learn some tricks and tips for the software. The software allows its users, based on permission levels, to access to patient information, prescription prescribing, and other sensitive information.

To access the software the user must first enter their username and password. Unfortunately, that is about where the security mechanisms fall apart. The password is limited to 12 characters, and is case insensitive. When was the last time you had a case insensitive password? Exactly, likely never, because that is very insecure.

Continuing to dig into the security in use, I looked to the underlying SQL Server database, which contains all of the user accounts for the software. When viewing the user table I noticed that there were similarities between most of the password hashes it stored. An example of the hash is F3d2427323a202034686f736973616 which is the hash for password All of the hashed started with F and many of the hashes end with 686f736973616. This peaked my interest and had me thinking that the hash maybe had a salt added to the end of it, but, since the end of each hash didn’t all match that couldn’t have been the case.

It turns out these password hashes aren’t really hashes at all, but rather a very easily reversed algorithm based on BITWISE Comparisons. The steps to create a valid hash are as follows:

Convert the password to lowercase.
Pad the password to 12 characters by appending spaces.
XOR the encoding of the password with the encoding of: metamorphosi
XOR each resulting byte with 0x20 (the ASCII encoding of a space).
Convert the result into hexadecimal.

Using this knowledge I reversed the process using some quick PHP to dump the plain text of all the passwords stored in the database.

The results were shocking. Mainly in the fact that it was so simple to generate a list of all of the passwords, that restrict access to such a large amount of sensitive data. With the ability to convert the hash to plain text I set forth attempting to set passwords from PHP as well. At first I was finding that my hashes I was generating were matching up, but the log in attempts would fail. I couldn’t figure out what was going wrong, so I took to the SQL, I dumped the value for the passwords to their binary representation.

After looking at the output it showed that there was an un-shown character stored at the beginning of the password, specifically a horizontal tab. I reworked my code a little to account for the tab and was successful in creating a new password.

This exercise was great to point out a security flaw in a piece of software that should have maximum security. The worst part about the flaw is that the designers opted to ignore convention by using a homegrown hashing algorithm instead of using a known and accepted one way hashing algorithm like SHA-1,  MD4, or one of the many others available. I have contacted the company that develops the software, informing them that their security is far from up to par, and hopefully prod them a bit to step up their security in future releases of the software. In the event of a reply to my contact attempt I will update this post. 

Update
I have received a phone call from the software vendor in question. After being grilled as to my place of employment where I interact with their software I was told that a fix is in the works. This phone call took place on March 26, 2013, a full month after I initially contacted them about the issue. To this point, there have been no updates made to enhance the security practices of the software.

Your Pass to Passbook

Jeremy Curcio

Speaking about Passbook

Tonight I gave a talk about Passbook the monthly meetup of Baltimore Cocoa, a local group dedicated to Apple iOS and OS X developers. The talk was titled “Your Pass to Passbook” and explained what Passbook was and what it does. I explained what passes are, how they are used, and how to make them.

In case you were unable to attend, or even if you just want to look at the slides again I have included them below for your viewing and learning pleasure.

A Rant on Congruency

Yesterday I received a phone call from my supervisor informing me of an bug he found in one of the applications that I was left by a former developer. I was told the name of the application and where it happened. No mention of the error(s) noted, but that is a story for another day. So with this bug report I started to dig in to see what was happening. It turns out that using an apostrophe in a user provided field was causing issues. The errors were pointing to the SQL Server not accepting the input provided. I then took a look at the code to see how we were working with the submitted form data. I found we were ‘sanitizing’ data using the following code.

1
2
3
$Comments=str_replace("\'","''",$Comments);
$Comments=str_replace("\\\"","\"",$Comments);
$Comments=str_replace("\\\\","\\",$Comments);

So, we were looking for \', \", and \\ in the submitted data. Since the users aren’t escaping their own data (nor should they) these replaces were never happening.

Now armed with the knowledge of what was wrong, I set off to fix it. Since the rest of the code was a complete mess, much like the sample provided above, and I was on a “make this work now” deadline I went forth and just fixed the escaping of special SQL characters for now, and will go back to refactor when things slow down a little bit. The above block of code was changed to this:

1
$Comments=str_replace("'","''",$Comments);

I pushed the change to the development server and went through the reproduction steps to ensure that the change functioned as expected before moving them to the production environment. This is where things went from an eye roll to a face palm. Our development and production servers do not match up at all. The production server runs IIS 7 with PHP 5.4.0, the development server runs IIS 6.5 with PHP 5.0.4, and my local environment runs a local instance of IIS 6.5 with PHP 5.4. Upon testing on the development server things still weren’t working quite right. The data wasn’t being escaped as expected.

After checking the PHP Manual to ensure that str_replace() worked the same in 5.0.4 as it did in 5.4.0, echoing out the data submitted, and running about a half dozen different input tests, I figured it out. The development server has magic_quotes turned on in the php.ini, even though it was turned off (as it should be) on the production server.

When I started in my current position I was told that the php.ini files on the production and development servers were tuned for each server and to not touch them. I have scanned through each to see how they were ‘tuned’ (Spoiler: They aren’t) but must have missed the magic_quote being on, probably because it was appended to the end of the file, especially because they were off in their normal location in the file.

; Magic quotes for incoming GET/POST/Cookie data.
; magic_quotes_gpc = Off

I then turned magic_quotes off, by touching the php.ini I was told to not touch, and reran my fix. The SQL statement ran as expected and the new data was inserted into the database.

So the moral of my story for all the System Administrators out there: Please keep everything in sync between your environments. Server versions, PHP versions, configuration files, and anything else that is on both servers. If they do not match, then your developers will be tearing their hair out trying to figure out why code that worked on Development doesn’t work on Production and vice-versa, which then causes two versions of the code in the code base, one for each environment.

Shorten URLs

Ever have to shorten a URL but didn’t know the best way to do so without the possibility of duplicates being stored in your database? Have no fear, I have the perfect workaround for this very problem. Using two very simple functions we are able to convert a number, presumably the ID of the link we are shortening, to a short alpha-numeric ([a-zA-Z0-9]) string and back.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	function base62_encode($val, $base=62, $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
		$str = '';
		do {
			$i = $val % $base;
			$str = $chars[$i] . $str;
			$val = ($val - $i) / $base;
		} while($val > 0);
		return $str;
	}
 
	function base62_decode($str, $base=62, $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
		$len = strlen($str);
		$val = 0;
		$arr = array_flip(str_split($chars));
		for($i = 0; $i < $len; ++$i) {
			$val += $arr[$str[$i]] * pow($base, $len-$i-1);
		}
		return $val;
	}

This will generate the shortest possible unique, URL safe, string for the given value. Using these two functions you can create millions of unique, short, URL’s quickly.

Checking for a String in an Array

PHP has a pair of functions built in that allows you to find if a substring exists within a string. These functions are strpos(), which is case sensitive, and stripos(), which is case insensitive. Both of these functions return the position of the last occurrence of the needle in the haystack, or FALSE if the needle wasn’t found.

The problem comes when you need to find if a substring exists in an array of string. In a recent project I was working on I needed to find if the word “Diagnostic” appeared in an array of strings. So I wrote a function that loops through each of the strings in the haystack for the supplied needle. int strinarray (array $haystack, string $needle). The function will return either the array index if the string is found, or FALSE is the string isn’t found.

1
2
3
4
5
6
7
8
9
function strinarray($haystack, $needle) {
	$i = 0;
	foreach ($haystack as $value) {
		$result = stripos($value,$needle);
		if ($result !== FALSE) return $i;
		$i++;
	}
	return FALSE;
}

Using this function is very simple, you need only supply the array you want to search and the string that you want to find. See the example below for a simple usage.

1
2
3
4
5
//Create the array to search through.
$array = array("abc","def","hij","123","456","789");
//Use strinarray to see if "hi" is in the array, and if 
//it is found, echo the array index in which it was found.
if (strinarray($array,"hi")) echo strinarray($array,"hi"); // 3

This function has come in handy multiple times since I wrote it and I hope that by sharing it it will help someone else as well.

PHP Barcode

A couple weeks back I was working on a project that required generation of UPC-A barcode. After a quick search I found that there weren’t many options out there to create barcodes and insert them directly where I wanted to. I decided to research how a barcode works and make my own.

UPC-A barcodes consist of a total of 12 digits, with the 12th digit being a check-sum to confirm the validity of the barcode to the scanner. Each digit (0-9) has a unique set of lines that will always be seven pieces wide and contain two bars and two spaces. The barcodes also have a standard beginning pattern, ending pattern, and middle pattern of space, bar, space, bar, space. The digits in the 2nd half of the barcode have their line pattern reversed from their standard orientation.

With this knowledge I set to work to generate the barcode using PHP. Below is the function that I came up with. Please feel free to use it within your projects, or to modify it as you see fit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
 * PHP Barcode
 * Written by Jeremy Curcio
 * This work is licensed under a Creative Commons 
 * Attribution-ShareAlike 3.0 Unported License.
 */
 
function upcaBarcode($numbers, $width, $height) {
 
	//Set output to be an image.
	header("Content-type:image/png");
	//Create image object and colors and define width of bars.
	if ($width < 190) $width = 190; 
	$barWidth = $width/95;
	$img=imagecreate($width, $height);
	$black_color=imagecolorallocate($img,0,0,0);
	$white_color=imagecolorallocate($img,255,255,255);
	//Set the background to white.
	imagefilledrectangle($img, 0, 0, 200, 60, $white_color);
	//Check to make sure $numbers is 12 characters long.
	$check = (intval(substr($numbers,0,1))*3)+intval(substr($numbers,1,1))+(intval(substr($numbers,2,1))*3)+intval(substr($numbers,3,1))+(intval(substr($numbers,4,1))*3)+intval(substr($numbers,5,1))+(intval(substr($numbers,6,1))*3)+intval(substr($numbers,7,1))+(intval(substr($numbers,8,1))*3)+intval(substr($numbers,9,1))+(intval(substr($numbers,10,1))*3);
	if ($check != 0) $check = 10-substr($check,strlen($check)-1,1);
	$numbers = $numbers.$check;
	$c = $numbers;
	if ((strlen($numbers) == 12) &amp;&amp; (is_numeric($numbers))) {
		//Append start and finish characters to the barcode.
		$numbers = "z".$numbers."z";
		//Find the middle of the string, break the string in half
		//then add the middle separater to the barcode.
		$half = (int) ( (strlen($numbers) / 2) );
		$left = substr($numbers, 0, $half);
		$right = substr($numbers, $half);
		$middle = "sbsbs";
		$numbers = $left.$middle;
		$numbers2 = $right;
		//Replace the left half's numbers with the correct pattern.
		$numbers = str_replace("z","sbsbs",$numbers);
		$numbers = str_replace("0","sssbbsb",$numbers);
		$numbers = str_replace("1","ssbbssb",$numbers);
		$numbers = str_replace("2","ssbssbb",$numbers);
		$numbers = str_replace("3","sbbbbsb",$numbers);
		$numbers = str_replace("4","sbsssbb",$numbers);
		$numbers = str_replace("5","sbbsssb",$numbers);
		$numbers = str_replace("6","sbsbbbb",$numbers);
		$numbers = str_replace("7","sbbbsbb",$numbers);
		$numbers = str_replace("8","sbbsbbb",$numbers);
		$numbers = str_replace("9","sssbsbb",$numbers);
		//Replace the right half's numbers with the correct pattern.
		$numbers2 = str_replace("0","bbbssbs",$numbers2);
		$numbers2 = str_replace("1","bbssbbs",$numbers2);
		$numbers2 = str_replace("2","bbsbbss",$numbers2);
		$numbers2 = str_replace("3","bssssbs",$numbers2);
		$numbers2 = str_replace("4","bsbbbss",$numbers2);
		$numbers2 = str_replace("5","bssbbbs",$numbers2);
		$numbers2 = str_replace("6","bsbssss",$numbers2);
		$numbers2 = str_replace("7","bsssbss",$numbers2);
		$numbers2 = str_replace("8","bssbsss",$numbers2);
		$numbers2 = str_replace("9","bbbsbss",$numbers2);
		$numbers2 = str_replace("z","sbsbs",$numbers2);
		//Create one string will all of the encodings.
		$finalEncoding = $numbers.$numbers2;
		//Add the bars and spaces to the image.
		for ($i = 0; $i < strlen($finalEncoding); $i++) {
			if (strcmp($finalEncoding[$i],"b") == 0) imagefilledrectangle($img, $i*$barWidth, 0, ($i*$barWidth)+$barWidth, $height, $black_color);
			else imagefilledrectangle($img, $i*$barWidth, 0, ($i*$barWidth)+$barWidth, $height, $white_color);
		}
	}
	//If $numbers isn't 12 characters wide produce error image.
	else {
		imagestring($img, 4, 0, 12, "Error: Input must be 12", $black_color);
		imagestring($img, 4, 0, 24, "characters (0-9) long.", $black_color);
	}
	//Return completed image.;
	return (imagepng($img));
}

To use this function you simply have to provide the number you want to be converted into a barcode, the width and the height that you want the barcode to be. Note: You need to supply an 11 digit number to be converted to a barcode, as the 12th digit check-sum will be generated for you. An example of using this is shown below.

1
2
3
4
$code = '10261104092'
$width = 200;
$height = 50;
upcaBarcode($code, $width, $height);
Barcode

Sample Output

Welcome

Hello and thank you for checking out my personal blog. I will be using this little corner of the Internet to post about things that I think are worth sharing. I will be mainly posting code snippets that I’ve put together. I’ll also use this blog to document progress of projects that I am working on. Don’t worry though, it won’t be all code related posts, I will occasionally post about things I found that I think are either interesting or humorous.

I hope you check back often and that if you learn something from a post here that you pay it forward.