Skip to main content

CloudFlare Challenge pages

Project description

CloudFlare-Challenge

Ensure that we can do a cloudflare challenge in flask

Rationale

If you Flask server is behind a CloudFlare wall then any upload of data may provoke a "challenge" of the "I'm not a robot" kind.

Instead of returning the response to your browser query, CloudFlare sends back an html page with a 403 HTTP status which will interogate your browser internals and leave a cookie cf_clearance -- if you "pass" the challenge!.

This is of course a disaster if you have used Ajax to send the request.

The idea here is to get that sweet, sweet CloudFlare cookie cf_clearance as soon as possible or at least before you do any ajax requests.

Basically if there is no cf_clearance cookie for a request this Blueprint will redirect to a "managed" page where it will automatically upload an image to provoke the CloudFlare challenge -- then check for success.

Once your browser has the cf_clearance cookie then CloudFlare-Challenge will leave your app alone.

This "solution" is not ideal but it maybe better than weird failures of your ajax requests that will ultimately confuse/anger your users.

The big assumption here is that an upload of an image will provoke the CloudFlare challenge. If it doesn't then don't use this package!

Configuration

You will need to set 1-5 configuration variables

# path to a static image (required) e.g:
CF_IMAGE_FILENAME = "img/Three-pink-daisies.jpeg"
# endpoint to redirect to after challenge
CF_REDIRECT_TO = None
# template to inherit from. Defaults to one provided by cloudflare_challenge.
CF_MAIN_TEMPLATE = None
# list of endpoint prefixes that will be white/black listed
# can be just a string
CF_WHITE_LIST = ()
CF_BLACK_LIST = ()

If CF_IMAGE_FILENAME is missing or None then the blueprint will silently not be registered even if init_app is called. init_app is indempotent.

The image filename will be used by url_for('static', filename=CF_IMAGE_FILENAME) to generate a url. The image should be large enough to provoke a challenge. Choose an image that will already be cached in your brower such as a banner image in your flask landing page.

If you specify a template (CF_MAIN_TEMPLATE) it should have a content block (for html, this is where the iframe is blatted).

If CF_REDIRECT_TO is missing or None then steps will be taken to redirect back to the original page that prompted the redirection to the challenge page otherwise it will redirect back to /. Remember: CF_REDIRECT_TO expects a flask endpoint not a URL.

White listed endpoints won't trigger a check for CloudFlare cookies, headers etc. Use this for "static" images, css etc (the static endpoint is already white listed).

You can blacklist flask endpoints -- possibly endpoints that generate html with forms in them and thus might trigger the challenge.

The black list is checked first then the white list.

Either way, Ajax requests (with a X-Requested-With header) will not trigger the challenge page (no point really since this doesn't help -- too late!).

It is maybe the best to black list endpoints that generate html forms for the user to fill out, or any page that might send an ajax request due to user interaction. You will want to trigger the challenge before any Ajax/form upload is undertaken.

Usage

Basic usage

from flask import Flask
from cloudflare_challenge import init_app

app = Flask(__name__)
app.config.from_pyfile("config.py") # say
init_app(app, url_prefix='/someprefix')

Client Side

If you are using jQuery on a page to enable Ajax then you can ensure Challenges are detected by adding to your page:

    {% if cf_challenge is defined %}
    {{ cf_challenge(use_toastr=True) }}
    {% endif %}

Then Ajax challenges will be detected and logged.

If, in addition you set MAIL_SERVER and CF_MAIL_RECIPIENT, then cloudflare-challenge will attempt to send an email too.

If you only want this part then set CF_WHITE_LIST = '*'

Otherwise using fetch you need to check each response for cloudflare interference....

    function ok_with_cloudflare(resp) {
        const ok = resp.headers.get("cf-mitigated") !== "challenge"
        if (!ok && window.toastr) {
            toastr.error(
            `Cloudflare has issued a challenge to a request. To continue the challenge click
                    <a class="btn btn-outline-primary" href="{{url_for('cloudflare.challenge')}}" target="cloudflare">here</a>`,
            null,
            { timeOut: 0, closeButton: true, html: true }
            )
        }
        return ok
    }
    resp = fetch(some_url)
    if (ok_with_cloudflare(resp)) {
        // do something with response!
    }

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloudflare_challenge-0.1.8.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloudflare_challenge-0.1.8-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file cloudflare_challenge-0.1.8.tar.gz.

File metadata

File hashes

Hashes for cloudflare_challenge-0.1.8.tar.gz
Algorithm Hash digest
SHA256 fee076b11182f973ddc8aca7fd7d201621f1a7930d1d55a71c9e7375a27105de
MD5 d6e14f0eb6c3267c8d6cab5e00c85c62
BLAKE2b-256 7b995e4d10d97be22d70c55e44491c2a42c6f8c3e8d0d0acda1b16b6b89a3938

See more details on using hashes here.

File details

Details for the file cloudflare_challenge-0.1.8-py3-none-any.whl.

File metadata

File hashes

Hashes for cloudflare_challenge-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 db3160230aaed7a27bfc2e2df6739e682b9df3c71082db9adfecbc197c970b63
MD5 e28819f1584bc280a859c5dc0e364d78
BLAKE2b-256 ae1cac4acbe67902b0acc7eb5c5b4ddd4b7b36e06f0f068cb7facc10784ddbb8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page