diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index c9c417f4..c5f37718 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -20,6 +20,7 @@ import vim import requests import urlparse +from base64 import b64decode, b64encode from retries import retries from requests_futures.sessions import FuturesSession from ycm.unsafe_thread_pool_executor import UnsafeThreadPoolExecutor @@ -124,8 +125,8 @@ class BaseRequest( object ): if not request_body: request_body = '' headers = dict( _HEADERS ) - headers[ _HMAC_HEADER ] = utils.CreateHexHmac( request_body, - BaseRequest.hmac_secret ) + headers[ _HMAC_HEADER ] = b64encode( + utils.CreateHexHmac( request_body, BaseRequest.hmac_secret ) ) return headers session = FuturesSession( executor = _EXECUTOR ) @@ -171,9 +172,10 @@ def JsonFromFuture( future ): def _ValidateResponseObject( response ): - if not utils.ContentHexHmacValid( response.content, - response.headers[ _HMAC_HEADER ], - BaseRequest.hmac_secret ): + if not utils.ContentHexHmacValid( + response.content, + b64decode( response.headers[ _HMAC_HEADER ] ), + BaseRequest.hmac_secret ): raise RuntimeError( 'Received invalid HMAC for response!' ) return True diff --git a/python/ycm/server/hmac_plugin.py b/python/ycm/server/hmac_plugin.py index cf8f475c..fec899bd 100644 --- a/python/ycm/server/hmac_plugin.py +++ b/python/ycm/server/hmac_plugin.py @@ -19,6 +19,7 @@ import logging import httplib +from base64 import b64decode, b64encode from bottle import request, response, abort from ycm import utils @@ -30,6 +31,9 @@ _HMAC_HEADER = 'x-ycm-hmac' # We want to ensure that every request coming in has a valid HMAC set in the # x-ycm-hmac header and that every response coming out sets such a valid header. # This is to prevent security issues with possible remote code execution. +# The x-ycm-hmac value is encoded as base64 during transport instead of sent raw +# because https://tools.ietf.org/html/rfc5987 says header values must be in the +# ISO-8859-1 character set. class HmacPlugin( object ): name = 'hmac' api = 2 @@ -54,9 +58,12 @@ class HmacPlugin( object ): def RequestAuthenticated( body, hmac_secret ): - return utils.ContentHexHmacValid( body, - request.headers[ _HMAC_HEADER ], - hmac_secret ) + return utils.ContentHexHmacValid( + body, + b64decode( request.headers[ _HMAC_HEADER ] ), + hmac_secret ) + def SetHmacHeader( body, hmac_secret ): - response.headers[ _HMAC_HEADER ] = utils.CreateHexHmac( body, hmac_secret ) + response.headers[ _HMAC_HEADER ] = b64encode( + utils.CreateHexHmac( body, hmac_secret ) )