Dealing with CloudFlare's: cf_chl_jschl_tk & cf_chl_captcha_tk?
Asked Answered
I

2

11

The problem:

When my website is set to "I'm under attack" mode, once a user passes the CloudFlare screen they are redirected to my website with a large, and rather long query get parameter:

?__cf_chl_jschl_tk__=63c51316f61a63e46f1639d6cf43f9d9b536adea-1587754610-0-AV-peahelegQeMeSrc_4ZJBUq47gdkX_QiS2eERoRTEODUjwbib2MM_73nQDAhukLbkspNpj01mv-Z-JteR4MpY4LUMm-yLJrPQKTX74DGYbZIs2utbp3_q4uozgzKpqcax10YESVKDhZgaWQYHGqBL9koIoasVOzKyvU7VQuKT1Nieo-i8DdXrV0IQf-nyI8KgWnxhYSVBOc-4WNrZzHQlEXFOpV45AGs10aMJyrs376HLRhNdV05MCj8oqMrexuQDtY7B3p7riHByYdB7GIgc

enter image description here

Why this is bad:

  • Ugly link shared around online - (I have seen this happen a few times already)
  • I cannot redirect the get parameters away - (They are not accessible to check if set to redirect away)
  • Ugly urls - (We spend lots of time writing clean/pretty urls for our applications)
  • POST data is set on the page - (you cannot refresh without 'resubmitting' the CF authentication)

Proposed solution:

The way I see to avoid this would be to check if the get parameters are set and then redirect back to the same page with the parameters removed. (Making sure not to lose any other query parameters if set)

I have written a function to achieve this:

function checkAndRemoveCloudFlareParams() {
    if (isset($_GET['__cf_chl_jschl_tk__']) && ! empty($_GET['__cf_chl_jschl_tk__'])
     || isset($_GET['__cf_chl_captcha_tk__']) && ! empty($_GET['__cf_chl_captcha_tk__'])) {

        $new_uri = '?';
        $uri = explode('?', $_SERVER['REQUEST_URI']);
        $uri = $uri[0];

        // Get any other params to put back on later
        foreach ($_GET as $key => $var) {
            if ($key !== '__cf_chl_jschl_tk__' && $key !== '__cf_chl_captcha_tk__') {
                $new_uri .= $key . '=' . $var . '&';
            }
        }

        if ($new_uri !== '?') {
            $new_uri = rtrim($new_uri, '&');
            $uri .= $new_uri;
        }

        header('Location: ' . $uri);
        die;
    }
}

When I test this locally by manually entering the _GET parameters it works. However when deployed up to my live site, the _GET query parameters are not there or available to access when loaded directly from CloudFlare. I believe CloudFlare adds the parameters after the page has been loaded? Maybe through Javascript push states(?) Has anyone else dealt with this before?

I have spoken to CloudFlare about this already and they said this is how it will work from now on as there were problems with their old system. Unfortunately these query parameters are very ugly and are making me start to twitch from annoyance of seeing it all the time ;)

Any advice on how to deal with these params and get rid of them? Kind regards

Insolent answered 24/4, 2020 at 19:16 Comment(0)
G
6

JS solution:

(function(){
    var reg = /[\?&](__cf_chl_jschl_tk__|__cf_chl_captcha_tk__|__cf_chl_managed_tk__|__cf_chl_tk)=[^&]+/
    history.replaceState && reg.test(location.search) && history.replaceState(
      null, '', location.pathname + location.search.replace(reg, '').replace(/^&/, '?') + location.hash
    );
})();

Updated in 2022 to deal with What exactly is the `#:~:text=` location hash in an URL? because it is not present in location.hash

Grenadine answered 19/9, 2020 at 16:22 Comment(0)
D
6

Cloudflare is a distributed reverse proxy. All your requests and responses are transmitted through the Cloudflare's reverse proxy in cleartext. The __cf_chl_jschl_tk__ (Cloudflare challenge / Javascript challenge token) is added to the redirect location URLs at the proxy and would be stripped at the proxy before it gets to your website.

You may try to get rid of the token with Javascript, however, it's important to understand the consequences. If a token is missing in a request, Cloudflare would be more likely to run your users through anti-bot challenges again and again, leading to poor user experience.

How exactly likely it would be to do that remains a mystery though, because DDoS mitigation services do not typically openly document those details.

Delisle answered 27/4, 2020 at 16:32 Comment(1)
The query parameters are only added on the first load after the CF Challenge page. After that, you are free to navigate to any page where no query parameters are added/required. All I need to do is detect when a user has been authenticated with CloudFlare and remove the query params with a redirect. It just doesn't seem to be possible to detect when. Thanks for your replyInsolent
G
6

JS solution:

(function(){
    var reg = /[\?&](__cf_chl_jschl_tk__|__cf_chl_captcha_tk__|__cf_chl_managed_tk__|__cf_chl_tk)=[^&]+/
    history.replaceState && reg.test(location.search) && history.replaceState(
      null, '', location.pathname + location.search.replace(reg, '').replace(/^&/, '?') + location.hash
    );
})();

Updated in 2022 to deal with What exactly is the `#:~:text=` location hash in an URL? because it is not present in location.hash

Grenadine answered 19/9, 2020 at 16:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.