Skip to content

Commit

Permalink
Merge pull request #13 from RuiSiang/ratelimit-dev
Browse files Browse the repository at this point in the history
Add ratelimit functionality
  • Loading branch information
RuiSiang authored Mar 16, 2021
2 parents 4c267c7 + 4e980a5 commit 13a180a
Show file tree
Hide file tree
Showing 16 changed files with 1,242 additions and 142 deletions.
9 changes: 8 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@ WAF=on
POW=on
NONCE_VALIDITY=60000
INITIAL_DIFFICULTY=13
BACKEND_URL="http://example.com"
BACKEND_URL="http://example.com"

RATE_LIMIT=on
RATE_LIMIT_SAMPLE_MINUTES=60
RATE_LIMIT_SESSION_THRESHOLD=100
RATE_LIMIT_BAN_IP=on
RATE_LIMIT_IP_THRESHOLD=500
RATE_LIMIT_BAN_MINUTES=15
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ Project dedicated to provide DDoS protection with proof-of-work

![screenshot](screenshot.jpg)
## Description
PoW Shield provides DDoS protection on OSI application layer by acting as a proxy between the backend service and the end user. This project aims to provide an alternative to general captcha methods such as Google's ReCaptcha that has always been a pain to solve. Accessing a web service protected by PoW Shield has never been easier, simply go to the url, and your browser will do the rest of the work for you.
PoW Shield provides DDoS protection on OSI application layer by acting as a proxy that utilizes proof of work between the backend service and the end user. This project aims to provide an alternative to general captcha methods such as Google's ReCaptcha that has always been a pain to solve. Accessing a web service protected by PoW Shield has never been easier, simply go to the url, and your browser will do the rest of the work for you.

[Detailed description and story on Medium](https://ruisiang.medium.com/pow-shield-application-layer-proof-of-work-ddos-filter-4fed32465509 "PoW Shield: Application Layer Proof of Work DDoS Filter")
PoW Shield aims to provide the following services bundles in a single webapp / docker image:
+ proof of work authentication
+ ratelimiting and ip blacklisting
+ web application firewall

[Story on Medium](https://ruisiang.medium.com/pow-shield-application-layer-proof-of-work-ddos-filter-4fed32465509 "PoW Shield: Application Layer Proof of Work DDoS Filter")

## Usage
github repo
Expand All @@ -31,24 +36,33 @@ see docker-compose.example.yaml
```

## Configuration
+ PORT: port that PoW Shield listens to
+ PORT: (default:3000) port that PoW Shield listens to
+ SESSION_KEY: secret key for cookie signatures, use a unique one for security reasons, or anyone can forge your signed cookies
+ WAF: toggles waf functionality on/off (waf is a work in progress)
+ POW: toggles PoW functionality on/off (if not temporary switched off, why use this project at all?)
+ NONCE_VALIDITY: specifies the maximum time a nonce has to be submitted to the server after generation(used to enforce difficulty change and filter out stale nonces)
+ INITIAL_DIFFICULTY: initial difficulty, number of leading 0-bits in produced hash (0:extremely easy ~ 256:impossible, 13(default):takes about 5 seconds for the browser to calculate)
+ WAF: (default:on) toggles waf functionality on/off (waf is a work in progress)
+ POW: (default:on) toggles PoW functionality on/off (if not temporary switched off, why use this project at all?)
+ NONCE_VALIDITY: (default:60000) specifies the maximum seconds a nonce has to be submitted to the server after generation(used to enforce difficulty change and filter out stale nonces)
+ INITIAL_DIFFICULTY: (default:13) initial difficulty, number of leading 0-bits in produced hash (0:extremely easy ~ 256:impossible, 13(default) takes about 5 seconds for the browser to calculate)
+ BACKEND_URL: location to proxy authenticated traffic to, IP and URLs are both accepted(accepts protocol://url(:port) or protocol://ip(:port))

+ RATE_LIMIT: (default:on) toggles ratelimit functionality on/off
+ RATE_LIMIT_SAMPLE_MINUTES: (default:60) specifies how many minutes until statistics reset for session/ip
+ RATE_LIMIT_SESSION_THRESHOLD: (default:100) number of requests that a single session can make until triggering token revokation
+ RATE_LIMIT_BAN_IP: (default:on) toggles ip banning functionality on/off
+ RATE_LIMIT_IP_THRESHOLD: (default:500) number of requests that a single session can make until triggering IP ban
+ RATE_LIMIT_BAN_MINUTES: (default:15) number of minutes that IP ban persists

## TODOs
- [x] Web Service Structure
- [x] Proxy Functionality
- [x] PoW Implementation
- [x] Dockerization
- [x] IP Blacklisting
- [x] Ratelimiting
- [ ] WAF Implementation
- [ ] IP Blacklisting
- [ ] Dynamic Difficulty
- [ ] Unit Testing
- [ ] Multi-Instance Syncing
- [ ] Monitoring

## License
BSD 3-Clause License
Expand Down
25 changes: 15 additions & 10 deletions app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,30 @@ import views from 'koa-views'
import json from 'koa-json'
import bodyparser from 'koa-bodyparser'
import logger from 'koa-logger'
import { createProxyMiddleware, Filter, Options } from 'http-proxy-middleware'
import { createProxyMiddleware } from 'http-proxy-middleware'
import c2k from 'koa2-connect'
import session from 'koa-generic-session'
import session from 'koa-session-minimal'

import config from './service/config-parser'
import powRouter from './routes/pow-router'
import { waf, authorizer } from './service/firewall-service'
import { controller } from './service/controller-service'

app.keys = [config.get()['session_key']]
app.keys = [config.session_key]
app.use(
session({
key: 'pow-shield',
cookie: {
maxAge: 86400000,
overwrite: true,
httpOnly: true,
signed: true,
sameSite: 'strict',
},
})
)

const proxy = createProxyMiddleware(['**', '!/pow'], {
target: config.get()['backend_url'],
target: config.backend_url,
changeOrigin: true,
ws: true,
})
Expand Down Expand Up @@ -50,13 +57,11 @@ app.use(async (ctx, next) => {
})

// service and routes
if (config.get()['waf']) {
app.use(waf)
}
if (config.get()['pow']) {
if (config.pow) {
app.use(powRouter.routes())
app.use(authorizer)
}
app.use(controller)

app.use(c2k(proxy))

// error-handling
Expand Down
6 changes: 6 additions & 0 deletions docker-compose.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ services:
- NONCE_VALIDITY=60000
- INITIAL_DIFFICULTY=13
- BACKEND_URL="http://example.com"
- RATE_LIMIT=on
- RATE_LIMIT_SAMPLE_MINUTES=60
- RATE_LIMIT_SESSION_THRESHOLD=100
- RATE_LIMIT_BAN_IP=on
- RATE_LIMIT_IP_THRESHOLD=500
- RATE_LIMIT_BAN_MINUTES=15
expose:
- '3000'
ports:
Expand Down
2 changes: 1 addition & 1 deletion lib/pow/verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import utils from './utils'

const MIN_NONCE_LEN = 8
const MAX_NONCE_LEN = 32
const DEFAULT_VALIDITY = config.get()['nonce_validity']
const DEFAULT_VALIDITY = config.nonce_validity

export interface IVerifierOptions {
readonly validity?: number
Expand Down
Loading

0 comments on commit 13a180a

Please sign in to comment.