In 2015, Egor Homakov discovered he could get free coffee at Starbucks by just misusing their website. Reading his post reminded me why it's important for developers to know about common weaknesses. Here's the one that Starbucks developers made, and I hope you'll know to avoid.
An Insecure Snippet
The problematic code in Starbucks' implementation was in a function that transferred money between two gift cards. I don't know which language Starbuck's site is written in, or how their code looks like, but I can guess if it was ruby it would have looked something like this:
def transfer amount = params[:amount].to_f raise 'Bad Transfer Amount' if amount < 0 card_a = Card.find(params[:card_a]) raise 'Insufficient Funds' if card_a.amount < amount card_a.amount -= amount card_a.save card_b = Card.find(params[:card_b]) card_b.amount += amount card_b.save redirect_to '/' end
The problem is manifested when we try to access the function from two browser windows at the same time. Assuming a prefork server, the server would use a different process per request, and so will try simultaneously to execute the function. When that happens, both processes will have finished checking the money in the first card before transferring it to the second card.
This means if we try to trasnfer money from a card with 5$ to another empty card using 2 browser windows at the exact same time, we may be able to transfer twice, and end with -5$ in the first card and 10$ on the second.
Homakov used a script to simulate transfer call from two different windows, and the rest is history.
Common Weakness Enumeration
But isn't that the point of hackers? to break into systems, and to think of all the little things the original developers did not consider? Yes, But. You see many security related mistakes we do (such as the one described above) are already known to mankind for a long time. We even have them written down.
In CWE Repository you'll find 705 weaknesses that software may suffer from. 705 is not that much. Read 10 minutes of CWEs a day and you'll be done within a year.
And what will you find there? Well CWE 362 of course is the weakness described above. Its full name is: Concurrent Execution using Shared Resource with Improper Synchronization. The page includes a code example of the error, explains what can go wrong and even how to fix it using locks.
And the best thing is, unlike software vulnerabilities in specific libraries, those weaknesses never grow old. Race conditions, Buffer overflows, Code injections - these are concepts that are over two decades old, and they're not going anywhere. Reading about them is one of the best career inverstment one can make.