Add basic rate limiting to login endpoint

Closes #1320
This commit is contained in:
Anmol Sethi 2020-04-27 08:41:52 -04:00
parent f21ba53609
commit 5accf3fe5f
No known key found for this signature in database
GPG Key ID: 8CEF1878FF10ADEB
5 changed files with 30 additions and 0 deletions

View File

@ -21,3 +21,4 @@ extends:
rules:
# For overloads.
no-dupe-class-members: off
"@typescript-eslint/no-use-before-define": off

View File

@ -52,6 +52,8 @@ randomly generated password so you can use that. You can set the `PASSWORD` envi
to use your own instead. If you want to handle authentication yourself, use `--auth none`
to disable password authentication.
**note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour.
If you want to use external authentication you should handle this with a reverse
proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy).

View File

@ -53,6 +53,7 @@
"fs-extra": "^8.1.0",
"http-proxy": "^1.18.0",
"httpolyglot": "^0.1.2",
"limiter": "^1.1.5",
"node-pty": "^0.9.0",
"pem": "^1.14.2",
"safe-compare": "^1.1.4",

View File

@ -1,4 +1,5 @@
import * as http from "http"
import * as limiter from "limiter"
import * as querystring from "querystring"
import { HttpCode, HttpError } from "../../common/http"
import { AuthType, HttpProvider, HttpResponse, Route } from "../http"
@ -48,6 +49,8 @@ export class LoginHttpProvider extends HttpProvider {
return this.replaceTemplates(route, response)
}
private readonly limiter = new RateLimiter()
/**
* Try logging in. On failure, show the login page with an error.
*/
@ -59,6 +62,10 @@ export class LoginHttpProvider extends HttpProvider {
}
try {
if (!this.limiter.try()) {
throw new Error("Login rate limited!")
}
const data = await this.getData(request)
const payload = data ? querystring.parse(data) : {}
return await this.login(payload, route, request)
@ -108,3 +115,17 @@ export class LoginHttpProvider extends HttpProvider {
throw new Error("Missing password")
}
}
// RateLimiter wraps around the limiter library for logins.
// It allows 2 logins every minute and 12 logins every hour.
class RateLimiter {
private readonly minuteLimiter = new limiter.RateLimiter(2, "minute")
private readonly hourLimiter = new limiter.RateLimiter(12, "hour")
public try(): boolean {
if (this.minuteLimiter.tryRemoveTokens(1)) {
return true
}
return this.hourLimiter.tryRemoveTokens(1)
}
}

View File

@ -4044,6 +4044,11 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
limiter@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2"
integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==
lines-and-columns@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"