Пример #1
0
    def test_backends_explicit(self):
        for ha in ["md5", "sha256", "sha512"]:
            for cache in ["default", "db"]:
                with override_settings(RATELIMIT_GROUP_HASH=ha,
                                       RATELIMIT_KEY_HASH=ha):
                    r = None
                    for i in range(0, 4):
                        r = ratelimit.get_ratelimit(group="test_backends",
                                                    rate="1/s",
                                                    key=b"explicittest",
                                                    cache=cache)
                        self.assertEqual(r["request_limit"], 0)

                    for i in range(0, 2):
                        r = ratelimit.get_ratelimit(group="test_backends",
                                                    rate="1/s",
                                                    key=b"explicittest",
                                                    inc=True,
                                                    cache=cache)
                    self.assertEqual(r["request_limit"], 1)
                    r = ratelimit.get_ratelimit(group="test_backends",
                                                rate="1/s",
                                                key=b"explicittest",
                                                inc=True,
                                                cache=cache)
                    self.assertEqual(r["request_limit"], 1)
            _get_group_hash.cache_clear()
Пример #2
0
    def test_basic(self):
        r = None
        for i in range(0, 4):
            # just view, without retrieving
            r = ratelimit.get_ratelimit(group="test_basic",
                                        rate="1/s",
                                        key=b"abc")
            self.assertEqual(r["request_limit"], 0)

        for i in range(0, 2):
            r = ratelimit.get_ratelimit(group="test_basic",
                                        rate="1/s",
                                        key=b"abc2",
                                        inc=True)
        self.assertEqual(r["request_limit"], 1)
        r = ratelimit.get_ratelimit(group="test_basic",
                                    rate="1/s",
                                    key=b"abc2",
                                    inc=True)
        self.assertEqual(r["request_limit"], 1)
        time.sleep(2)
        r = ratelimit.get_ratelimit(group="test_basic",
                                    rate="1/s",
                                    key=b"abc2",
                                    inc=True)
        self.assertEqual(r["request_limit"], 0)
Пример #3
0
    def test_request_post_get_filter(self):
        r = None
        request = self.factory.get('/customer/details')
        for i in range(0, 4):
            r = ratelimit.get_ratelimit(group="test_request_post_get_filter",
                                        rate="1/s",
                                        key="ip",
                                        request=request,
                                        inc=True,
                                        methods=["POST"])
            self.assertEqual(r["request_limit"], 0)

        for i in range(0, 2):
            r = ratelimit.get_ratelimit(group="test_request_post_get_filter",
                                        rate="1/s",
                                        key="ip:32/64",
                                        inc=True,
                                        request=request,
                                        methods=["GET"])
        self.assertEqual(r["request_limit"], 1)
        r = ratelimit.get_ratelimit(group="test_request_post_get_filter",
                                    rate="1/s",
                                    key="ip",
                                    inc=True,
                                    request=request,
                                    methods=["GET"])
        self.assertEqual(r["request_limit"], 1)
Пример #4
0
    def authenticate(self,
                     request,
                     username=None,
                     protection_codes=None,
                     nospider=False,
                     **kwargs):
        """ Use protections for authentication"""
        # disable SpiderAuthBackend backend (against recursion)
        if nospider:
            return
        uc = UserComponent.objects.filter(user__username=username,
                                          name="index").first()
        if not uc:
            request.protections = \
                Protection.objects.valid().order_by(
                    "code"
                ).authall(
                    request, scope="auth",
                    ptype=ProtectionType.authentication,
                    protection_codes=protection_codes
                )
            if type(request.protections) is int:  # should never happen
                logger.warning(
                    "Login try without username, should never "
                    "happen, archieved strength: %s", request.protections)
                return None
        else:
            try:
                request.protections = uc.auth(
                    request,
                    scope="auth",
                    ptype=ProtectionType.authentication,
                    protection_codes=protection_codes)
            except Http404:
                # for Http404 auth abort by protections (e.g. Random Fail)
                pass

            if type(request.protections) is int:
                if AssignedContent.travel.auth(request, uc):
                    if request.protections < MIN_PROTECTION_STRENGTH_LOGIN:
                        logger.warning("Low login protection strength: %s, %s",
                                       request.protections, username)
                    return uc.user
        # error path

        # allow blocking per hour
        ratelimit.get_ratelimit(request=request,
                                group="spider_login_failed_ip",
                                key="ip",
                                inc=True,
                                rate=(float("inf"), 3600))
        ratelimit.get_ratelimit(request=request,
                                group="spider_login_failed_account",
                                key=lambda x, y: username,
                                inc=True,
                                rate=(float("inf"), 3600))
        # be less secure here, most probably the user is already known
        time.sleep(_nonexhaustRandom.random() / 2)
