ZacharyDavidSaunders / pseudoname

Pseudoname is a free, disposable email alias generating service.
https://pseudoname.io
Mozilla Public License 2.0
2 stars 0 forks source link

Need a CAPTCHA system #9

Open ZacharyDavidSaunders opened 5 years ago

ZacharyDavidSaunders commented 5 years ago

Sometime, over the course of the last 4 days, the system was brute forced and 800+ illegitimate aliases were created.

This incident did not impact system uptime and the illegitimate aliases will be purged by end of day, however this serves to highlight the need for a CAPTCHA type system.

Luckily, the attack wasn't sophisticated enough to vary the pattern of alias names, making them easy to identify (see examples below):

03a2853c-0863-45db-900e-000a6a4fc8a6 03f135e5-f43d-4fd0-9237-aa99193a0cc2 041f25d8-b8e2-4fbf-ab17-086d78751098 043e3db5-d854-446f-86b2-3da0145e93fd 045f748b-a454-4a22-889e-7e044c903415 047545b2-5cad-4cfa-9d83-8468ea181498 0481e11d-33da-4971-919e-0045d83fbf2b 048557bd-b578-4684-86a7-ed102f3a742f 04ce971a-a91f-49e0-a202-30b956ecd9dc 04fbd611-d4ce-4636-a0b8-9463a47b6ea5 051aab40-6b3b-401e-8512-ee16ef52826e 0529ef90-65e7-4132-a21e-990cdbaed701 05b4c99d-de67-4b80-8515-6a371bff1725 05bed30e-adec-41bc-a863-c5a89f742661 05fcb679-61c1-407a-9637-921570743b06 05fee2e1-50a4-4b8d-9f02-ab8d9fa8d7b9 06161794-c900-43c1-b294-fa8bebb7ae7c 06226bad-62c4-4b71-a75a-9cf17d4f8250 0632f075-a736-4ac7-9d72-03fe969f309e 06e48c70-ae45-4428-9879-d5a322a658c3 06e5f982-735e-4640-8308-a1705470f545

This is obviously a subset of the 800+ aliases, but as you can see, they follow a common structure. Given the low number of aliases created (~800 is pretty small, all things considered), I suspect that this was a proof of concept test and not a full scale attack. Regardless, a CAPTCHA seems necessary.

ZacharyDavidSaunders commented 5 years ago

Final number of illegitimate aliases was 862. ForwardMX doesn't have a batch update feature and their server got overwhelmed/DOS'd when I sent 862 individual destroy record calls. So, I had to play the "send lots of requests – but not too many" game. Admittedly, this wasn't ideal. My script got less and less efficient the more times it was ran. I could've updated the list each time it was ran and excluded the previously removed (and therefore non-existent) aliases, but I had to export the alias list by hand and continuously updating the list would have been too tedious. The ForwardMX server struggled through but eventually was able to remove all illegitimate aliases.

Here's the script I used to purge:

function run(){
  var numberPurged = 0;
  var list= []; // The exported list of fraudulent aliases. See my earlier comment for examples of these^^.

  for(var i = 0; i < list.length; i++){
    var xhttp = new XMLHttpRequest();
    xhttp.open('POST', ('https://forwardmx.io/api/alias/destroy?' +
        '&key=' + '~~REDACTED~~' +
        '&domain=' + 'pseudoname.io' +
        '&alias=' + list[i]), true);
        xhttp.send();
        numberPurged++;
  }
  console.log(numberPurged);
}

I've been looking to migrate away from ForwardMX to an open source alternative, and ForwardMX's lack of batch updating feature is yet another reason to do so.

ZacharyDavidSaunders commented 5 years ago

0c92638: I added a rudimentary CAPTCHA system to protect the service while I investigate the possibility of implementing Google's ReCAPTCHA. My system is not ideal (it likely can be bypassed via optical character recognition) and it is not intended to be a long term solution.

dcstone09 commented 5 years ago

I would recommend also adding a rate limiter to the API, possibly https://www.npmjs.com/package/express-rate-limit it could also benefit from logging requests https://www.npmjs.com/package/morgan

ZacharyDavidSaunders commented 5 years ago

I'll definitely check those out, thank you. I've been trying to find a solution that will allow the site to be excluded by rate limiting, while enforcing rate limiting on all other API users. These might work well.

I'm also probably going to add https://helmetjs.github.io/ to tighten everything a bit more.

dcstone09 commented 5 years ago

Because the requests on the site are to the API from the user's browser there isn't really any difference between the site and API users. Both should be rate limited equally.
Helmet is a good idea ✅

ZacharyDavidSaunders commented 5 years ago

For those wondering, a fix is coming for this. I've been gone on vacation (Annapolis, MD ⚓️ is lovely this time of year) and bogged down with grad school work, but I haven't forgotten.

Ideally, I'd like to roll this change into a bigger, quality of life update with changes to the API HTTP methods (e.g. /delete/ should be a DELETE, not a GET), refactoring to make the codebase ES2017 complaint, etc. This all depends on how quickly I can get through more pressing items and how frequently the system is attacked. Even with these attacks, the system continues to be operational and is servicing new (legitimate) users. With that in mind, please understand my delayed response.