Catching up on some reading, I finally got a chance to read Ted Neward's article "Pragmatic Architecture: Security". It's very good. (Actually, the whole series is pretty good, and I recommend them all. At least as of February 2008... I make no assertions about future quality!)
Ted nails it. I agree with all of the principles he identifies, and I particularly like his advice to "fail securely".
I would add one more, though: Be visible.
After any breach, the three worst questions are always:
- How long has this been happening?
- How much have we lost?
- Why didn't we know about it sooner?
The answers are always, respectively, "Far too long", "We have no idea", and "We didn't expect that exploit". To which the only possible response is, "Well, duh, if you'd expected it, you would have closed the vulnerability."
Successful exploits are always successful because they stay hidden. Are you sure that nobody's in your systems right now, leaching data, stealing credit card numbers, or stealing products? Of course not. For a vivid case in point, google "Kerviel Societe Generale".
While you cannot prove a negative, you can improve your odds of detecting nefarious activity by making sure that everything interesting is logged. (And by "interesting", I mean "potentially valuable".)
There are some pretty spiffy event correlation tools out there these days. They can monitor logs across hundreds of servers and network devices, extracting patterns of anomalous behavior. But, they only work if your application exposes data that could indicate a breach.
For example, you might not be able to log every login attempt, but you probably should log every admin login attempt.
Or, you might consider logging every price change. (I shudder to think about collusion between a merchant with pricing control and an outside buyer. Imagine a 10-minute long sale on laptops: 90% off for 10 minutes only.)
If your internal web service listens on a port, then it should only accept connections from known sources. Whether you enforce that through IPTables, a hardware firewall, or inside the application itself, make sure you're logging refused connections.
Then, of course, once you're logging the data, make sure someone's monitoring it and keeping pattern and signature definitions up to date!