Пример #5
0
    def clean_domain_upgrade(self, context, token):
        if "referrer" not in self.request.GET:
            return False
        # domain mode must be used alone
        if len(context["intentions"]) > 1:
            return False
        if not context["intentions"].issubset(VALID_INTENTIONS):
            return False

        if not getattr(self.request, "_clean_domain_upgrade_checked", False):
            if ratelimit.get_ratelimit(request=self.request,
                                       group="clean_domain_upgrade",
                                       key=("get", {
                                           "IP": True,
                                           "USER": True
                                       }),
                                       rate=settings.SPIDER_DOMAIN_UPDATE_RATE,
                                       inc=True)["request_limit"] > 0:
                return False

            setattr(self.request, "_clean_domain_upgrade_checked", True)

        # False for really no token
        if token is False:
            return True
        if not token or token.extra.get("strength", 0) >= 10:
            return False
        return True
Пример #6
0
def rate_limit_default(request, view):
    group = getattr(view, "rate_limit_group", None)
    if group:
        ratelimit.get_ratelimit(request=request,
                                group=group,
                                key="user_or_ip",
                                inc=True,
                                rate=(math.inf, 3600))
    results = failed_guess.send_robust(sender=view, request=request)
    for (receiver, result) in results:
        if isinstance(result, Exception):
            logging.error("%s failed", receiver, exc_info=result)
    # with 0.4% chance reseed
    if _nonexhaustRandom.randint(0, 249) == 0:
        _nonexhaustRandom.seed(os.urandom(10))
    time.sleep(_nonexhaustRandom.random() / 2)
    raise Http404()
Пример #7
0
 def get(self, request, *args, **kwargs):
     request.ratelimit2 = ratelimit.get_ratelimit(group=ratelimit.o2g(
         self.get),
                                                  rate="1/s",
                                                  key=b"o2gtest",
                                                  inc=True)
     if request.ratelimit2["request_limit"] > 0:
         return HttpResponse(status=400)
     return HttpResponse()
Пример #8
0
 def test_block_empty(self):
     request = self.factory.get('/customer/details')
     request.user = AnonymousUser()
     r = ratelimit.get_ratelimit(group="test_block_empty",
                                 rate="1/s",
                                 key="user",
                                 request=request,
                                 empty_to=123)
     self.assertEqual(r["request_limit"], 123)
Пример #9
0
 def test_inverted(self):
     request = self.factory.get('/customer/details')
     r = ratelimit.get_ratelimit(group="test_inverted",
                                 rate="1/s",
                                 key="ip:32/64",
                                 inc=True,
                                 request=request,
                                 methods=ratelimit.invertedset(["GET"]))
     self.assertEqual(r["count"], 0)
Пример #10
0
 def test_bypass_empty(self):
     r = None
     request = self.factory.get('/customer/details')
     request.user = AnonymousUser()
     for i in range(0, 4):
         r = ratelimit.get_ratelimit(group="test_bypass_empty",
                                     rate="1/s",
                                     key="user",
                                     request=request,
                                     empty_to=0)
     self.assertEqual(r["request_limit"], 0)
Пример #11
0
 def test_window(self):
     # window should start with first inc and end after period
     # (fixed window counter algorithm)
     r = None
     for i in range(0, 2):
         r = ratelimit.get_ratelimit(group="test_window",
                                     rate="2/4s",
                                     key=b"abc",
                                     inc=True)
         self.assertEqual(r["request_limit"], 0)
         time.sleep(1)
     r = ratelimit.get_ratelimit(group="test_window",
                                 rate="2/4s",
                                 key=b"abc",
                                 inc=True)
     self.assertEqual(r["request_limit"], 1)
     # window times out
     time.sleep(3)
     r = ratelimit.get_ratelimit(group="test_window",
                                 rate="2/4s",
                                 key=b"abc",
                                 inc=True)
     self.assertEqual(r["request_limit"], 0)
Пример #12
0
    def test_request(self):
        r = None
        request = self.factory.get('/customer/details')
        for i in range(0, 4):
            r = ratelimit.get_ratelimit(group="test_request",
                                        rate="1/s",
                                        key="ip",
                                        request=request)
            self.assertEqual(r["request_limit"], 0)

        for i in range(0, 2):
            r = ratelimit.get_ratelimit(group="test_request",
                                        rate="1/s",
                                        key="ip:32/64",
                                        inc=True,
                                        request=request)
        self.assertEqual(r["request_limit"], 1)
        r = ratelimit.get_ratelimit(group="test_request",
                                    rate="1/s",
                                    key="ip",
                                    inc=True,
                                    request=request)
        self.assertEqual(r["request_limit"], 1)
