When a bad day gets worse – getting hacked twice in one day
chrishateswriting.com
chrishateswriting.com
Moot left out the most sensible response to Mistake #5:
I went through a rushed 8hr rebase to remove all of our keys, certificates, cookie secrets and the like before DocumentCloud's platform was opened. Two days after, a friend asked me why I hadn't simply revoked and replaced all of our secrets to the sound of me facepalming repeatedly.
It is always much easier just to revoke and replace your secrets. Doing so should always be relatively easy for you to execute, and having a chance to practice that is also always good.
This should be "failure to use parameterised queries." The term 'unescaped' may lead some to think that simply escaping characters is sufficient.
The problem is not that this query was not escaped, the problem was that: 1) unparametrized queries are allowed in code, 2) user input is obviously not properly checked in all cases and 3) that WAF (Web Application Firewall) was not used / set up properly.
Other than that, thanks to OP for in-depth writeup - it helps to be reminded from time to time why security matters.
I would trust parameters much more (although I have used proper escaping in the past).
Without placeholders the risk is way, way too high. A single mistake can be the end of your entire application if not career.
Don't think "Oh, this is just test code, I'll fix it later" and leave a vulnerability in your application. Always write using placeholders. No exceptions.
I wonder how old the code was for "Mistake 2"? SQL injection is something most sites have patterns/frameworks to prevent, but unless the site started out with such practices...the code that was written when the site was just a fun side-project might go unchecked even as the site becomes a well-run project in its later years.
I'm not a terribly good programmer, and have been very hands-off with 4chan's code for quite some time. I still direct development and am responsible for the servers/sysadmin tasks, but there are far more talented developers out there than I. In the case of Canvas/DrawQuest, I was 100% uninvolved on the tech side.
But again, in both cases I accept full responsibility for the breaches since ultimately it's up to the project leader to ensure these things don't happen -- even if not active on the technical side.
> I wonder how old the code was for "Mistake 2"?
Very new. It was in a once-off file that we used to quickly pull stats about reported posts, which a) shouldn't have been on a domain without HTTP auth, b) should have been deleted long ago, c) shouldn't have had a bugged auth check or injection vuln to begin with.
This isn't to say that you should treat all one-off's and temporary solutions as permanenent but it is a good idea to audit them periodically.
Storing that kind of metadata about code is something I've often pondered we could do better, putting it in comments is a nasty hack, storing it away from the code means it instantly gets out of date, commit messages are not a good place to put that stuff either.
I've never come up with an elegant solution even in my head but it would be something I'd love to have for my own uses.
Someone once came into my office and asked why the email export feature had stopped working. Once they described going to test.php, I realized that about a month ago, I had migrated our version control system to a new deployment system, and hadn't included test.php, what I thought to be an insecure relic left hanging around by a predecessor.
Things that end up on a live web server are one offs much less than the people who make them think.
Codebase I once worked on, I found a /csv route that dropped the entire customer database in CSV format and /route_csv that enumerated all the routes the application had including admin and cron routes :| (denial of service by spamming the cron routes that did no access checking was the least of it).
When I checked the commit date it was 19 months ago..and in production for 17 months :|
The midden and the windmill fully hit each other that day.
Sorry about you getting hacked twice in one day though. I hope things have been better since then!
The biggest concern I have is not so much the price it would fetch (which is probably not much given recent events), but rather finding a suitable steward for the community.
Stewarding a community is a difficult job. You need more than just passion and I imagine finding one and feeling confident that they'll do a good job is quite difficult.
Can someone with the leaked credentials turn off the billing alerts?
The bad idea was not to maintain the source in a separate repo that could easily be released.
If you want to keep the checkout process simple for your developers, maybe use git subtree for the overall project.
I always tell my devs on the first day, "leaving AWS keys in a public repository is as bad as showing up drunk to work". Mainly because the last guy to leave our AWS keys in the open was drunk at work.
Or maybe just a rant on PHP and/or frameworks that make it easy to do the wrong thing, and hard or time-consuming to do the right thing.
Another alternative is to store credentials in environment variables :)
These already exist in droves, which is exactly how our Amazon credentials were found.
http://www.itnews.com.au/News/375785,aws-urges-developers-to...
http://security.stackexchange.com/questions/56911/does-anyon...
Anyone has any idea about this website I am trying to find?
Not bad in itself, sometimes all you need is a dirty script, but as other have said, they tend to stick around, a key part of our CI module is actually putting expire date on scripts, or check dates. I will receive an email telling me to check and a warning on the CI at build time. It's been great to keep our code clean while allowing us to still do things dirty when required.
Seems like far too common a mistake and something they could help fix once and for all.
So if the auth system wouldn't have let him login directly with the hash by changing his cookie, he wouldn't have been able to login as an admin.
Then the actual password is hashed, and the hash of the input password is compared to the previously stored hash, to see if it matches.
This way, you need the actual password to auth, but the actual password is stored nowhere by the app, only the hash is -- so the actual password can't be stolen by getting access to the db or the file system or anything else, because it's simply not there. But it's what you need to auth.
This is really the whole point of storing hashes rather than original passwords. Right?
Now, I guess that would mean you'd store the _actual_ password in the cookie. But that does sound risky, even if the cookies are https only. Which is why usually you store a _session id_ in the cookie, and auth the session with a single auth action, not store the password in a cookie.
When authenticating, the server needs to do a hashing step to compare against the password database. Otherwise, it isn't a hashed password database - it's a plaintext password database.
And if possible, store the session information somewhere else than your database. Redis and Memcached is a nice fit for stuff like that.
Assume nothing.
Wh... Why... Who...
How was that ever OK?
I've been on a few sites (very recently) that just stick the password right in an auth cookie, served via HTTP no less. Luckily they're sweet enough to base64 encode it for extra security.
I would have expected a site like 4chan, the source of all sorts of script kiddie idiocy, would know better by this time than to stick a password, even hashed, in a cookie.
But sometimes you piss off the HN bees nest, and downvotes come streaming in. Reminds me of Reddit.
If this was anyone else it wouldn't been something more along the lines of "this is why you should leave security to the experts" or "seriously, just spending an extra day reading about the best practices would've solved the whole thing"
moot has a reality distortion field on HN
No, just look at your comment. You quote the OP saying it was a boneheaded move to do X. Then you use feigned surprise ('cause really, who could be literally be so surprised that they type in half-words?) to express that it was a boneheaded move to do X.
Why bother to write that out, beyond "I thought this"? Why should anyone want to read it?
That's a despicable thing to say. No one deserves to have bad things thrust upon them.