
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Tue, 14 Apr 2026 21:39:22 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Integrating Turnstile with the Cloudflare WAF to challenge fetch requests]]></title>
            <link>https://blog.cloudflare.com/integrating-turnstile-with-the-cloudflare-waf-to-challenge-fetch-requests/</link>
            <pubDate>Mon, 18 Dec 2023 14:00:17 GMT</pubDate>
            <description><![CDATA[ By editing or creating a new Turnstile widget with “Pre-Clearance” enabled, Cloudflare customers can now use Turnstile to issue a challenge when a page’s HTML loads, and enforce that all valid responses have a valid Turnstile token ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3UV6CnIMI92jBmCr4VeqCU/98b0de9d9ca221f3d60bc7d02213264c/image8.png" />
            
            </figure><p>Two months ago, we made Cloudflare Turnstile <a href="/turnstile-ga/">generally available</a> — giving website owners everywhere an easy way to fend off bots, without ever issuing a CAPTCHA. Turnstile allows any website owner to embed a frustration-free Cloudflare challenge on their website with a simple code snippet, making it easy to help ensure that only human traffic makes it through. In addition to protecting a website’s frontend, Turnstile also empowers web administrators to harden browser-initiated (AJAX) API calls running under the hood. These APIs are commonly used by dynamic single-page web apps, like those created with React, Angular, Vue.js.</p><p>Today, we’re excited to announce that we have integrated Turnstile with the <a href="https://www.cloudflare.com/application-services/products/waf/">Cloudflare Web Application Firewall (WAF)</a>. This means that web admins can add the Turnstile code snippet to their websites, and then configure the Cloudflare WAF to manage these requests. This is completely customizable using WAF Rules; for instance, you can allow a user authenticated by Turnstile to interact with all of an application’s API endpoints without facing any further challenges, or you can configure certain sensitive endpoints, like Login, to always issue a challenge.</p>
    <div>
      <h3>Challenging fetch requests in the Cloudflare WAF</h3>
      <a href="#challenging-fetch-requests-in-the-cloudflare-waf">
        
      </a>
    </div>
    <p>Millions of websites protected by Cloudflare’s WAF leverage our JS Challenge, Managed Challenge, and Interactive Challenge to stop bots while letting humans through. For each of these challenges, Cloudflare intercepts the matching request and responds with an HTML page rendered by the browser, where the user completes a basic task to demonstrate that they’re human. When a user successfully completes a challenge, they receive a <a href="https://developers.cloudflare.com/fundamentals/reference/policies-compliances/cloudflare-cookies/#additional-cookies-used-by-the-challenge-platform">cf_clearance cookie</a>, which tells Cloudflare that a user has successfully passed a challenge, the type of challenge, and when it was completed. A clearance cookie can’t be shared between users, and is only valid for the time set by the Cloudflare customer in their Security Settings dashboard.</p><p>This process works well, except when a browser receives a challenge on a fetch request and the browser has not previously passed a challenge. On a fetch request, or an XML HTTP Request (XHR), the browser expects to get back simple text (in JSON or XML formats) and cannot render the HTML necessary to run a challenge.</p><p>As an example, let’s imagine a pizzeria owner who built an online ordering form in React with a payment page that submits data to an API endpoint that processes payments. When a user views the web form to add their credit card details they can pass a Managed Challenge, but when the user submits their credit card details by making a fetch request, the browser won’t execute the code necessary for a challenge to run. The pizzeria owner’s only option for handling suspicious (but potentially legitimate) requests is to block them, which runs the risk of false positives that could cause the restaurant to lose a sale.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7fOg2KPmEgB5nyeywCc0X0/8ddf84d382f902ad633fb30a3f8226a2/Group-3955.png" />
            
            </figure><p>This is where Turnstile can help. Turnstile allows anyone on the Internet to embed a Cloudflare challenge anywhere on their website. Before today, the output of Turnstile was only a one-time use token. To enable customers to issue challenges for these fetch requests, Turnstile can now issue a clearance cookie for the domain that it's embedded on. Customers can issue their challenge within the HTML page before a fetch request, <i>pre-clearing</i> the visitor to interact with the Payment API.</p>
    <div>
      <h3>Turnstile Pre-Clearance mode</h3>
      <a href="#turnstile-pre-clearance-mode">
        
      </a>
    </div>
    <p>Returning to our pizzeria example, the three big advantages of using Pre-Clearance to integrate Turnstile with the Cloudflare WAF are:</p><ol><li><p><b>Improved user experience</b>: Turnstile’s embedded challenge can run in the background while the visitor is entering their payment details.</p></li><li><p><b>Blocking more requests at the edge</b>: Because Turnstile now issues a clearance cookie for the domain that it’s embedded on, our pizzeria owner can use a Custom Rule to issue a Managed Challenge for every request to the payment API. This ensures that automated attacks attempting to target the payment API directly are stopped by Cloudflare before they can reach the API.</p></li><li><p><b>(Optional) Securing the action and the user</b>: No backend code changes are necessary to get the benefit of Pre-Clearance. However, further Turnstile integration will increase security for the integrated API. The pizzeria owner can adjust their payment form to <a href="https://developers.cloudflare.com/turnstile/get-started/server-side-validation/">validate the received Turnstile token</a>, ensuring that every payment attempt is individually validated by Turnstile to protect their payment endpoint from session hijacking.</p></li></ol>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1Er3Qa9TvxheeCOxbYeCQh/50afffa59cef839aba3a256484ea6ea5/Pre-clearance.png" />
            
            </figure><p>A Turnstile widget with Pre-Clearance enabled will still issue turnstile tokens, which gives customers the flexibility to decide if an endpoint is critical enough to require a security check on every request to it, or just once a session. Clearance cookies issued by a Turnstile widget are automatically applied to the Cloudflare zone the Turnstile widget is embedded on, with no configuration necessary. The clearance time the token is valid for is still controlled by the zone specific “Challenge Passage” time.</p>
    <div>
      <h3>Implementing Turnstile with Pre-Clearance</h3>
      <a href="#implementing-turnstile-with-pre-clearance">
        
      </a>
    </div>
    <p>Let’s make this concrete by walking through a basic implementation. Before we start, we’ve set up a simple demo application where we emulate a frontend talking to a backend on a <code>/your-api</code> endpoint.</p><p>To this end, we have the following code:</p>
            <pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
   &lt;title&gt;Turnstile Pre-Clearance Demo &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;main class="pre-clearance-demo"&gt;
    &lt;h2&gt;Pre-clearance Demo&lt;/h2&gt;
    &lt;button id="fetchBtn"&gt;Fetch Data&lt;/button&gt;
    &lt;div id="response"&gt;&lt;/div&gt;
&lt;/main&gt;

&lt;script&gt;
  const button = document.getElementById('fetchBtn');
  const responseDiv = document.getElementById('response');
  button.addEventListener('click', async () =&gt; {
  try {
    let result = await fetch('/your-api');
    if (result.ok) {
      let data = await result.json();
      responseDiv.textContent = JSON.stringify(data);
    } else {
      responseDiv.textContent = 'Error fetching data';
    }
  } catch (error) {
    responseDiv.textContent = 'Network error';
  }
});
&lt;/script&gt;</code></pre>
            <p>We've created a button. Upon clicking, Cloudflare makes a <code>fetch()</code> request to the <code>/your-api</code> endpoint, showing the result in the response container.</p><p>Now let’s consider that we have a Cloudflare WAF rule set up that protects the <code>/your-api</code> endpoint with a Managed Challenge.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1sjpmlJe4atSe3ztUjbL2M/99335880b870554a9c1dd3e5c8d70614/pasted-image-0-3.png" />
            
            </figure><p>Due to this rule, the app that we just wrote is going to fail for the reason described earlier (the browser is expecting a JSON response, but instead receives the challenge page as HTML).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4HJrHiNoxjmSdRwEcZrYuA/a62895eaa382e160eb17fce51acde32c/Screenshot-2023-12-18-at-12.00.16.png" />
            
            </figure><p>If we inspect the Network Tab, we can see that the request to <code>/your-api</code> has been given a 403 response.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2DiC7Lus2CVxUJKw5pr7mi/ab45a3af70f411998ebb4892977a255d/image10.png" />
            
            </figure><p>Upon inspection, the Cf-Mitigated header shows that the response was challenged by Cloudflare’s firewall, as the visitor has not solved a challenge before.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2D81qpEEa60G1W1pZMUr2U/f04a2571ed6f52a16f6bf28adaee9ee4/image6.png" />
            
            </figure><p>To address this problem in our app, we set up a Turnstile Widget in Pre-Clearance mode for the Turnstile sitekey that we want to use.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6xLOm4TvNFK32gEf45I1XF/7e04c0a1fdc746a64dc8cf1e08ec3bf1/image2-4.png" />
            
            </figure><p>In our application, we override the <code>fetch()</code> function to invoke Turnstile once a Cf-Mitigated response has been received.</p>
            <pre><code>&lt;script&gt;
turnstileLoad = function () {
  // Save a reference to the original fetch function
  const originalFetch = window.fetch;

  // A simple modal to contain Cloudflare Turnstile
  const overlay = document.createElement('div');
  overlay.style.position = 'fixed';
  overlay.style.top = '0';
  overlay.style.left = '0';
  overlay.style.right = '0';
  overlay.style.bottom = '0';
  overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
  overlay.style.border = '1px solid grey';
  overlay.style.zIndex = '10000';
  overlay.style.display = 'none';
  overlay.innerHTML =       '&lt;p style="color: white; text-align: center; margin-top: 50vh;"&gt;One more step before you proceed...&lt;/p&gt;&lt;div style=”display: flex; flex-wrap: nowrap; align-items: center; justify-content: center;” id="turnstile_widget"&gt;&lt;/div&gt;';
  document.body.appendChild(overlay);

  // Override the native fetch function
  window.fetch = async function (...args) {
      let response = await originalFetch(...args);

      // If the original request was challenged...
      if (response.headers.has('cf-mitigated') &amp;&amp; response.headers.get('cf-mitigated') === 'challenge') {
          // The request has been challenged...
          overlay.style.display = 'block';

          await new Promise((resolve, reject) =&gt; {
              turnstile.render('#turnstile_widget', {
                  'sitekey': ‘YOUR_TURNSTILE_SITEKEY',
                  'error-callback': function (e) {
                      overlay.style.display = 'none';
                      reject(e);
                  },
                  'callback': function (token, preClearanceObtained) {
                      if (preClearanceObtained) {
                          // The visitor successfully solved the challenge on the page. 
                          overlay.style.display = 'none';
                          resolve();
                      } else {
                          reject(new Error('Unable to obtain pre-clearance'));
                      }
                  },
              });
          });

          // Replay the original fetch request, this time it will have the cf_clearance Cookie
          response = await originalFetch(...args);
      }
      return response;
  };
};
&lt;/script&gt;
&lt;script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=turnstileLoad" async defer&gt;&lt;/script&gt;</code></pre>
            <p>There is a lot going on in the snippet above: First, we create a hidden overlay element and override the browser’s <code>fetch()</code> function. The <code>fetch()</code> function is changed to introspect the Cf-Mitigated header for ‘challenge’. If a challenge is issued, the initial result will be unsuccessful; instead, a Turnstile overlay (with Pre-Clearance enabled) will appear in our web application. Once the Turnstile challenge has been completed we will retry the previous request after Turnstile has obtained the cf_clearance cookie to get through the Cloudflare WAF.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1HNSoEaOmTMmQFuc8kKY2p/1877b884856e092cfc51637f3f050c2c/image1-2.png" />
            
            </figure><p>Upon solving the Turnstile widget, the overlay disappears, and the requested API result is shown successfully:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7aPtaSfD7JdV0jYb1iDX50/dd9807c4807f6234dcb453471f43db99/Screenshot-2023-12-18-at-12.02.56.png" />
            
            </figure>
    <div>
      <h3>Pre-Clearance is available to all Cloudflare customers</h3>
      <a href="#pre-clearance-is-available-to-all-cloudflare-customers">
        
      </a>
    </div>
    <p>Every Cloudflare user with a <a href="https://www.cloudflare.com/plans/free/">free plan</a> or above can use Turnstile in managed mode free for an unlimited number of requests. If you’re a Cloudflare user looking to improve your security and user experience for your critical API endpoints, head over to our dashboard and <a href="https://dash.cloudflare.com/?to=/:account/turnstile">create a Turnstile widget with Pre-Clearance</a> today.</p> ]]></content:encoded>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[CAPTCHA]]></category>
            <category><![CDATA[Bots]]></category>
            <category><![CDATA[Turnstile]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Micro-frontends]]></category>
            <guid isPermaLink="false">1aYnXBUBD1B2KvKgz0veFW</guid>
            <dc:creator>Adam Martinetti</dc:creator>
            <dc:creator>Benedikt Wolters</dc:creator>
            <dc:creator>Miguel de Moura</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing Turnstile, a user-friendly, privacy-preserving alternative to CAPTCHA]]></title>
            <link>https://blog.cloudflare.com/turnstile-private-captcha-alternative/</link>
            <pubDate>Wed, 28 Sep 2022 13:01:00 GMT</pubDate>
            <description><![CDATA[ Any website can use a simple API to replace CAPTCHAs with our invisible alternative, whether they’re on the Cloudflare network or not. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Today, we’re announcing the open beta of Turnstile, an invisible <a href="https://www.cloudflare.com/products/turnstile/">alternative to CAPTCHA</a>. Anyone, anywhere on the Internet, who wants to replace CAPTCHA on their site will be able to call a simple API, without having to be a Cloudflare customer or sending traffic through the Cloudflare global network. <a href="http://www.cloudflare.com/lp/turnstile/">Sign up here for free</a>.</p><p>There is no point in rehashing the fact that CAPTCHA provides a terrible user experience. It's been discussed in detail before <a href="/moving-from-recaptcha-to-hcaptcha/">on this blog</a>, and countless times elsewhere. The creator of the CAPTCHA has even publicly lamented that he “unwittingly created a system that was <a href="https://thewalrus.ca/human-resources/">frittering away, in ten-second increments, millions of hours</a> of a most precious resource: human brain cycles.” We hate it, you hate it, everyone hates it. Today we’re giving everyone a better option.</p><div></div><p>Turnstile is our smart CAPTCHA alternative. It automatically chooses from a rotating suite of non-intrusive browser challenges based on telemetry and client behavior exhibited during a session. We talked in an earlier post about how we’ve <a href="/end-cloudflare-captcha/">used our Managed Challenge system to reduce our use of CAPTCHA by 91%</a>. Now anyone can take advantage of this same technology to stop using CAPTCHA on their own site.</p>
    <div>
      <h3>UX isn’t the only big problem with CAPTCHA — so is privacy</h3>
      <a href="#ux-isnt-the-only-big-problem-with-captcha-so-is-privacy">
        
      </a>
    </div>
    <p>While having to solve a CAPTCHA is a frustrating user experience, there is also a potential hidden tradeoff a website must make when using CAPTCHA. If you are a small site using CAPTCHA today, you essentially have one option: an 800 pound gorilla with <a href="https://trends.builtwith.com/widgets/captcha">98% of the CAPTCHA</a> market share. This tool is free to use, but in fact it has a privacy cost: you have to give your data to an ad sales company.</p><p>According to security researchers, one of the signals that Google uses to decide if you are malicious is whether you have a Google cookie in your browser, and if you have this cookie, Google <a href="https://web.archive.org/web/20220826231627/https://www.fastcompany.com/90369697/googles-new-recaptcha-has-a-dark-side">will give you a higher score</a>. Google says they don’t use this information for ad targeting, but at the end of the day, Google is an ad sales company. Meanwhile, at Cloudflare, we make money when customers choose us to <a href="https://www.cloudflare.com/security/">protect their websites</a> and make their services run better. It's a simple, direct relationship that perfectly aligns our incentives.</p>
    <div>
      <h3>Less data collection, more privacy, same security</h3>
      <a href="#less-data-collection-more-privacy-same-security">
        
      </a>
    </div>
    <p>In June, we announced an effort <a href="/eliminating-captchas-on-iphones-and-macs-using-new-standard/">with Apple to use Private Access Tokens</a>. Visitors using operating systems that support these tokens, including the upcoming versions of macOS or iOS, can now prove they’re human without completing a CAPTCHA or giving up personal data.</p><p>By collaborating with third parties like device manufacturers, who already have the data that would help us validate a device, we are able to abstract portions of the validation process, and confirm data without actually collecting, touching, or storing that data ourselves. Rather than interrogating a device directly, we ask the device vendor to do it for us.</p><p>Private Access Tokens are built directly into Turnstile. While Turnstile has to look at some session data (like headers, user agent, and browser characteristics) to validate users without challenging them, Private Access Tokens allow us to minimize data collection by asking Apple to validate the device for us. In addition, Turnstile never looks for <a href="https://www.cloudflare.com/learning/privacy/what-are-cookies/">cookies</a> (like a login cookie), or uses cookies to collect or store information of any kind. Cloudflare has a <a href="/next-generation-privacy-protocols/">long</a> track <a href="/announcing-the-results-of-the-1-1-1-1-public-dns-resolver-privacy-examination/">record</a> of <a href="/certifying-our-commitment-to-your-right-to-information-privacy/">investing</a> in <a href="/zaraz-privacy-features-in-response-to-cnil/">user privacy</a>, which we will continue with Turnstile.</p>
    <div>
      <h3>We are opening our CAPTCHA replacement to everyone</h3>
      <a href="#we-are-opening-our-captcha-replacement-to-everyone">
        
      </a>
    </div>
    <p>To improve the Internet for everyone, we decided to open up the technology that powers our <a href="/end-cloudflare-captcha/">Managed Challenge</a> to everyone in beta as a standalone product called Turnstile.</p><p>Rather than try to unilaterally deprecate and replace CAPTCHA with a single alternative, we built a platform to test many alternatives and rotate new challenges in and out as they become more or less effective. With Turnstile, we adapt the actual challenge outcome to the individual visitor/browser. First we run a series of small non-interactive JavaScript challenges gathering more signals about the visitor/browser environment. Those challenges include proof-of-work, proof-of-space, probing for web APIs, and various other challenges for detecting browser-quirks and human behavior. As a result, we can fine-tune the difficulty of the challenge to the specific request.</p><p>Turnstile also includes <a href="https://www.cloudflare.com/learning/ai/what-is-machine-learning/">machine learning models</a> that detect common features of end visitors who were able to pass a challenge before. The computational hardness of those initial challenges may vary by visitor, but is targeted to run fast.</p>
    <div>
      <h3>Swap out your existing CAPTCHA in a few minutes</h3>
      <a href="#swap-out-your-existing-captcha-in-a-few-minutes">
        
      </a>
    </div>
    <p>You can take advantage of Turnstile and stop bothering your visitors with a CAPTCHA even without being on the <a href="https://www.cloudflare.com/network/">Cloudflare network</a>. While we make it as easy as possible to use our network, we don't want this to be a barrier to improving privacy and user experience.</p><p>To switch from a CAPTCHA service, all you need to do is:</p><ol><li><p><a href="https://dash.cloudflare.com/?to=/:account/turnstile">Create a Cloudflare account</a>, navigate to the `Turnstile` tab on the navigation bar, and get a sitekey and secret key.</p></li><li><p>Copy our JavaScript from the dashboard and paste over your old CAPTCHA JavaScript.</p></li><li><p>Update the server-side integration by replacing the old siteverify URL with ours.</p></li></ol><p>There is more detail on the process below, including options you can configure, but that’s really it. We’re excited about the simplicity of making a change.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2o1JdkC5Dh44zULVVl4ktw/0ebbef92b61e7f1707232f06997be24e/image2-55.png" />
            
            </figure>
    <div>
      <h3>Deployment options and analytics</h3>
      <a href="#deployment-options-and-analytics">
        
      </a>
    </div>
    <p>To use Turnstile, first create an account and get your site and secret keys.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3FAcI6beB4iWixsqmoJmeQ/05817ed2836d5aec236250669111f0d8/image3-39.png" />
            
            </figure><p>Then, copy and paste our HTML snippet:</p><p><code>&lt;script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer&gt;&lt;/script&gt;</code></p><p>Once the script is embedded, you can use implicit rendering. Here, the HTML is scanned for elements that have a <code>cf-turnstile</code> class:</p>
            <pre><code>&lt;form action="/login" method="POST"&gt;
  &lt;div class="cf-turnstile" data-sitekey="yourSiteKey"&gt;&lt;/div&gt;
  &lt;input type="submit"&gt;
&lt;/form&gt;</code></pre>
            <p>Once a challenge has been solved, a token is injected in your form, with the name <code>cf-turnstile-response</code>. This token can be used with our <code>siteverify</code> endpoint to validate a challenge response. A token can only be validated once, and a token cannot be redeemed twice. The validation can be done on the server side or even in the cloud, for <a href="https://demo.turnstile.workers.dev/">example</a> using a simple Workers fetch (<a href="https://github.com/cloudflare/turnstile-demo-workers">see a demo here</a>):</p>
            <pre><code>async function handleRequest() {
    // ... Receive token
    let formData = new FormData();
    formData.append('secret', turnstileISecretKey);
    formData.append('response', receivedToken);
 
    await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify',
        {
            body: formData,
            method: 'POST'
        });
    // ...
}</code></pre>
            <p>For more complex use cases, the challenge can be invoked explicitly via JavaScript:</p>
            <pre><code>&lt;script&gt;
    window.turnstileCallbackFunction = function () {
        const turnstileOptions = {
            sitekey: 'yourSitekey',
            callback: function(token) {
                console.log(`Challenge Success: ${token}`);
            }
        };
        turnstile.render('#container', turnstileOptions);
    };
&lt;/script&gt;
&lt;div id="container"&gt;&lt;/div&gt;</code></pre>
            <p>You can also create what we call 'Actions'. Custom labels that allow you to distinguish between different pages where you're using Turnstile, like a login, checkout, or account creation page.</p><p>Once you’ve deployed Turnstile, you can go back to the dashboard and see analytics on where you have widgets deployed, how users are solving them, and view any defined actions.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4wP8P97T96SukNsOdZ6pnn/eea084506bef00ee817db94750bde22a/image1-64.png" />
            
            </figure>
    <div>
      <h3>Why are we giving this away for free?</h3>
      <a href="#why-are-we-giving-this-away-for-free">
        
      </a>
    </div>
    <p>While this is sometimes hard for people outside to believe, helping build a better Internet truly is <a href="https://www.cloudflare.com/careers/people/#:~:text=%E2%80%9CCloudflare's%20mission%20is%20to%20help,quantum%20algorithms%20at%20Cloudflare%20scale.%E2%80%9D">our mission</a>. This isn’t the first time we’ve built <a href="/1111-warp-better-vpn/">free tools</a> that we think will <a href="/announcing-1111/">make the Internet better</a>, and it won’t be the last. It's really important to us.</p><p>So whether or not you’re a Cloudflare customer today, if you’re using a CAPTCHA, try Turnstile for free, instead. You’ll make your users happier, and minimize the data you send to third parties.</p><p>Visit <a href="http://www.cloudflare.com/lp/turnstile/">this page</a> to sign up for the best invisible, privacy-first, CAPTCHA replacement and to retrieve your Turnstile beta sitekey.</p><p>If you want to read more, refer to our <a href="https://developers.cloudflare.com/turnstile/">documentation</a>.</p><p>
</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Turnstile]]></category>
            <category><![CDATA[CAPTCHA]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Bots]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Free]]></category>
            <guid isPermaLink="false">2EwI6qWhe8xClQaOJd1GP8</guid>
            <dc:creator>Reid Tatoris</dc:creator>
            <dc:creator>Benedikt Wolters</dc:creator>
            <dc:creator>Maxime Guerreiro</dc:creator>
            <dc:creator>Miguel de Moura</dc:creator>
        </item>
        <item>
            <title><![CDATA[Using HPKE to Encrypt Request Payloads]]></title>
            <link>https://blog.cloudflare.com/using-hpke-to-encrypt-request-payloads/</link>
            <pubDate>Fri, 19 Feb 2021 12:00:00 GMT</pubDate>
            <description><![CDATA[ Allowing users to securely log parts of the request that match firewall rules while making it impossible for anyone else to decrypt. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>The Managed Rules team was recently given the task of allowing Enterprise users to <a href="/encrypt-waf-payloads-hpke/">debug Firewall Rules</a> by viewing the part of a request that matched the rule. This makes it easier to determine what specific attacks a rule is stopping or why a request was a false positive, and what possible refinements of a rule could improve it.</p><p>The fundamental problem, though, was how to securely store this debugging data as it may contain sensitive data such as personally identifiable information from submissions, cookies, and other parts of the request. We needed to store this data in such a way that <b>only</b> the user who is allowed to access it can do so. Even Cloudflare shouldn't be able to see the data, following our philosophy that any personally identifiable information that passes through our network is a <a href="/welcome-to-privacy-and-compliance-week/">toxic asset</a>.</p><p>This means we needed to encrypt the data in such a way that we can allow the user to decrypt it, but not Cloudflare. This means <a href="https://www.cloudflare.com/learning/ssl/how-does-public-key-encryption-work/">public key encryption</a>.</p><p>Now we needed to decide on which encryption algorithm to use. We came up with some questions to help us evaluate which one to use:</p><ul><li><p>What requirements do we have for the algorithm?</p></li><li><p>What language do we implement it in?</p></li><li><p>How do we make this as secure as possible for users?</p></li></ul><p>Here's how we made those decisions.</p>
    <div>
      <h3>Algorithm Requirements</h3>
      <a href="#algorithm-requirements">
        
      </a>
    </div>
    <p>While we knew we needed to use <a href="https://www.cloudflare.com/learning/ssl/how-does-public-key-encryption-work/">public key encryption</a>, we also needed to keep an eye on performance. This led us to select <a href="https://tools.ietf.org/html/draft-irtf-cfrg-hpke-06">Hybrid Public Key Encryption</a> (HPKE) early on as it has a best-of-both-worlds approach to using symmetric as well as public-key cryptography to increase performance. While these best-of-both-worlds schemes aren’t new [<a href="https://nacl.cr.yp.to/box.html">1</a>][<a href="https://github.com/google/tink">2</a>][<a href="https://age-encryption.org/">3</a>], HPKE aims to provide a single, future-proof, robust, interoperable combination of a general key encapsulation mechanism and a symmetric encryption algorithm.</p><p>HPKE is an emerging standard developed by the Crypto Forum Research Group (CFRG), the research body that supports the development of Internet standards at the <a href="http://ietf.org">IETF. The CFRG</a> produces specifications called RFCs (such as <a href="https://tools.ietf.org/html/rfc7748">RFC 7748</a> for elliptic curves) that are then used in higher level protocols including two we talked about previously: <a href="/oblivious-dns/">ODoH</a> and <a href="/encrypted-client-hello/">ECH</a>. Cloudflare has long been a supporter of Internet standards, so HPKE was a natural choice to use for this feature. Additionally, HPKE was co-authored by one of our colleagues at Cloudflare.</p>
    <div>
      <h3>How HPKE Works</h3>
      <a href="#how-hpke-works">
        
      </a>
    </div>
    <p>HPKE combines an asymmetric algorithm such as <a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman">elliptic curve Diffie-Hellman</a> and a symmetric cipher such as AES. One of the upsides of HPKE is that the algorithms aren't dictated to the implementer, but making a combination that’s <a href="https://en.wikipedia.org/wiki/Provable_security#In_cryptography">provably secure</a> and meets the developer’s intuitive notions of security is important. All too often developers reach for a scheme without carefully understanding what it does, resulting in security vulnerabilities.</p><p>HPKE solves these problems by providing a high level of security in a generic manner and providing necessary hooks to tie messages to the context in which they are generated. This is the application of decades of research into the correct security notions and schemes.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/d6wSZdRKA3sg9R7181Rc3/6f61f19999611103d51ee2f394caa00d/image2-13.png" />
            
            </figure><p>HPKE is built in stages. First it turns a Diffie-Hellman key agreement into a Key Encapsulation Mechanism. A key encapsulation mechanism has two algorithms: Encap and Decap. The Encap algorithm creates a symmetric secret and wraps it in a public key, so that only the holder of the private key can unwrap it. An attacker with the encapsulation cannot recover the random key. Decap takes the encapsulation and the private key associated to the public key, and computes the same random key. This translation gives HPKE the flexibility to work almost unchanged with any kind of public key encryption or key agreement algorithm.</p><p>HPKE mixes this key with an optional info argument, as well as information relating to the cryptographic parameters used by each side. This ensures that attackers cannot modify messages’ meaning by taking them out of context. A postcard marked “So happy to see you again soon” is ominous from the dentist and endearing from one’s grandmother.</p><p>The specification for HPKE is open and available on the <a href="https://tools.ietf.org/html/draft-irtf-cfrg-hpke-06">IETF website</a>. It is on its way to becoming an RFC after passing multiple rounds of review and analysis by cryptography experts at the CFRG. HPKE is already gaining adoption in IETF protocols like ODoH, ECH, and the new <a href="https://messaginglayersecurity.rocks/">Messaging Layer Security (MLS)</a> protocol. HPKE is also designed with the <a href="/securing-the-post-quantum-world/">post-quantum future</a> since it is built to work with any KEM, including <a href="https://csrc.nist.gov/News/2020/pqc-third-round-candidate-announcement">all the NIST finalists for post-quantum</a> public-key encryption.</p>
    <div>
      <h3>Implementation Language</h3>
      <a href="#implementation-language">
        
      </a>
    </div>
    <p>Once we had an encryption scheme selected, we needed to settle on an implementation. HPKE is still fairly new, so the libraries aren't quite mature yet. There is a <a href="https://github.com/cisco/go-hpke">reference implementation</a>, and we’re in the process of developing an implementation in Go as part of <a href="https://github.com/cloudflare/circl">CIRCL</a>. However, in the absence of a clear "go to" that is widely known to be the best, we decided to go with <a href="https://github.com/rozbb/rust-hpke">an implementation</a> leveraging the same language already powering much of the Firewall code running at the Cloudflare edge - <a href="/building-fast-interpreters-in-rust/">Rust</a>.</p><p>Aside from this, the language benefits from features like native primitives, and crucially the ability to easily compile to <a href="https://developer.mozilla.org/en-US/docs/WebAssembly">WebAssembly (WASM)</a>.</p><p>As we mentioned in a <a href="/encrypt-waf-payloads-hpke/">previous blog post</a>, customers are able to generate a key pair and decrypt payloads either from the dashboard UI or from a CLI. Instead of writing and maintaining two different codebases for these, we opted to reuse the same implementation across the edge component that encrypts the payloads and the UI and CLI that decrypt them. To achieve this we compile our library to target WASM so it can be used in the dashboard UI code that runs in the browser. While this approach may yield a slightly larger JavaScript bundle size and relatively small computational overhead, we found it preferable to spending a significant amount of time securely re-implementing HPKE using JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">WebCrypto</a> primitives.</p><p>The HPKE implementation we decided on comes with the caveat of not yet being formally audited, so we performed our own internal security review. We analyzed the cryptography primitives being used and the corresponding libraries. Between the composition of said primitives and secure programming practices like correctly zeroing memory and safe usage of random number generators, we found no security issues.</p>
    <div>
      <h3>Making It Secure For Users</h3>
      <a href="#making-it-secure-for-users">
        
      </a>
    </div>
    <p>To encrypt on behalf of users, we need them to provide us with a public key. To make this as easy as possible, we built a CLI tool along with the ability to do it right in the browser. Either option allows the user to generate a public/private key pair without needing to talk to Cloudflare servers at all.</p><p>In our API, we specifically do not accept the private key of the key pair — we don't want it! We don't need and don't want to be able to decrypt the data we're storing.</p><p>For the dashboard, once the user provides the private key for decryption, the key is held in a temporary JavaScript variable and used for the in-browser decryption. This allows the user to not constantly have to provide the key while browsing the Firewall event logs. The private key is also not persisted in any way in the browser, so any action that refreshes the page such as refreshing or navigating away will require the user to provide the key again. We believe this is an acceptable usability compromise for better security.</p>
    <div>
      <h3>How Payload Extraction Works</h3>
      <a href="#how-payload-extraction-works">
        
      </a>
    </div>
    <p>After deciding how to encrypt the data, we just had to figure out the rest of the feature: what data to encrypt, how to store and transmit it, and how to allow users to decrypt it.</p><p>When an HTTP request reaches the L7 Firewall, it is evaluated against a set of rulesets. Each of these rulesets contain several rules written in the <a href="https://github.com/cloudflare/wirefilter">wirefilter</a> syntax.</p><p>An example of one such rule would be:</p>
            <pre><code>http.request.version eq "HTTP/1.1"
and
(
    http.request.uri.path matches "\n+."
    or
    http.request.uri.query matches "\x00+."
)</code></pre>
            <p>This expression evaluates to a boolean “true” for HTTP/1.1 requests that either contain one or more newlines followed by a character in the request path or one or more NULL bytes followed by a character in the query string.</p><p>Say we had the following request that would match the rule above:</p>
            <pre><code>GET /cms/%0Aadmin?action=%00post HTTP/1.1
Host: example.com</code></pre>
            <p>If matched data logging is enabled, the rules that match would be executed again in a special context that tags all fields that are accessed during execution. We do this second execution because this tagging adds a noticeable computational overhead, and since the vast majority of requests don't trigger a rule at all we would be unnecessarily adding overhead to each request. Requests that do match any rules will only match a few rules as well, so we don't need to re-execute a large portion of the ruleset.</p><p>You may notice that although <code>http.request.uri.query matches "\x00+."</code> evaluates to <code>true</code> for this request, it won’t be executed, because the expression short-circuits with the first <code>or</code> condition that also matches. This results in only <code>http.request.version</code> and <code>http.request.uri.path</code> being tagged as accessed:</p>
            <pre><code>http.request.version -&gt; HTTP/1.1
http.request.uri.path -&gt; /cms/%0Aadmin</code></pre>
            <p>Having gathered the fields that were accessed, the Firewall engine does some post-processing; removing fields that are a subset of others (e.g., the query string and the full URI), or truncating fields that are beyond a certain character length.</p><p>Finally, these get serialized as JSON, encrypted with the customer's public key, serialized again as a set of bytes, and prefixed with a version number should we need to change/update it in the future. To simplify consumption of these blobs, our APIs display a base64 encoded version of the bytes:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3GszxT7kezPhIz3olZ7NRG/5e5468f1d414682c3279c9f427c92dfa/image3-8.png" />
            
            </figure><p>Now that we have encrypted the data at the edge and persisted it in <a href="/tag/clickhouse/">ClickHouse</a>, we need to allow users to decrypt it. As part of the setup of turning this feature on, users generated a key-pair: the public key which was used to encrypt the payloads and a private key which is used to decrypt them. Decryption is done completely offline via either the command line using <a href="https://github.com/cloudflare/matched-data-cli">cloudflare/matched-data-cli</a>:</p>
            <pre><code>$ MATCHED_DATA=AkjQDktMX4FudxeQhwa0UPNezhkgLAUbkglNQ8XVCHYqPgAAAAAAAACox6cEwqWQpFVE2gCFyOFsSdm2hCoE0/oWKXZJGa5UPd5mWSRxNctuXNtU32hcYNR/azLjsGO668Jwk+qCdFvmKjEqEMJgI+fvhwLQmm4=
$ matched-data-cli decrypt -d $MATCHED_DATA -k $PRIVATE_KEY
{"http.request.version": "HTTP/1.1", "http.request.uri.path": "/cms/%0Aadmin"}</code></pre>
            <p>Or the dashboard UI:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4S6H5u9SqEUrWDRRnYnCS/18a59db043aab89967c898bf87185151/image1-7.png" />
            
            </figure><p>Since our CLI tool is open-source and HPKE is interoperable, it can also be used in other tooling as part of a user's logging pipeline, for example in security information and event management (SIEM) software.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>This was a team effort with help from our Research and Security teams throughout the process. We relied on them for recommendations on how best to evaluate the algorithms as well as vetting the libraries we wanted to use.</p><p>We're very pleased with how HPKE has worked out for us from an ease-of-implementation and performance standpoint. It was also an easy choice for us to make due to its impending standardization and best-of-both-worlds approach to security.</p>
    <div>
      <h3>Watch it on Cloudflare TV</h3>
      <a href="#watch-it-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div>
<p></p> ]]></content:encoded>
            <category><![CDATA[WAF]]></category>
            <category><![CDATA[WAF Rules]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Firewall]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">2D6DVPVrqbmzOVwOsplIix</guid>
            <dc:creator>Miguel de Moura</dc:creator>
            <dc:creator>Andre Bluehs</dc:creator>
        </item>
        <item>
            <title><![CDATA[Making the WAF 40% faster]]></title>
            <link>https://blog.cloudflare.com/making-the-waf-40-faster/</link>
            <pubDate>Wed, 01 Jul 2020 11:00:00 GMT</pubDate>
            <description><![CDATA[ As with all Cloudflare security products, the WAF is designed to not sacrifice performance for security, but there is always room for improvement.
This blog post provides a brief overview of the latest performance improvements that were rolled out to our customers. ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare’s <a href="https://www.cloudflare.com/waf/">Web Application Firewall (WAF)</a> protects against malicious attacks aiming to exploit vulnerabilities in web applications. It is continuously updated to provide comprehensive coverage against the most recent threats while ensuring a low false positive rate.</p><p>As with all <a href="https://www.cloudflare.com/security/">Cloudflare security products</a>, the WAF is designed to not sacrifice performance for security, but there is always room for improvement.</p><p>This blog post provides a brief overview of the latest performance improvements that were rolled out to our customers. Visit our learning center to learn more about <a href="https://www.cloudflare.com/learning/ddos/glossary/web-application-firewall-waf/">how a Web Application Firewall (WAF) works</a>.</p>
    <div>
      <h2>Transitioning from PCRE to RE2</h2>
      <a href="#transitioning-from-pcre-to-re2">
        
      </a>
    </div>
    <p>Back in July 2019, the WAF transitioned from using a regular expression engine based on <a href="https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions">PCRE</a> to <a href="https://github.com/rust-lang/regex">one inspired by RE2</a>, which is based around using a <a href="https://en.wikipedia.org/wiki/Deterministic_finite_automaton">deterministic finite automaton (DFA)</a> instead of backtracking algorithms. This change came as a result of an outage where an update added a regular expression which backtracked enormously on certain HTTP requests, resulting in exponential execution time.</p><p>After the migration was finished, we saw no measurable difference in CPU consumption at the edge, but noticed execution time outliers in the 95th and 99th percentiles decreased, something we expected given RE2's guarantees of a linear time execution with the size of the input.</p><p>As the <a href="/the-problem-with-event-loops/">WAF engine uses a thread pool</a>, we also had to implement and tune a regex cache shared between the threads to avoid excessive memory consumption (the first implementation turned out to use a staggering amount of memory).</p><p>These changes, along with others outlined in the <a href="/details-of-the-cloudflare-outage-on-july-2-2019/#what-s-happened-since-last-tuesday">postmortem blog post</a>, helped us improve reliability and safety at the edge and have the confidence to explore further performance improvements.</p><p>But while we’ve highlighted regular expressions, they are only one of the many capabilities of the WAF engine.</p>
    <div>
      <h2>Matching Stages</h2>
      <a href="#matching-stages">
        
      </a>
    </div>
    <p>When an HTTP request reaches the WAF, it gets organized into several logical sections to be analyzed: method, path, headers, and body. These sections are all stored in <a href="/cloudflares-new-waf-compiling-to-lua/">Lua variables</a>. If you are interested in more detail on the implementation of the WAF itself you can <a href="https://www.youtube.com/watch?v=nlt4XKhucS4">watch this old presentation</a>.</p><p>Before matching these variables against specific malicious request signatures, some transformations are applied. These transformations are functions that range from simple modifications like lowercasing strings to complex tokenizers and parsers looking to fingerprint certain malicious payloads.</p><p>As the WAF currently uses a variant of the <a href="https://www.modsecurity.org/">ModSecurity</a> syntax, this is what a rule might look like:</p>
            <pre><code>SecRule REQUEST_BODY "@rx /\x00+evil" "drop, t:urlDecode, t:lowercase"</code></pre>
            <p>It takes the request body stored in the <code>REQUEST_BODY</code> variable, applies the <code>urlDecode()</code> and <code>lowercase()</code> functions to it and then compares the result with the regular expression signature <code>\x00+evil</code>.</p><p>In pseudo-code, we can represent it as:</p>
            <pre><code>rx( "/\x00+evil", lowercase( urlDecode( REQUEST_BODY ) ) )</code></pre>
            <p>Which in turn would match a request whose body contained <a href="https://en.wikipedia.org/wiki/Percent-encoding">percent encoded</a> NULL bytes followed by the word "evil", e.g.:</p>
            <pre><code>POST /cms/admin?action=post HTTP/1.1
Host: example.com
Content-Type: text/plain; charset=utf-8
Content-Length: 16

thiSis%2F%00eVil</code></pre>
            <p>The WAF contains thousands of these rules and its objective is to execute them as quickly as possible to minimize any added latency to a request. And to make things harder, it needs to run most of the rules on nearly every request. That’s because almost all HTTP requests are non-malicious and no rules are going to match. So we have to optimize for the worst case: execute everything!</p><p>To help mitigate this problem, one of the first matching steps executed for many rules is pre-filtering. By checking if a request contains certain bytes or sets of strings we are able to potentially skip a considerable number of expressions.</p><p>In the previous example, doing a quick check for the NULL byte (represented by <code>\x00</code> in the regular expression) allows us to completely skip the rule if it isn’t found:</p>
            <pre><code>contains( "\x00", REQUEST_BODY )
and
rx( "/\x00+evil", lowercase( urlDecode( REQUEST_BODY ) ) )</code></pre>
            <p>Since most requests don’t match any rule and these checks are quick to execute, overall we aren’t doing more operations by adding them.</p><p>Other steps can also be used to scan through and combine several regular expressions and avoid execution of rule expressions. As usual, doing less work is often the simplest way to make a system faster.</p>
    <div>
      <h2>Memoization</h2>
      <a href="#memoization">
        
      </a>
    </div>
    <p>Which brings us to <a href="https://en.wikipedia.org/wiki/Memoization">memoization</a> - caching the output of a function call to reuse it in future calls.</p><p>Let’s say we have the following expressions:</p>
            <pre><code>1. rx( "\x00+evil", lowercase( url_decode( body ) ) )
2. rx( "\x00+EVIL", remove_spaces( url_decode( body ) ) )
3. rx( "\x00+evil", lowercase( url_decode( headers ) ) )
4. streq( "\x00evil", lowercase( url_decode( body ) ) )</code></pre>
            <p>In this case, we can reuse the result of the nested function calls (1) as they’re the same in (4). By saving intermediate results we are also able to take advantage of the result of <code>url_decode( body )</code> from (1) and use it in (2) and (4). Sometimes it is also possible to swap the order functions are applied to improve caching, though in this case we would get different results.</p><p>A naive implementation of this system can simply be a hash table with each entry having the function(s) name(s) and arguments as the key and its output as the value.</p><p>Some of these functions are expensive and caching the result does lead to significant savings. To give a sense of magnitude, one of the rules we modified to ensure memoization took place saw its execution time reduced by about 95%:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7kud0Xv668ZFip72geJ3h6/8cdc6f4a5c49664df89a2e33434c6147/rule.png" />
            
            </figure><p>Execution time per rule</p><p>The WAF engine implements memoization and the rules take advantage of it, but there’s always room to increase cache hits.</p>
    <div>
      <h2>Rewriting Rules and Results</h2>
      <a href="#rewriting-rules-and-results">
        
      </a>
    </div>
    <p>Cloudflare has a <a href="https://developers.cloudflare.com/waf/change-log/">very regular cadence of releasing updates</a> and new rules to the Managed Rulesets. However, as more rules are added and new functions implemented, the memoization cache hit rate tends to decrease.</p><p>To improve this, we first looked into the rules taking the most <a href="https://en.wikipedia.org/wiki/Elapsed_real_time">wall-clock time</a> to execute using some of our performance metrics:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ahB7tm8BWAjy3zyN8S1ZY/03369f203293f3ea39fa51b6d87088c8/execution-time.png" />
            
            </figure><p>Execution time per rule</p><p>Having these, we cross-referenced them with the ones having cache misses (output is truncated with [...]):</p>
            <pre><code>$ ./parse.py --profile
Hit Ratio:
-------------
0.5608

Hot entries:
-------------
[urlDecode, replaceComments, REQUEST_URI, REQUEST_HEADERS, ARGS_POST]
[urlDecode, REQUEST_URI]
[urlDecode, htmlEntityDecode, jsDecode, replaceNulls, removeWhitespace, REQUEST_URI, REQUEST_HEADERS]
[urlDecode, lowercase, REQUEST_FILENAME]
[urlDecode, REQUEST_FILENAME]
[urlDecode, lowercase, replaceComments, compressWhitespace, ARGS, REQUEST_FILENAME]
[urlDecode, replaceNulls, removeWhitespace, REQUEST_URI, REQUEST_HEADERS, ARGS_POST]
[...]

Candidates:
-------------
100152A - replace t:removeWhitespace with t:compressWhitespace,t:removeWhitespace
100214 - replace t:lowercase with (?i)
100215 - replace t:lowercase with (?i)
100300 - consider REQUEST_URI over REQUEST_FILENAME
100137D - invert order of t:replaceNulls,t:lowercase
[...]</code></pre>
            <p>After identifying more than 40 rules, we rewrote them to take full advantage of memoization and added pre-filter checks where possible. Many of these changes were not immediately obvious, which is why we’re also creating tools to aid analysts in creating even more efficient rules. This also helps ensure they run in accordance with the latency budgets the team has set.</p><p>This change resulted in an increase of the cache hit percentage from 56% to <b>74%</b>, which crucially included the most expensive transformations.</p><p>Most importantly, we also observed a sharp decrease of <b>40%</b> in the average time the WAF takes to process and analyze an HTTP request at the Cloudflare edge.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2cNxDlf2ad0Ns8yp8OLPLP/8b8d2d7953210ba57e0df12991b8a444/results.png" />
            
            </figure><p>WAF Request Processing - Time Average</p><p>A comparable decrease was also observed for the 95th and 99th percentiles.</p><p>Finally, we saw a drop of CPU consumption at the edge of around <b>4.3%</b>.</p>
    <div>
      <h2>Next Steps</h2>
      <a href="#next-steps">
        
      </a>
    </div>
    <p>While the Lua WAF has served us well throughout all these years, we are currently porting it to use the same engine powering Firewall Rules. It is based on our open-sourced <a href="https://github.com/cloudflare/wirefilter">wirefilter</a> execution engine, which uses a filter syntax inspired by Wireshark®. In addition to allowing more flexible filter expressions, it provides better performance and safety.</p><p>The rule optimizations we've described in this blog post are not lost when moving to the new engine, however, as the changes were deliberately not specific to the current Lua engine’s implementation. And while we're routinely profiling, benchmarking and making complex optimizations to the Firewall stack, sometimes just relatively simple changes can have a surprisingly huge effect.</p> ]]></content:encoded>
            <category><![CDATA[WAF]]></category>
            <category><![CDATA[Performance]]></category>
            <guid isPermaLink="false">5ok6HaCaWMjoW205DBhdQB</guid>
            <dc:creator>Miguel de Moura</dc:creator>
        </item>
    </channel>
</rss>