Permalink
Browse files

1st draft of URL security filter

  • Loading branch information...
1 parent 6271485 commit 5c9aa5c1e311dd0814bc9b00874dceb0c183b3f4 Bjarni R. Einarsson committed Jul 17, 2012
Showing with 45 additions and 2 deletions.
  1. +1 −1 Makefile
  2. +1 −0 pagekite/manual.py
  3. +2 −0 pagekite/pk.py
  4. +9 −1 pagekite/proto/conns.py
  5. +32 −0 pagekite/proto/filters.py
View
@@ -10,8 +10,8 @@ BREED_PAGEKITE = pagekite/__init__.py \
pagekite/proto/proto.py \
pagekite/proto/parsers.py \
pagekite/proto/selectables.py \
- pagekite/proto/conns.py \
pagekite/proto/filters.py \
+ pagekite/proto/conns.py \
pagekite/ui/__init__.py \
pagekite/ui/nullui.py \
pagekite/ui/basic.py \
View
@@ -83,6 +83,7 @@
+rewritehost</b> __Rewrite the incoming Host: header.
+rewritehost</b>=<a>N</a> __Replace Host: header value with N.
+rawheaders</b> __Do not rewrite (or add) any HTTP headers at all.
+ +insecure</b> __Allow access to phpMyAdmin, /admin, etc.
""")
MAN_FLAGS_BUILTIN = ("""\
+indexes __Enable directory indexes.
View
@@ -2491,12 +2491,14 @@ def CreateTunnels(self, conns):
if server == LOOPBACK_FE:
loop = LoopbackTunnel.Loop(conns, self.backends)
loop.filters.append(HttpHeaderFilter())
+ loop.filters.append(HttpSecurityFilter(self.ui))
else:
self.ui.Status('connect', color=self.ui.YELLOW,
message='Front-end connect: %s' % server)
tun = Tunnel.BackEnd(server, self.backends, self.require_all, conns)
if tun:
tun.filters.append(HttpHeaderFilter())
+ tun.filters.append(HttpSecurityFilter(self.ui))
if self.watch_level[0] is not None:
tun.filters.append(TunnelWatcher(self.watch_level, self.ui))
logging.Log([('connect', server)])
View
@@ -33,6 +33,7 @@
import pagekite.common as common
import pagekite.logging as logging
+from filters import HttpSecurityFilter
from selectables import *
from parsers import *
from proto import *
@@ -693,7 +694,7 @@ def ConnectBE(self, sid, proto, port, host, rIp, rPort, rTLS, data):
else:
rewritehost = False
- data = self.FilterIncoming(sid, data, info={
+ data = self.FilterIncoming(sid, data, info={
'proto': proto,
'port': port,
'host': host,
@@ -702,11 +703,15 @@ def ConnectBE(self, sid, proto, port, host, rIp, rPort, rTLS, data):
'using_tls': rTLS,
'be_host': conn and conn.backend[BE_BHOST],
'be_port': conn and conn.backend[BE_BPORT],
+ 'insecure': conn and conn.config.get('insecure', False),
'rawheaders': conn and conn.config.get('rawheaders', False),
'rewritehost': rewritehost
})
if proto in ('http', 'http2', 'http3', 'websocket'):
+ if conn and data.startswith(HttpSecurityFilter.REJECT):
+ # Pretend we need authentication for dangerous URLs
+ conn, data = False, ''
if not conn:
# conn is None means we have no back-end.
# conn is False means authentication is required.
@@ -717,6 +722,8 @@ def ConnectBE(self, sid, proto, port, host, rIp, rPort, rTLS, data):
code=code
))):
return False, False
+ else:
+ conn = None
elif conn and proto == 'httpfinger':
# Rewrite a finger request to HTTP.
@@ -736,6 +743,7 @@ def ConnectBE(self, sid, proto, port, host, rIp, rPort, rTLS, data):
'Host: %s\r\n\r\n%s') % args
except Exception, e:
self.LogError('Error formatting HTTP-Finger: %s' % e)
+ conn.Die()
conn = None
if conn:
View
@@ -156,3 +156,35 @@ def filter_data_in(self, tunnel, sid, data):
return TunnelFilter.filter_data_in(self, tunnel, sid, data)
+
+class HttpSecurityFilter(TunnelFilter):
+ """Filter that blocks known-to-be-dangerous requests."""
+
+ HTTP_DANGER = re.compile('(?ism)^(([A-Z]+) '
+ '(/+(?:xampp|security|adm)'
+ '|[^\n]*(?:/wp-admin/|/system32/'
+ '|/(?:php)?my(?:sql)?(?:adm|manager)'
+ '|/(?:setup|install|admin).php)'
+ ')[^\n]*'
+ ' HTTP/\d+\.\d+\s*)$')
+ REJECT = 'PAGEKITE_REJECT_'
+
+ def __init__(self, ui):
+ TunnelFilter.__init__(self)
+ self.ui = ui
+
+ def filter_data_in(self, tunnel, sid, data):
+ info = self.sid.get(sid)
+ if (info and
+ info.get('proto') in ('http', 'http2', 'http3', 'websocket') and
+ not info.get('insecure', False)):
+
+ danger = self.HTTP_DANGER.search(data)
+ if danger:
+ data = self.REJECT+data
+ self.ui.Notify('BLOCKED: %s %s' % (danger.group(2), danger.group(3)),
+ color=self.ui.RED, prefix='***')
+ self.ui.Notify('NOTE: Use the +insecure flag to disable basic URL '
+ 'security checks.')
+
+ return TunnelFilter.filter_data_in(self, tunnel, sid, data)

0 comments on commit 5c9aa5c

Please sign in to comment.