|« All In The Config||Unattended Consequences »|
Last month, rachetingDateObject showed us something a little different: a curious perversions that was actually created by the submitter. This time, Brian F decided to share his story.
Do you have any confessions you'd like to make? Send them on in.
About a decade ago, I landed my first grown-up job at a small IT shop. Not too long after I started, the company landed a project to develop an ecommerce website for a range of slimming products. Being that web development wasn't the company's specialist, they would subcontract these types of jobs to real web developers at our hosting company, and have folks like me coordinate the project work.
Instead, I saw an opportunity. You see, at this stage in my career, not only had I managed to copy a wordsearch program from Amstrad Action onto my CPC 464, but I knew how to control the Windows Media Player COM object from Delphi. Therefore, I was fully qualified to work in the exciting new world of web programming, and persuaded my boss that I was up to the task. Enticed by all the billable hours it'd bring in, he was happy to let me give it a shot and promoted me from general IT monkey to web programmer.
The project called for a shopping cart and, after reading a 30 minute "getting started" guide on SQL, I created my first database. I figured a Shopping Cart is a logical unit of data, and as such deserving of its own table. And since each Shopper had their own shopping cart, they should also have their own Shopping Cart table.
Easy enough. The homepage of the website would create a new table for each customer with a name like CART14. Of course, I had to figure out what the next table name should be, and the most logical way to do this was to simply try to
SELECT * from each "CART" table (starting at CART1) until it threw a "table not found" error. Of course, if anyone started on a page other than the home page, they would get an error. But hey, that was their fault for not starting at the right place.
I realized that, after a few visitors, this might get a little slow, so the next stage was to create a table that tracked the last basket number. With that information on hand, I could simply run a cleanup script to delete old data. There were a lot of ways that I could have run the clean up script, but the most logical was clearly when the home page was loaded. The script was simple: it would delete baskets that were less than 100 below the current cart id.
The next big challenge was figuring out which shopping cart belonged to which customer after they loaded the home page. Cookies hadn't been invented yet (well, they had been, but I didn't know about them, which means they didn't exist), so I figured URL embedding a "cart id" was the way to go. It was an ID that tracked their Session, if you will.
Then I realized this lead to another problem: incremental Session IDs could be a security problem. I had seen a "GUID" before, and read that it was basically guaranteed to be unique across the universe. So, I decided to use them instead. Well not real GUIDs... more something I threw together using the Random function. Not surprisingly, this lead to a few situations where one user would strangely get items in their shopping cart they didn't select... but I'm sure that had more to do with "clogged internet tubes" and corrupt bits than anything else.
After thinking about security even further I realized that even using a "GUID" wasn’t secure enough. I mean, anybody could just memorize the "GUID" from the URL if they saw it on screen, and then retype it back into the browser to see another person's shopping cart. Therefore, for security purposes, I decided that this id should change after every click.
Each page would take the raw id, generate a new hash code, hash the raw id and use the hashed value as the cart id. It would also take the last hash from the URL string, load from the session the previously generated hash and compare the two. One consequence of this was that the Back Button on the browser didn't work, but I solved that by simply posting a giant warning that proclaimed that it was a "bad practice" to use the back button, anyway.
For all its failings, the site did just about work, and the client was actually happy. Of course, they never really got any traffic or users… mostly because they went out of business a month later. Something about selling FDA unapproved, slightly-dodgy "medicine".
After a few more years a total cowboy programmer, I have since reformed my ways. Now I spend my time trying to help others in my organization steer clear of the mistakes I have made (though some people are determined to learn the hard way).
And for the record, the Bad Programming Karma I unleashed on the world has been paid back to me a thousand times over. I always have to remember: when judging others work, I shouldn't be the one to throw the first stone.
|« All In The Config||Unattended Consequences »|