def get_csrf_token_from_request(request): """Given a Request object, reject it if it's a forgery. """ if request.line.uri.startswith('/assets/'): return if request.line.uri.startswith('/callbacks/'): return try: csrf_token = _sanitize_token(request.headers.cookie['csrf_token'].value) except KeyError: csrf_token = None request.context['csrf_token'] = csrf_token or _get_new_csrf_key() # Assume that anything not defined as 'safe' by RC2616 needs protection if request.line.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if csrf_token is None: raise Response(403, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.line.method == "POST": if isinstance(request.body, dict): request_csrf_token = request.body.get('csrf_token', '') if request_csrf_token == "": # Fall back to X-CSRF-TOKEN, to make things easier for AJAX, # and possible for PUT/DELETE. request_csrf_token = request.headers.get('X-CSRF-TOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): raise Response(403, REASON_BAD_TOKEN)
def check_id_auth(data): from app import db from models import Voter from crypto import salted_hmac, constant_time_compare curr_eid = current_app.config.get("CURRENT_ELECTION_ID", 0) voters = db.session.query(Voter)\ .filter(Voter.election_id == curr_eid, Voter.status == Voter.STATUS_AUTHENTICATED, Voter.is_active == True, Voter.id == int(data['identifier'])) if voters.count() != 1: return error("Invalid identifier", error_codename="invalid_id") # check token key = current_app.config.get("AGORA_SHARED_SECRET_KEY", "") hmac = salted_hmac(key, data['identifier'], "").hexdigest() if not constant_time_compare(data["sha1_hmac"], hmac): return error("Invalid hmac", error_codename="invalid_hmac") is_rowlock = (current_app.config.get("SERIALIZATION_MODE", "SERIALIZED") == "ROWLOCK") if is_rowlock: voters = voters.with_lockmode("update").all() voter = voters[0] else: voter = voters.first() data['voter'] = voter return RET_PIPE_CONTINUE
def get_csrf_token_from_request(request): """Given a Request object, reject it if it's a forgery. """ if request.line.uri.startswith('/assets/'): return if request.line.uri.startswith('/callbacks/'): return try: csrf_token = _sanitize_token( request.headers.cookie['csrf_token'].value) except KeyError: csrf_token = None request.context['csrf_token'] = csrf_token or _get_new_csrf_key() # Assume that anything not defined as 'safe' by RC2616 needs protection if request.line.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if _is_secure(request): # Suppose user visits http://example.com/ # An active network attacker (man-in-the-middle, MITM) sends a # POST form that targets https://example.com/detonate-bomb/ and # submits it via JavaScript. # # The attacker will need to provide a CSRF cookie and token, but # that's no problem for a MITM and the session-independent # nonce we're using. So the MITM can circumvent the CSRF # protection. This is true for any HTTP connection, but anyone # using HTTPS expects better! For this reason, for # https://example.com/ we need additional protection that treats # http://example.com/ as completely untrusted. Under HTTPS, # Barth et al. found that the Referer header is missing for # same-domain requests in only about 0.2% of cases or less, so # we can use strict Referer checking. referer = request.headers.get('Referer') if referer is None: raise Response(403, REASON_NO_REFERER) good_referer = 'https://%s/' % _get_host(request) if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) log_dammit(reason) raise Response(403, reason) if csrf_token is None: raise Response(403, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.line.method == "POST": if isinstance(request.body, dict): request_csrf_token = request.body.get('csrf_token', '') if request_csrf_token == "": # Fall back to X-CSRF-TOKEN, to make things easier for AJAX, # and possible for PUT/DELETE. request_csrf_token = request.headers.get('X-CSRF-TOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): raise Response(403, REASON_BAD_TOKEN)
def inbound(request): """Given a Request object, reject it if it's a forgery. """ if request.line.uri.startswith('/assets/'): return try: csrf_token = request.headers.cookie.get('csrf_token') csrf_token = '' if csrf_token is None else csrf_token.value csrf_token = _sanitize_token(csrf_token) except KeyError: csrf_token = _get_new_csrf_key() request.context['csrf_token'] = csrf_token # Assume that anything not defined as 'safe' by RC2616 needs protection if request.line.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if _is_secure(request): # Suppose user visits http://example.com/ # An active network attacker (man-in-the-middle, MITM) sends a # POST form that targets https://example.com/detonate-bomb/ and # submits it via JavaScript. # # The attacker will need to provide a CSRF cookie and token, but # that's no problem for a MITM and the session-independent # nonce we're using. So the MITM can circumvent the CSRF # protection. This is true for any HTTP connection, but anyone # using HTTPS expects better! For this reason, for # https://example.com/ we need additional protection that treats # http://example.com/ as completely untrusted. Under HTTPS, # Barth et al. found that the Referer header is missing for # same-domain requests in only about 0.2% of cases or less, so # we can use strict Referer checking. referer = request.headers.get('Referer') if referer is None: raise Response(403, REASON_NO_REFERER) good_referer = 'https://%s/' % _get_host(request) if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) log_dammit(reason) raise Response(403, reason) if csrf_token is None: raise Response(403, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.line.method == "POST": request_csrf_token = request.body.get('csrf_token', '') if request_csrf_token == "": # Fall back to X-CSRF-TOKEN, to make things easier for AJAX, # and possible for PUT/DELETE. request_csrf_token = request.headers.get('X-CSRF-TOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): raise Response(403, REASON_BAD_TOKEN)
def authenticate(self, request, user, salt, one_time_salt, password_hash, data=None): password = crypto.parse_password(user.password) try: session_one_time_salt = request.session['one_time_salt'] except KeyError: return if crypto.from_string(session_one_time_salt) == one_time_salt and password['salt'] == salt: valid_password_hash = crypto.hash(password['hash'], one_time_salt) if data: valid_password_hash = crypto.hash(data, valid_password_hash) if crypto.constant_time_compare(valid_password_hash, password_hash): request.user = user return user
def critical_path(): voters = db.session.query(Voter)\ .filter(Voter.election_id == curr_eid, Voter.tlf == data["tlf"], Voter.dni == data["dni"].upper(), Voter.status == Voter.STATUS_SENT, Voter.is_active == True) if voters.count() == 0: return error("Voter has not any sms", error_codename="sms_notsent") is_rowlock = (current_app.config.get("SERIALIZATION_MODE", "SERIALIZED") == "ROWLOCK") if is_rowlock: voters = voters.with_lockmode("update").all() voter = voters[0] else: voter = voters.first() # check token has not too many guesses or has expired expire_time = current_app.config.get('SMS_TOKEN_EXPIRE_SECS', 60*10) expire_dt = datetime.utcnow() - timedelta(seconds=expire_time) if voter.token_guesses >= current_app.config.get("MAX_TOKEN_GUESSES", 3) or\ voter.message.created <= expire_dt: db.session.commit() return error("Voter provided invalid token, please try a new one", error_codename="need_new_token") token = data["token"].upper() token_hash = hash_token(token) # check token if not constant_time_compare(token_hash, voter.message.token): voter.token_guesses += 1 voter.modified = datetime.utcnow() db.session.add(voter) db.session.commit() return error("Voter provided invalid token", error_codename="invalid_token") voter.status = Voter.STATUS_AUTHENTICATED voter.modified = datetime.utcnow() db.session.add(voter) # invalidate other voters with same tlf for v in voters[1:]: v.is_active = False db.session.add(v) db.session.commit() # okey now we have finished the critical serialized path, we can breath now return voter
def authenticate(self, request, user, salt, one_time_salt, password_hash, data=None): password = crypto.parse_password(user.password) try: session_one_time_salt = request.session['one_time_salt'] except KeyError: return if crypto.from_string(session_one_time_salt ) == one_time_salt and password['salt'] == salt: valid_password_hash = crypto.hash(password['hash'], one_time_salt) if data: valid_password_hash = crypto.hash(data, valid_password_hash) if crypto.constant_time_compare(valid_password_hash, password_hash): request.user = user return user