示例#1
0
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)
示例#2
0
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
示例#3
0
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
示例#4
0
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)
示例#6
0
 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
示例#7
0
    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
示例#8
0
 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