Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
.iml
*.pyc
db.sqlite3
manage.py
Expand Down
42 changes: 23 additions & 19 deletions perimeterx/middleware.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from px_logger import Logger
import px_context
import px_activities_client
import px_cookie
import px_cookie_validator
import px_httpc
import px_captcha
import px_api
import px_template
import Cookie



class PerimeterX(object):
def __init__(self, app, config=None):
self.app = app
Expand All @@ -22,6 +21,7 @@ def __init__(self, app, config=None):
'perimeterx_server_host': 'sapi.perimeterx.net',
'captcha_enabled': True,
'server_calls_enabled': True,
'encryption_enabled': True,
'sensitive_headers': ['cookie', 'cookies'],
'send_page_activities': True,
'api_timeout': 1,
Expand Down Expand Up @@ -63,26 +63,30 @@ def custom_start_response(status, headers, exc_info=None):

def _verify(self, environ, start_response):
logger = self.config['logger']
ctx = px_context.build_context(environ, self.config)

if ctx.get('module_mode') == 'inactive' or is_static_file(ctx):
logger.debug('Filter static file request. uri: ' + ctx.get('uri'))
return self.app(environ, start_response)
try:
ctx = px_context.build_context(environ, self.config)

cookies = Cookie.SimpleCookie(environ.get('HTTP_COOKIE'))
if self.config.get('captcha_enabled') and cookies.get('_pxCaptcha') and cookies.get('_pxCaptcha').value:
pxCaptcha = cookies.get('_pxCaptcha').value
if px_captcha.verify(ctx, self.config, pxCaptcha):
logger.debug('User passed captcha verification. user ip: ' + ctx.get('socket_ip'))
if ctx.get('module_mode') == 'inactive' or is_static_file(ctx):
logger.debug('Filter static file request. uri: ' + ctx.get('uri'))
return self.app(environ, start_response)

# PX Cookie verification
if not px_cookie.verify(ctx, self.config) and self.config.get('server_calls_enabled', True):
# Server-to-Server verification fallback
if not px_api.verify(ctx, self.config):
return self.app(environ, start_response)

return self.handle_verification(ctx, self.config, environ, start_response)
cookies = Cookie.SimpleCookie(environ.get('HTTP_COOKIE'))
if self.config.get('captcha_enabled') and cookies.get('_pxCaptcha') and cookies.get('_pxCaptcha').value:
pxCaptcha = cookies.get('_pxCaptcha').value
if px_captcha.verify(ctx, self.config, pxCaptcha):
logger.debug('User passed captcha verification. user ip: ' + ctx.get('socket_ip'))
return self.app(environ, start_response)

# PX Cookie verification
if not px_cookie_validator.verify(ctx, self.config) and self.config.get('server_calls_enabled', True):
# Server-to-Server verification fallback
if not px_api.verify(ctx, self.config):
return self.app(environ, start_response)

return self.handle_verification(ctx, self.config, environ, start_response)
except:
logger.error("Cought exception, passing request")
self.pass_traffic(environ, start_response, ctx)

def handle_verification(self, ctx, config, environ, start_response):
score = ctx.get('risk_score', -1)
Expand Down
2 changes: 0 additions & 2 deletions perimeterx/px_activities_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def send_activities():
def send_to_perimeterx(activity_type, ctx, config, detail):
global CONFIG
try:
print activity_type
if not config.get('server_calls_enabled', True):
return

Expand Down Expand Up @@ -57,7 +56,6 @@ def send_to_perimeterx(activity_type, ctx, config, detail):
'vid': ctx.get('vid', ''),
'uuid': ctx.get('uuid', '')
}
print 'appending'
ACTIVITIES_BUFFER.append(data)
except:
print traceback.format_exception(*sys.exc_info())
Expand Down
16 changes: 12 additions & 4 deletions perimeterx/px_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@

def send_risk_request(ctx, config):
body = prepare_risk_body(ctx, config)
return px_httpc.send('/api/v1/risk', body, config)
return px_httpc.send('/api/v2/risk', body, config)


def verify(ctx, config):
logger = config['logger']
logger.debug("PxAPI[verify]")
try:
response = send_risk_request(ctx, config)
if response:
ctx['risk_score'] = response['scores']['non_human']
score = response['score']
ctx['score'] = score
ctx['uuid'] = response['uuid']
if ctx['risk_score'] >= config['blocking_score']:
ctx['block_action'] = response['action']
if score >= config['blocking_score']:
logger.debug("PxAPI[verify] block score threshold reached")
ctx['block_reason'] = 's2s_high_score'

logger.debug("PxAPI[verify] S2S completed")
return True
else:
return False
Expand All @@ -27,6 +32,7 @@ def verify(ctx, config):

def prepare_risk_body(ctx, config):
logger = config['logger']
logger.debug("PxAPI[send_risk_request]")
body = {
'request': {
'ip': ctx.get('socket_ip'),
Expand All @@ -41,7 +47,8 @@ def prepare_risk_body(ctx, config):
'http_method': ctx.get('http_method', ''),
'http_version': ctx.get('http_version', ''),
'module_version': config.get('module_version', ''),
'risk_mode': config.get('module_mode', '')
'risk_mode': config.get('module_mode', ''),
'px_cookie_hmac': ctx.get('cookie_hmac', '')
}
}

Expand All @@ -53,6 +60,7 @@ def prepare_risk_body(ctx, config):
logger.debug('attaching px_cookie to request')
body['additional']['px_cookie'] = ctx.get('decoded_cookie')

logger.debug("PxAPI[send_risk_request] request body: " + str(body))
return body


Expand Down
5 changes: 5 additions & 0 deletions perimeterx/px_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
PREFIX_PX_COOKIE_V1 = '_px'
PREFIX_PX_COOKIE_V3 = '_px3'

TRANS_5C = b"".join(chr(x ^ 0x5C) for x in range(256))
TRANS_36 = b"".join(chr(x ^ 0x36) for x in range(256))
15 changes: 10 additions & 5 deletions perimeterx/px_context.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import Cookie
from px_constants import *


def build_context(environ, config):
logger = config['logger']
headers = {}

# Default values
http_method = 'GET'
http_version = '1.1'
http_protocol = 'http://'
px_cookie = ''
uuid = ''
px_cookies = {}

# IP Extraction
if config.get('ip_handler'):
Expand All @@ -33,8 +34,12 @@ def build_context(environ, config):
http_version = protocol_split[1]

cookies = Cookie.SimpleCookie(environ.get('HTTP_COOKIE', ''))
if cookies.get('_px') and cookies.get('_px').value:
px_cookie = cookies.get('_px').value
cookie_keys = cookies.keys()

for key in cookie_keys:
if key == PREFIX_PX_COOKIE_V1 or key == PREFIX_PX_COOKIE_V3:
logger.debug('Found cookie prefix:' + key)
px_cookies[key] = cookies.get(key).value

user_agent = headers.get('user-agent')
uri = environ.get('PATH_INFO') or ''
Expand All @@ -49,6 +54,6 @@ def build_context(environ, config):
'full_url': full_url,
'uri': uri,
'hostname': hostname,
'_px': px_cookie
'px_cookies': px_cookies
}
return ctx
Loading