Пример #13
0
 def auth(cls, request, obj, **kwargs):
     if not obj:
         return False
     if obj:
         temp = obj.data.get("rate_accessed", None)
         if temp and ratelimit.get_ratelimit(
                 request=request,
                 group="spider_ratelimit_accessed",
                 key=cls.count_access(request, obj),
                 rate=temp,
                 inc=True)["request_limit"] > 0:
             return False
         temp = obj.data.get("rate_static_token_error", None)
         if temp and ratelimit.get_ratelimit(
                 request=request,
                 group="spider_static_token_error",
                 key="user_or_ip",
                 rate=(int(temp), 3600),
                 inc=False)["request_limit"] > 0:
             return False
         temp = obj.data.get("rate_login_failed_ip", None)
         if temp and ratelimit.get_ratelimit(
                 request=request,
                 group="spider_login_failed_ip",
                 key="ip",
                 rate=(int(temp), 3600),
                 inc=False)["request_limit"] > 0:
             return False
         temp = obj.data.get("rate_login_failed_account", None)
         if temp and ratelimit.get_ratelimit(
                 request=request,
                 group="spider_login_failed_account",
                 key=lambda x, y: obj.usercomponent.username,
                 rate=(int(temp), 3600),
                 inc=False)["request_limit"] > 0:
             return False
     return 1
Пример #14
0
    def refer_with_post(self, context, token):
        # application/x-www-form-urlencoded is best here,
        # for beeing compatible to most webservers
        # client side rdf is no problem
        # NOTE: csrf must be disabled or use csrf token from GET,
        #       here is no way to know the token value

        h = hashlib.sha256(context["referrer"].encode("utf8")).hexdigest()

        def h_fun(*a):
            return h

        # rate limit on errors
        if ratelimit.get_ratelimit(request=self.request,
                                   group="refer_with_post.refer_with_post",
                                   key=h_fun,
                                   rate=settings.SPIDER_DOMAIN_ERROR_RATE,
                                   inc=False)["request_limit"] > 0:
            return HttpResponseRedirect(
                redirect_to=merge_get_url(context["referrer"],
                                          status="post_failed",
                                          error="error_rate_limit"))
        d = {
            "token": token.token,
            "hash_algorithm": settings.SPIDER_HASH_ALGORITHM.name,
            "action": context["action"],
        }
        if context["payload"] is not None:
            d["payload"] = context["payload"]
        params, inline_domain = get_requests_params(context["referrer"])
        if inline_domain:
            response = Client().post(
                context["referrer"],
                data=d,
                Connection="close",
                Referer=merge_get_url(
                    "%s%s" % (context["hostpart"], self.request.path)
                    # sending full url not required anymore, payload
                ),
                SERVER_NAME=inline_domain)
            if response.status_code != 200:
                return HttpResponseRedirect(redirect_to=merge_get_url(
                    context["referrer"], status="post_failed", error="other"))
        else:
            try:
                with requests.post(
                        context["referrer"],
                        data=d,
                        headers={
                            "Referer":
                            merge_get_url(
                                "%s%s" %
                                (context["hostpart"], self.request.path)
                                # sending full url not required anymore, payload
                            ),
                            "Connection":
                            "close"
                        },
                        **params) as resp:
                    resp.raise_for_status()
            except requests.exceptions.SSLError as exc:
                logger.info("referrer: \"%s\" has a broken ssl configuration",
                            context["referrer"],
                            exc_info=exc)
                return HttpResponseRedirect(redirect_to=merge_get_url(
                    context["referrer"], status="post_failed", error="ssl"))
            except (Exception, requests.exceptions.HTTPError) as exc:
                apply_error_limit = False
                if isinstance(exc, (requests.exceptions.ConnectionError,
                                    requests.exceptions.Timeout)):
                    apply_error_limit = True
                elif (isinstance(exc, requests.exceptions.HTTPError)
                      and exc.response.status_code >= 500):
                    apply_error_limit = True
                if apply_error_limit:
                    ratelimit.get_ratelimit(
                        request=self.request,
                        group="refer_with_post",
                        key=h_fun,
                        rate=settings.SPIDER_DOMAIN_ERROR_RATE,
                        inc=True)
                logger.info("post failed: \"%s\" failed",
                            context["referrer"],
                            exc_info=exc)
                return HttpResponseRedirect(redirect_to=merge_get_url(
                    context["referrer"], status="post_failed", error="other"))
        context["post_success"] = True
        h = get_hashob()
        h.update(token.token.encode("utf-8", "ignore"))
        return HttpResponseRedirect(redirect_to=merge_get_url(
            context["referrer"], status="success", hash=h.finalize().hex()))