$ cat post/the-config-was-wrong-/-a-port-scan-echoes-back-now-/-i-kept-the-bash-script.md

the config was wrong / a port scan echoes back now / I kept the bash script


December 27, 2004 - Debugging the Web


I’m writing this from my home office on Christmas Eve. The lights are dimmed for a movie marathon with the kids, but my head is still in the lab. A few months ago, I was handed an open-source PHP app that’s been humming along nicely under Apache and MySQL since 2002. Now it’s having trouble at scale, and I’m in the middle of trying to figure out why.

The Setup

It’s a typical LAMP stack setup—PHP 4.3.10, MySQL 5.0, and Apache 2.0.6 on CentOS 4.3. The application is a social networking site with a decent number of users. Over the last few months, we’ve seen steady growth in hits per day. On good days, it handles around 50k page views; on bad days, it’s more like 120k.

The Problem

Today, things went south pretty quickly. Traffic was going up, but instead of our usual smooth traffic pattern, there were massive spikes every few minutes. Our monitoring tools showed that Apache was hitting its limits, and we started seeing a lot of 503 errors from MySQL.

I opened the application code in vim, hoping to find a simple mistake, but it felt like I was dealing with a complex web of dependencies and poorly named variables. It’s a mess, but one thing stood out: a query that fetched user data using PHP’s mysql_query function without any proper sanitization or error handling.

Debugging

I started by firing up strace to see what MySQL was doing under the hood when it failed. It didn’t take long to find the culprit:

SELECT * FROM users WHERE username = '$username';

The $username variable wasn’t being sanitized, and some user input was causing a SQL injection attack that was overwhelming our database server.

The Fix

I rewrote the query using prepared statements in PHP. It wasn’t pretty, but it worked:

$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param('s', $_GET['username']);
$stmt->execute();

After deploying this change, I watched as the load on MySQL dropped dramatically and the 503 errors disappeared. The site was back to handling its usual traffic pattern.

The Learning Experience

This experience brought home a few lessons for me:

  1. Sanitize Your Inputs: Always sanitize user inputs in your queries or use parameterized queries.
  2. Monitoring is Key: Even with good monitoring tools, you need to understand the underlying mechanics of your system to diagnose problems effectively.
  3. Keep Learning: The technologies and best practices change rapidly, but staying on top of them can save a lot of headaches.

As I hit Save in my editor, feeling relieved that the issue was resolved, I realized that open-source tools like PHP, MySQL, and Apache had been the backbone of so many applications. In 2004, they were still maturing, but it was clear to me that they would be foundational for the web development world to come.

Today, as I wrap up my debugging session, I look forward to a bit of Christmas fun with the kids. But this experience reminds me that even in a time of rapid change and excitement like 2004, the core principles of good engineering—like proper input handling and robust monitoring—never go out of style.


Merry Christmas from the server room!