Added MAX_CONNECTION_RATE, MAX_COMMAND_RATE for throttling various aspects of input as a DoS measure as per #640.

This commit is contained in:
Griatch 2015-05-15 01:51:09 +02:00
parent f5eeba72e0
commit 37763ceca5
2 changed files with 31 additions and 11 deletions

View file

@ -1,17 +1,19 @@
"""
Sessionhandler for portal sessions
"""
from collections import deque
from time import time
from twisted.internet import reactor, task
from twisted.internet import reactor
from django.conf import settings
from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC
_CONNECTION_RATE = 5.0
_MIN_TIME_BETWEEN_CONNECTS = 1.0 / _CONNECTION_RATE
# module import
_MOD_IMPORT = None
#_MAX_CMD_RATE = 80.0
#_ERROR_COMMAND_OVERFLOW = "You entered commands too fast. Wait a moment and try again."
# throttles
_MIN_TIME_BETWEEN_CONNECTS = 1.0 / float(settings.MAX_CONNECTION_RATE) if float(settings.MAX_CONNECTION_RATE) > 0 else 1.0 / 5.0
_MIN_TIME_BETWEEN_CMDS = 1.0 / float(settings.MAX_COMMAND_RATE) if float(settings.MAX_COMMAND_RATE) > 0 else -10
_ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING
#------------------------------------------------------------
# Portal-SessionHandler class
@ -66,9 +68,8 @@ class PortalSessionHandler(SessionHandler):
session.sessid = self.latest_sessid
now = time()
current_rate = 1.0 / (now - self.time_last_connect)
if current_rate > _CONNECTION_RATE:
if now - self.time_last_connect < _MIN_TIME_BETWEEN_CONNECTS:
# we have too many connections per second. Delay.
#print " delaying connecting", session.sessid
reactor.callLater(_MIN_TIME_BETWEEN_CONNECTS, self.connect, session)
@ -80,9 +81,9 @@ class PortalSessionHandler(SessionHandler):
reactor.callLater(0.5, self.connect, session)
return
# sync with server-side
self.time_last_connect = now
# sync with server-side
sessdata = session.get_sync_data()
self.sessions[session.sessid] = session
session.server_connected = True
@ -290,7 +291,13 @@ class PortalSessionHandler(SessionHandler):
serialized before passed on.
"""
# data throttle (anti DoS measure)
prev_cmd_last = session.cmd_last
session.cmd_last = time()
if session.cmd_last - prev_cmd_last < _MIN_TIME_BETWEEN_CMDS:
self.data_out(session.sessid, text=_ERROR_COMMAND_OVERFLOW)
return
# relay data to Server
self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid,
msg=text,
data=kwargs)

View file

@ -71,7 +71,7 @@ WEBSOCKET_CLIENT_ENABLED = True
WEBSOCKET_CLIENT_PORT = 8001
# Interface addresses to listen to. If 0.0.0.0, listen to all. Use :: for IPv6.
WEBSOCKET_CLIENT_INTERFACE = '0.0.0.0'
# Actual URL for webclient component to reach the websocket.
# Actual URL for webclient component to reach the websocket.
# The WEBSOCKET_CLIENT_PORT will be automatically appended to this URL.
WEBSOCKET_CLIENT_URL = "ws://localhost"
# Activate SSH protocol communication (SecureShell)
@ -179,6 +179,19 @@ AMP_INTERFACE = '127.0.0.1'
# be necessary (use @server to see how many objects are in the idmapper
# cache at any time). Setting this to None disables the cache cap.
IDMAPPER_CACHE_MAXSIZE = 200 # (MB)
# This determines how many connections per second the Portal should
# accept, as a DoS countermeasure. If the rate exceeds this number, incoming
# connections will be queued to this rate, so none will be lost.
# Must be set to a value > 0.
MAX_CONNECTION_RATE = 5
# Determine how many commands per second a given Session is allowed
# to send to the Portal via a connected protocol. Too high rate will
# drop the command and echo a warning. Note that this will also cap
# OOB messages so don't set it too low if you expect a lot of events
# from the client! To turn the limiter off, set to <= 0.
MAX_COMMAND_RATE = 80
# The warning to echo back to users if they send commands too fast
COMMAND_RATE_WARNING ="You entered commands too fast. Wait a moment and try again."
######################################################################
# Evennia Database config