summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeiMei <30769358+mei23@users.noreply.github.com>2022-05-31 17:44:22 +0900
committerGitHub <noreply@github.com>2022-05-31 17:44:22 +0900
commitc05723ca6ad4f17b823662e83ed8b442fe10626a (patch)
treef38e26f44e7ef714d37e196a319d7129a0391962
parentchore(meta): label Pull Requests containing tests (#8768) (diff)
downloadmisskey-c05723ca6ad4f17b823662e83ed8b442fe10626a.tar.gz
misskey-c05723ca6ad4f17b823662e83ed8b442fe10626a.tar.bz2
misskey-c05723ca6ad4f17b823662e83ed8b442fe10626a.zip
Fix IP address rate limit (#8758)
* Fix IP address rate limit * CHANGELOG * Tune getIpHash
-rw-r--r--CHANGELOG.md2
-rw-r--r--packages/backend/src/misc/get-ip-hash.ts9
-rw-r--r--packages/backend/src/server/api/call.ts11
-rw-r--r--packages/backend/src/server/api/private/signin.ts3
4 files changed, 15 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b086ddba9..cfcf52ce92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,7 +26,7 @@ You should also include the user name that made the change.
Your own theme color may be unset if it was in an invalid format.
Admins should check their instance settings if in doubt.
- Perform port diagnosis at startup only when Listen fails @mei23
-- Rate limiting is now also usable for non-authenticated users. @Johann150
+- Rate limiting is now also usable for non-authenticated users. @Johann150 @mei23
Admins should make sure the reverse proxy sets the `X-Forwarded-For` header to the original address.
### Bugfixes
diff --git a/packages/backend/src/misc/get-ip-hash.ts b/packages/backend/src/misc/get-ip-hash.ts
new file mode 100644
index 0000000000..379325bb13
--- /dev/null
+++ b/packages/backend/src/misc/get-ip-hash.ts
@@ -0,0 +1,9 @@
+import IPCIDR from 'ip-cidr';
+
+export function getIpHash(ip: string) {
+ // because a single person may control many IPv6 addresses,
+ // only a /64 subnet prefix of any IP will be taken into account.
+ // (this means for IPv4 the entire address is used)
+ const prefix = IPCIDR.createAddress(ip).mask(64);
+ return 'ip-' + BigInt('0b' + prefix).toString(36);
+}
diff --git a/packages/backend/src/server/api/call.ts b/packages/backend/src/server/api/call.ts
index fbe25e1732..cd3e0abc06 100644
--- a/packages/backend/src/server/api/call.ts
+++ b/packages/backend/src/server/api/call.ts
@@ -6,7 +6,7 @@ import endpoints, { IEndpointMeta } from './endpoints.js';
import { ApiError } from './error.js';
import { apiLogger } from './logger.js';
import { AccessToken } from '@/models/entities/access-token.js';
-import IPCIDR from 'ip-cidr';
+import { getIpHash } from '@/misc/get-ip-hash.js';
const accessDenied = {
message: 'Access denied.',
@@ -33,18 +33,13 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
throw new ApiError(accessDenied);
}
- if (ep.meta.requireCredential && ep.meta.limit && !isModerator) {
+ if (ep.meta.limit && !isModerator) {
// koa will automatically load the `X-Forwarded-For` header if `proxy: true` is configured in the app.
let limitActor: string;
if (user) {
limitActor = user.id;
} else {
- // because a single person may control many IPv6 addresses,
- // only a /64 subnet prefix of any IP will be taken into account.
- // (this means for IPv4 the entire address is used)
- const ip = IPCIDR.createAddress(ctx.ip).mask(64);
-
- limitActor = 'ip-' + parseInt(ip, 2).toString(36);
+ limitActor = getIpHash(ctx!.ip);
}
const limit = Object.assign({}, ep.meta.limit);
diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts
index b304550e29..79b31764fd 100644
--- a/packages/backend/src/server/api/private/signin.ts
+++ b/packages/backend/src/server/api/private/signin.ts
@@ -10,6 +10,7 @@ import { verifyLogin, hash } from '../2fa.js';
import { randomBytes } from 'node:crypto';
import { IsNull } from 'typeorm';
import { limiter } from '../limiter.js';
+import { getIpHash } from '@/misc/get-ip-hash.js';
export default async (ctx: Koa.Context) => {
ctx.set('Access-Control-Allow-Origin', config.url);
@@ -27,7 +28,7 @@ export default async (ctx: Koa.Context) => {
try {
// not more than 1 attempt per second and not more than 10 attempts per hour
- await limiter({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, ctx.ip);
+ await limiter({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(ctx.ip));
} catch (err) {
ctx.status = 429;
ctx.body = {