Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rate limit signups #2280

Merged
merged 10 commits into from
Aug 5, 2024
Merged

rate limit signups #2280

merged 10 commits into from
Aug 5, 2024

Conversation

taoeffect
Copy link
Member

Thanks so much to @SGrondin's amazing Bottleneck library we can now rate limit signups easily!

Copy link

socket-security bot commented Aug 3, 2024

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/bottleneck@2.19.5 eval 0 629 kB sgrondin

View full report↗︎

Copy link

cypress bot commented Aug 3, 2024



Test summary

112 0 10 0


Run details

Project group-income
Status Passed
Commit 558caf2 ℹ️
Started Aug 5, 2024 5:59 PM
Ended Aug 5, 2024 6:09 PM
Duration 10:43 💡
OS Linux Ubuntu - 20.04
Browser Electron 89

View run in Cypress Cloud ➡️


This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Cloud

SebinSong
SebinSong previously approved these changes Aug 4, 2024
Copy link
Member

@corrideat corrideat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment for concrete changes. In addition, I have the following comment:

I think that the documentation (which now doesn't exist, so next best thing is adding a comment somewhere in this file) should explain the limitations of this approach:

  1. Limiting by IP addresses is maybe the simplest way of doing rate-limiting, but it has serious limitations:
    a. Because of CGNAT, multiple users (potentially millions, but more likely a few hundred) can be sharing a single IP address. This makes this PR break things for legitimate users (if they're all using Group Income).
    b. On the flip side, it doesn't really stop attacks, because attackers that are rate-limited can easily get a new IP address.
    c. Because of the previous point, this PR can be used to cause a DoS by filling up the list of IP addresses.
    d. At the very least, the key used should be the /64 block for IPv6 addresses. Not doing this makes this PR pointless and exposes the server to very easy DoS.
  2. Because this state is local to the server, it doesn't work under load balancing scenarios.

backend/routes.js Show resolved Hide resolved
backend/routes.js Show resolved Hide resolved
backend/routes.js Outdated Show resolved Hide resolved
// rate limit signups in production
if (process.env.NODE_ENV === 'production') {
try {
await limiterPerMinute.key(ip).schedule(() => Promise.resolve())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment about why ip cannot be used as a key if the address is IPv6.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to possibly deal with in the future. On a call Ricardo asked an AI for the code to get this ipv6 key, and this is what he said the AI said:

function getFirstIPv6_64(ipv6Address) {
  // Expand the address if it uses compressed notation
  const expandedAddress = expandIPv6Address(ipv6Address);
  
  // Split the address into its 8 groups
  const groups = expandedAddress.split(':');
  
  // Take the first 4 groups (64 bits) and join them
  return groups.slice(0, 4).join(':');
}

function expandIPv6Address(address) {
  // If the address doesn't contain ::, it's already expanded
  if (!address.includes('::')) {
    return address;
  }

  // Split the address into parts before and after ::
  const [left, right] = address.split('::');
  const leftGroups = left ? left.split(':') : [];
  const rightGroups = right ? right.split(':') : [];

  // Calculate how many zero groups we need to insert
  const missingGroups = 8 - leftGroups.length - rightGroups.length;

  // Create the expanded address
  return [
    ...leftGroups,
    ...Array(missingGroups).fill('0000'),
    ...rightGroups
  ].map(group => group.padStart(4, '0')).join(':');

corrideat
corrideat previously approved these changes Aug 5, 2024
@taoeffect taoeffect merged commit 72ad34e into master Aug 5, 2024
4 checks passed
@taoeffect taoeffect deleted the rate-limiting branch August 5, 2024 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants