Obscure the X-Auth-Token in proxy log
The X-Auth-Token is sensitive data. If revealed to an unauthozied person, they can now make requests against an account until the token expires. This implementation maintains current behavior (i.e, the token is logged). Implementers can choose to set reveal_sensitive_prefix to (e.g.) 12 so only first 12 characters of the token are logged. Or, set to 0 to replace the token with "...". DocImpact Part of bug #1004114 Change-Id: Iecefa843d8f9ef59b9dcf0860e7a4d0e186a6cb5
This commit is contained in:
parent
6a9f55d876
commit
eb99e8f84c
@ -425,6 +425,18 @@ use = egg:swift#proxy_logging
|
||||
# access_log_statsd_metric_prefix =
|
||||
# access_log_headers = false
|
||||
#
|
||||
# By default, the X-Auth-Token is logged. To obscure the value,
|
||||
# set reveal_sensitive_prefix to the number of characters to log.
|
||||
# For example, if set to 12, only the first 12 characters of the
|
||||
# token appear in the log. An unauthorized access of the log file
|
||||
# won't allow unauthorized usage of the token. However, the first
|
||||
# 12 or so characters is unique enough that you can trace/debug
|
||||
# token usage. Set to 0 to suppress the token completely (replaced
|
||||
# by '...' in the log).
|
||||
# Note: reveal_sensitive_prefix will not affect the value
|
||||
# logged with access_log_headers=True.
|
||||
# reveal_sensitive_prefix = 8192
|
||||
#
|
||||
# What HTTP methods are allowed for StatsD logging (comma-sep); request methods
|
||||
# not in this list will have "BAD_METHOD" for the <verb> portion of the metric.
|
||||
# log_statsd_valid_http_methods = GET,HEAD,POST,PUT,DELETE,COPY,OPTIONS
|
||||
|
@ -77,6 +77,7 @@ from swift.common.swob import Request
|
||||
from swift.common.utils import (get_logger, get_remote_client,
|
||||
get_valid_utf8_str, config_true_value,
|
||||
InputProxy)
|
||||
from swift.common.constraints import MAX_HEADER_SIZE
|
||||
|
||||
QUOTE_SAFE = '/:'
|
||||
|
||||
@ -112,6 +113,8 @@ class ProxyLoggingMiddleware(object):
|
||||
self.access_logger = get_logger(access_log_conf,
|
||||
log_route='proxy-access')
|
||||
self.access_logger.set_statsd_prefix('proxy-server')
|
||||
self.reveal_sensitive_prefix = int(conf.get('reveal_sensitive_prefix',
|
||||
MAX_HEADER_SIZE))
|
||||
|
||||
def method_from_req(self, req):
|
||||
return req.environ.get('swift.orig_req_method', req.method)
|
||||
@ -122,6 +125,13 @@ class ProxyLoggingMiddleware(object):
|
||||
def mark_req_logged(self, req):
|
||||
req.environ['swift.proxy_access_log_made'] = True
|
||||
|
||||
def obscure_sensitive(self, value):
|
||||
if not value:
|
||||
return '-'
|
||||
if len(value) > self.reveal_sensitive_prefix:
|
||||
return value[:self.reveal_sensitive_prefix] + '...'
|
||||
return value
|
||||
|
||||
def log_request(self, req, status_int, bytes_received, bytes_sent,
|
||||
request_time):
|
||||
"""
|
||||
@ -156,7 +166,7 @@ class ProxyLoggingMiddleware(object):
|
||||
status_int,
|
||||
req.referer,
|
||||
req.user_agent,
|
||||
req.headers.get('x-auth-token'),
|
||||
self.obscure_sensitive(req.headers.get('x-auth-token')),
|
||||
bytes_received,
|
||||
bytes_sent,
|
||||
req.headers.get('etag', None),
|
||||
|
@ -571,6 +571,77 @@ class TestProxyLogging(unittest.TestCase):
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[17], 'one%2Cand%20two')
|
||||
|
||||
def test_log_auth_token(self):
|
||||
auth_token = 'b05bf940-0464-4c0e-8c70-87717d2d73e8'
|
||||
|
||||
# Default - no reveal_sensitive_prefix in config
|
||||
# No x-auth-token header
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], '-')
|
||||
# Has x-auth-token header
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET',
|
||||
'HTTP_X_AUTH_TOKEN': auth_token})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], auth_token)
|
||||
|
||||
# Truncate to first 8 characters
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'reveal_sensitive_prefix': '8'})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], '-')
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'reveal_sensitive_prefix': '8'})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET',
|
||||
'HTTP_X_AUTH_TOKEN': auth_token})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], 'b05bf940...')
|
||||
|
||||
# Token length and reveal_sensitive_prefix are same (no truncate)
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'reveal_sensitive_prefix': str(len(auth_token))})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET',
|
||||
'HTTP_X_AUTH_TOKEN': auth_token})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], auth_token)
|
||||
|
||||
# Don't log x-auth-token
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'reveal_sensitive_prefix': '0'})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET'})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], '-')
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {
|
||||
'reveal_sensitive_prefix': '0'})
|
||||
app.access_logger = FakeLogger()
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET',
|
||||
'HTTP_X_AUTH_TOKEN': auth_token})
|
||||
resp = app(req.environ, start_response)
|
||||
resp_body = ''.join(resp)
|
||||
log_parts = self._log_parts(app)
|
||||
self.assertEquals(log_parts[9], '...')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user