DEV Community

Boots
Boots

Posted on

Baby's First Denial of Service

Today, while waiting for a build to finish, I ended up on a developer's personal website. It had this super cute little widget in the bottom left.

Screen grab of fist bump icon thingy

A little icon of two fists about to bump. D'awh.

And it had a counter!! The counter counts how many times the fist bump has been clicked. Kinda reminded me of those page-view counters on Geocities sites.

At any rate, I was curious how the counter was implemented.

I cracked open dev tools and saw that each click sent a GET request to /api/bro.php?add=1.

An attempt to add ONE-THOUSAND BUMPS with ?add=1000 did not work. There was still a 200 response, but the counter didn't jump up 1000 bumps. Shucks.

// BTW I added the header to be consistent with the site owner's api call
fetch('/api/bro.php?add=1000', {
  headers: { 'x-requested-with': 'XMLHttpRequest' }
}) 
Enter fullscreen mode Exit fullscreen mode

Poking around more, I noticed that the page would limit me to 10 fist-bumps through the UI, but refreshing the page would give me 10 more bumps.

Unlimited bumps!!!

His site was not setting any sort of tracking-related stuff (no cookies, no identifiers in local storage, etc), so I assumed he wouldn't have a way to rate-limit a large number of API requests for those sweet, sweet bro-knucks.

That's when I got a little too... spirited.

In my defense, I really wanted one-thousand more bumps. But I wanted to be nice to his api.

So, I spaced out one-thousand requests, trying to average about 60 requests a second:

Array.from({ length: 1000 }).forEach((meh, i) => {
  setTimeout(() => {
    fetch('/api/bro.php?add=1', { headers: { ['x-requested-with']: 'XMLHttpRequest' } })      
  }, i * 17)
});
Enter fullscreen mode Exit fullscreen mode

Within a few seconds, the requests started failing.

Then, I tried reloading the page.

It was down.

I oscillated between laughing a lot and feeling bad for this guy.

After another minute or two, the site was still down. I assumed it had not gracefully restarted. So, I found his contact info on Dribbble and sent him an email apology.

He was not mean, but also did not seem to be amused.

His site was back up and running in 10 minutes or so, but he hasn't responded to me since then. I don't wanna push it, you know?

If I can confirm with him that he has a fix for this, I'll post a link to his website. (It's really really really good!)

That's least I could do, right?

Top comments (0)