
<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>Thu, 09 Apr 2026 10:36:25 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Bringing more transparency to post-quantum usage, encrypted messaging, and routing security]]></title>
            <link>https://blog.cloudflare.com/radar-origin-pq-key-transparency-aspa/</link>
            <pubDate>Fri, 27 Feb 2026 06:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare Radar has added new tools for monitoring PQ adoption, KT logs for messaging, and ASPA routing records to track the Internet's migration toward more secure encryption and routing standards.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare Radar already offers a wide array of <a href="https://radar.cloudflare.com/security/"><u>security insights</u></a> — from application and network layer attacks, to malicious email messages, to digital certificates and Internet routing.</p><p>And today we’re introducing even more. We are launching several new security-related data sets and tools on Radar: </p><ul><li><p>We are extending our post-quantum (PQ) monitoring beyond the client side to now include origin-facing connections. We have also released a new tool to help you check any website's post-quantum encryption compatibility. </p></li><li><p>A new Key Transparency section on Radar provides a public dashboard showing the real-time verification status of Key Transparency Logs for end-to-end encrypted messaging services like WhatsApp, showing when each log was last signed and verified by Cloudflare's Auditor. The page serves as a transparent interface where anyone can monitor the integrity of public key distribution and access the API to independently validate our Auditor’s proofs. </p></li><li><p>Routing Security insights continue to expand with the addition of global, country, and network-level information about the deployment of ASPA, an emerging standard that can help detect and prevent BGP route leaks. </p></li></ul>
    <div>
      <h2>Measuring origin post-quantum support</h2>
      <a href="#measuring-origin-post-quantum-support">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2gs0x3zMZTxios168jT9xW/179d8959b5e0939835cf6facef797457/1.png" />
          </figure><p>Since <a href="https://x.com/CloudflareRadar/status/1788277817362329983"><u>April 2024</u></a>, we have tracked the aggregate growth of client support for post-quantum encryption on Cloudflare Radar, chronicling its global growth from <a href="https://radar.cloudflare.com/adoption-and-usage?dateStart=2024-01-01&amp;dateEnd=2024-01-31#post-quantum-encryption-adoption"><u>under 3% at the start of 2024</u></a>, to <a href="https://radar.cloudflare.com/adoption-and-usage?dateStart=2026-02-01&amp;dateEnd=2026-02-28#post-quantum-encryption-adoption"><u>over 60% in February 2026</u></a>. And in October 2025, <a href="https://blog.cloudflare.com/pq-2025/#what-you-can-do-today-to-stay-safe-against-quantum-attacks"><u>we added the ability</u></a> for users to <a href="https://radar.cloudflare.com/adoption-and-usage#browser-support"><u>check</u></a> whether their browser supports <a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-support/#x25519mlkem768"><code><u>X25519MLKEM768</u></code></a> — a hybrid key exchange algorithm combining classical <a href="https://www.rfc-editor.org/rfc/rfc8410"><code><u>X25519</u></code></a> with <a href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf"><u>ML-KEM</u></a>, a lattice-based post-quantum scheme standardized by NIST. This provides security against both classical and quantum attacks. </p><p>However, post-quantum encryption support on user-to-Cloudflare connections is only part of the story.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/67cvSmOaISIHjrKKRHKPzg/e0ccf032658904fd6beaa7de7340b561/2.png" />
          </figure><p>For content not in our CDN cache, or for uncacheable content, Cloudflare’s edge servers establish a separate connection with a customer’s origin servers to retrieve it. To accelerate the transition to quantum-resistant security for these origin-facing fetches, we <a href="https://blog.cloudflare.com/post-quantum-to-origins/"><u>previously introduced an API</u></a> allowing customers to opt in to preferring post-quantum connections. Today, we’re making post-quantum compatibility of origin servers visible on Radar.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6KvV2meYLEPbNIQyHP6yji/9477a134c8f5f6a7aaecd6257cd59981/3.png" />
          </figure><p>The new origin post-quantum support graph on Radar illustrates the share of customer origins supporting <code>X25519MLKEM768</code>. This data is derived from <a href="https://blog.cloudflare.com/automatically-secure/"><u>our automated TLS scanner,</u></a> which probes TLS 1.3-compatible origins and aggregates the results daily. It is important to note that our scanner tests for support rather than the origin server's specific preference. While an origin may support a post-quantum key exchange algorithm, its local TLS key exchange preference can ultimately dictate the encryption outcome.</p><p>While the headline graph focuses on post-quantum readiness, the scanner also evaluates support for classical key exchange algorithms. Within the Radar <a href="https://radar.cloudflare.com/explorer?dataSet=post_quantum.origin&amp;groupBy=key_agreement#result"><u>Data Explorer view</u></a>, you can also see the full distribution of these supported TLS key exchange methods.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5PBOoQSCcIAQrYezKp1pJU/d4218aba59deef6c21df53856a93040a/4.png" />
          </figure><p>As shown in the graphs above, approximately 10% of origins could benefit from a post-quantum-preferred key agreement today. This represents a significant jump from less than 1% at the start of 2025 — <a href="https://radar.cloudflare.com/explorer?dataSet=post_quantum.origin&amp;groupBy=key_agreement&amp;dt=2025-01-01_2025-12-31"><u>a 10x increase in just over a year</u></a>. We expect this number to grow steadily as the industry continues its migration. This upward trend likely accelerated in 2025 as many server-side TLS libraries, such as <a href="https://openssl-library.org/post/2025-04-08-openssl-35-final-release/"><u>OpenSSL 3.5.0+</u></a>,<a href="https://www.gnutls.org/"><u> GnuTLS 3.8.9+</u></a>, and <a href="https://go.dev/doc/go1.24#cryptotlspkgcryptotls"><u>Go 1.24+</u></a>, enabled hybrid post-quantum key exchange by default, allowing platforms and services to support post-quantum connections simply by upgrading their cryptographic library dependencies.</p><p>In addition to the Radar and Data Explorer graphs, the <a href="https://developers.cloudflare.com/api/resources/radar/subresources/post_quantum/subresources/origin/"><u>origin readiness data is available through the Radar API</u></a> as well.</p><p>As an additional part of our efforts to help the Internet transition to post-quantum cryptography, we are also launching <a href="https://radar.cloudflare.com/post-quantum#website-support"><u>a tool to test whether a specific hostname supports post-quantum encryption</u></a>. These tests can be run against any publicly accessible website, as long as they allow connections from Cloudflare’s <a href="https://www.cloudflare.com/ips/"><u>egress IP address ranges</u></a>. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5dgwK3i7IeLLSUt5xnk4lf/276e25dda3389f6e0ad83a26acd08fec/5.png" />
          </figure><p><sub><i>A screenshot of the tool in Radar to test whether a hostname supports post-quantum encryption.</i></sub></p><p>The tool presents a simple form where users can enter a hostname (such as <a href="https://radar.cloudflare.com/post-quantum?host=cloudflare.com%3A443"><code><u>cloudflare.com</u></code></a> or <a href="https://radar.cloudflare.com/post-quantum?host=www.wikipedia.org%3A443"><code><u>www.wikipedia.org</u></code></a>) and optionally specify a custom port (the default is <a href="https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=443"><u>443, the standard HTTPS port</u></a>). After clicking "Test", the result displays a tag indicating PQ support status alongside the negotiated TLS key exchange algorithm. If the server prefers PQ secure connections, a green "PQ" tag appears with a message confirming the connection is "post-quantum secure." Otherwise, a red tag indicates the connection is "not post-quantum secure", showing the classical algorithm that was negotiated.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3rfEG4dMlwR4FJkaKXTRWF/8cab135242057ce57f3b0e4a92be4cec/6.png" />
          </figure>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/PXu3kjzwhVkb29kIFREOn/41785c06297e0667ff9e2b261ae9b819/7.png" />
          </figure><p>Under the hood, this tool uses <a href="https://developers.cloudflare.com/containers/"><u>Cloudflare Containers</u></a> — a new capability that allows running container workloads alongside Workers. Since the Workers runtime is not exposed to details of the underlying TLS handshake, Workers cannot initiate TLS scans. Therefore, we created a Go container that leverages the <a href="https://pkg.go.dev/crypto/tls"><code><u>crypto/tls</u></code></a> package's support for post-quantum compatibility checks. The container runs on-demand and performs the actual handshake to determine the negotiated TLS key exchange algorithm, returning results through the <a href="https://developers.cloudflare.com/api/resources/radar/subresources/post_quantum/subresources/tls/methods/support/"><u>Radar API</u></a>.</p><p>With the addition of these origin-facing insights, complementing the existing client-facing insights, we have moved all the post-quantum content to <a href="https://radar.cloudflare.com/post-quantum"><u>its own section on Radar</u></a>. </p>
    <div>
      <h2>Securing E2EE messaging systems with Key Transparency</h2>
      <a href="#securing-e2ee-messaging-systems-with-key-transparency">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/71b8HJK1iT0udJscvkqqI4/778efb329047fca017ff2cf4153330ad/8.png" />
          </figure><p><a href="https://www.cloudflare.com/learning/privacy/what-is-end-to-end-encryption/"><u>End-to-end encrypted (E2EE)</u></a> messaging apps like WhatsApp and Signal have become essential tools for private communication, relied upon by billions of people worldwide. These apps use <a href="https://www.cloudflare.com/learning/ssl/how-does-public-key-encryption-work/"><u>public-key cryptography</u></a> to ensure that only the sender and recipient can read the contents of their messages — not even the messaging service itself. However, there's an often-overlooked vulnerability in this model: users must trust that the messaging app is distributing the correct public keys for each contact.</p><p>If an attacker were able to substitute an incorrect public key in the messaging app's database, they could intercept messages intended for someone else — all without the sender knowing.</p><p>Key Transparency addresses this challenge by creating an auditable, append-only log of public keys — similar in concept to <a href="https://radar.cloudflare.com/certificate-transparency"><u>Certificate Transparency</u></a> for TLS certificates. Messaging apps publish their users' public keys to a transparency log, and independent third parties can verify and vouch that the log has been constructed correctly and consistently over time. In September 2024, Cloudflare <a href="https://blog.cloudflare.com/key-transparency/"><u>announced</u></a> such a Key Transparency auditor for WhatsApp, providing an independent verification layer that helps ensure the integrity of public key distribution for the messaging app's billions of users.</p><p>Today, we're publishing Key Transparency audit data in a new <a href="https://radar.cloudflare.com/key-transparency"><u>Key Transparency section</u></a> on Cloudflare Radar. This section showcases the Key Transparency logs that Cloudflare audits, giving researchers, security professionals, and curious users a window into the health and activity of these critical systems.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1LZ1DUzv0SCgBa0XqDURKP/26ccd8b0741073895cbb52aa7f1d5643/image11.png" />
          </figure><p>The new page launches with two monitored logs: WhatsApp and Facebook Messenger Transport. Each monitored log is displayed as a card containing the following information:</p><ul><li><p><b>Status:</b> Indicates whether the log is online, in initialization, or disabled. An "online" status means the log is actively publishing key updates into epochs that Cloudflare audits. (An epoch represents a set of updates applied to the key directory at a specific time.)</p></li><li><p><b>Last signed epoch:</b> The most recent epoch that has been published by the messaging service's log and acknowledged by Cloudflare. By clicking on the eye icon, users can view the full epoch data in JSON format, including the epoch number, timestamp, cryptographic digest, and signature.</p></li><li><p><b>Last verified epoch:</b> The most recent epoch that Cloudflare has verified. Verification involves checking that the transition of the transparency log data structure from the previous epoch to the current one represents a valid tree transformation — ensuring the log has been constructed correctly. The verification timestamp indicates when Cloudflare completed its audit.</p></li><li><p><b>Root:</b> The current root hash of the <a href="https://github.com/facebook/akd"><u>Auditable Key Directory (AKD)</u></a> tree. This hash cryptographically represents the entire state of the key directory at the current epoch. Like the epoch fields, users can click to view the complete JSON response from the auditor.</p></li></ul><p>The data shown on the page is also available via the Key Transparency Auditor API, with endpoints for <a href="https://developers.cloudflare.com/key-transparency/api/auditor-information/"><u>auditor information</u></a> and <a href="https://developers.cloudflare.com/key-transparency/api/namespaces/"><u>namespaces</u></a>.</p><p>If you would like to perform audit proof verification yourself, you can follow the instructions in our <a href="https://blog.cloudflare.com/key-transparency/"><u>Auditing Key Transparency blog post</u></a>. We hope that these use cases are the first of many that we publish in this Key Transparency section in Radar — if your company or organization is interested in auditing for your public key or related infrastructure, you can <a href="https://www.cloudflare.com/lp/privacy-edge/"><u>reach out to us here</u></a>.</p>
    <div>
      <h2>Tracking RPKI ASPA adoption</h2>
      <a href="#tracking-rpki-aspa-adoption">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2LAbrwY9ziVbe1BzfUyl7K/821a40f86c62dd9b44f7bcaee018dd28/10.png" />
          </figure><p>While the <a href="https://www.cloudflare.com/learning/security/glossary/what-is-bgp/"><u>Border Gateway Protocol (BGP)</u></a> is the backbone of Internet routing, it was designed without built-in mechanisms to verify the validity of the paths it propagates. This inherent trust has long left the global network vulnerable to route leaks and hijacks, where traffic is accidentally or maliciously detoured through unauthorized networks.</p><p>Although <a href="https://en.wikipedia.org/wiki/Resource_Public_Key_Infrastructure"><u>RPKI</u></a> and <a href="https://www.arin.net/resources/manage/rpki/roas/"><u>Route Origin Authorizations (ROAs)</u></a> have successfully hardened the origin of routes, they cannot verify the path traffic takes between networks. This is where <a href="https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/"><u>ASPA (Autonomous System Provider Authorization)</u></a><b> </b>comes in. ASPA extends RPKI protection by allowing an <a href="https://www.cloudflare.com/learning/network-layer/what-is-an-autonomous-system/"><u>Autonomous System (AS)</u></a> to cryptographically sign a record listing the networks authorized to propagate its routes upstream. By validating these Customer-to-Provider relationships, ASPA allows systems to detect invalid path announcements with confidence and react accordingly.</p><p>While the specific IETF standard remains <a href="https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/"><u>in draft</u></a>, the operational community is moving fast. Support for creating ASPA objects has already landed in the portals of Regional Internet Registries (RIRs) like <a href="https://www.arin.net/announcements/20260120/"><u>ARIN</u></a> and <a href="https://labs.ripe.net/author/tim_bruijnzeels/aspa-in-the-rpki-dashboard-a-new-layer-of-routing-security/"><u>RIPE NCC</u></a>, and validation logic is available in major software routing stacks like <a href="https://www.undeadly.org/cgi?action=article;sid=20231002135058"><u>OpenBGPD</u></a> and <a href="https://bird.network.cz/?get_doc&amp;v=20&amp;f=bird-5.html"><u>BIRD</u></a>.</p><p>To provide better visibility into the adoption of this emerging standard, we have added comprehensive RPKI ASPA support to the <a href="https://radar.cloudflare.com/routing"><u>Routing section</u></a> of Cloudflare Radar. Tracking these records globally allows us to understand how quickly the industry is moving toward better path validation.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6SI6A5vd2bAp3QnBAsJFmZ/24e11445eb0309252d759e88dbf2ba62/11.png" />
          </figure><p>Our new ASPA deployment view allows users to examine the growth of ASPA adoption over time, with the ability to visualize trends across the five <a href="https://en.wikipedia.org/wiki/Regional_Internet_registry"><u>Regional Internet Registries</u></a> (RIRs) based on AS registration. You can view the entire history of ASPA entries, dating back to October 1, 2023, or zoom into specific date ranges to correlate spikes in adoption with industry events, such as the introduction of ASPA features on ARIN and RIPE NCC online dashboards.</p><p>Beyond aggregate trends, we have also introduced a granular, searchable explorer for real-time ASPA content. This table view allows you to inspect the current state of ASPA records, searchable by AS number, AS name, or by filtering for only providers or customer ASNs. This allows network operators to verify that their records are published correctly and to view other networks’ configurations.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/K97G5TC7O1MYwkvFbrdTl/85b27f807401f85d2bbe140f1611a034/12.png" />
          </figure><p>We have also integrated ASPA data directly into the country/region routing pages. Users can now track how different locations are progressing in securing their infrastructure, based on the associated ASPA records from the customer ASNs registered locally.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6mhZyfrHexdo1GDAoKZEd7/44b63675595a01939fa4748210d8c482/13.png" />
          </figure><p>On individual AS pages, we have updated the Connectivity section. Now, when viewing the connections of a network, you may see a visual indicator for "ASPA Verified Provider." This annotation confirms that an ASPA record exists authorizing that specific upstream connection, providing an immediate signal of routing hygiene and trust.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3lVJY4fZWv3KaFdKwLHfAV/aeb2bc27bdccb6a9025345dbaed5b762/14.png" />
          </figure><p>For ASes that have deployed ASPA, we now display a complete list of authorized provider ASNs along with their details. Beyond the current state, Radar also provides a detailed timeline of ASPA activity involving the AS. This history distinguishes between changes initiated by the AS itself ("As customer") and records created by others designating it as a provider ("As provider"), allowing users to immediately identify when specific routing authorizations were established or modified.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/ZIlAn2l0sDTLCyEMMcBI9/871b8d7abffe17b3aee060502eaa4c1c/15.png" />
          </figure><p>Visibility is an essential first step toward broader adoption of emerging routing security protocols like ASPA. By surfacing this data, we aim to help operators deploy protections and assist researchers in tracking the Internet's progress toward a more secure routing path. For those who need to integrate this data into their own workflows or perform deeper analysis, we are also exposing these metrics programmatically. Users can now access ASPA content snapshots, historical timeseries, and detailed changes data using the newly introduced endpoints in the<a href="https://developers.cloudflare.com/api/resources/radar/subresources/bgp/subresources/rpki/subresources/aspa/"> <u>Cloudflare Radar API</u></a>.</p>
    <div>
      <h2>As security evolves, so does our data</h2>
      <a href="#as-security-evolves-so-does-our-data">
        
      </a>
    </div>
    <p>Internet security continues to evolve, with new approaches, protocols, and standards being developed to ensure that information, applications, and networks remain secure. The security data and insights available on Cloudflare Radar will continue to evolve as well. The new sections highlighted above serve to expand existing routing security, transparency, and post-quantum insights already available on Cloudflare Radar. </p><p>If you share any of these new charts and graphs on social media, be sure to tag us: <a href="https://x.com/CloudflareRadar"><u>@CloudflareRadar</u></a> (X), <a href="https://noc.social/@cloudflareradar"><u>noc.social/@cloudflareradar</u></a> (Mastodon), and <a href="https://bsky.app/profile/radar.cloudflare.com"><u>radar.cloudflare.com</u></a> (Bluesky). If you have questions or comments, or suggestions for data that you’d like to see us add to Radar, you can reach out to us on social media, or contact us via <a><u>email</u></a>.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jAzDXss7PvszWkwGC0q2g/df14de40bf268052fac11239952fc1ed/16.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[Radar]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Post-Quantum]]></category>
            <category><![CDATA[Routing]]></category>
            <category><![CDATA[Research]]></category>
            <guid isPermaLink="false">1Iy1Qvw9TsOhRwgjUYqFxO</guid>
            <dc:creator>David Belson</dc:creator>
            <dc:creator>Mingwei Zhang</dc:creator>
            <dc:creator>André Jesus</dc:creator>
            <dc:creator>Suleman Ahmad</dc:creator>
            <dc:creator>Sabina Zejnilovic</dc:creator>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Mari Galicer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Beyond IP lists: a registry format for bots and agents]]></title>
            <link>https://blog.cloudflare.com/agent-registry/</link>
            <pubDate>Thu, 30 Oct 2025 22:00:00 GMT</pubDate>
            <description><![CDATA[ We propose an open registry format for Web Bot Auth to move beyond IP-based identity. This allows any origin to discover and verify cryptographic keys for bots, fostering a decentralized and more trustworthy ecosystem. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>As bots and agents start <a href="https://blog.cloudflare.com/web-bot-auth/"><u>cryptographically signing their requests</u></a>, there is a growing need for website operators to learn public keys as they are setting up their service. I might be able to find the public key material for well-known fetchers and crawlers, but what about the next 1,000 or next 1,000,000? And how do I find their public key material in order to verify that they are who they say they are? This problem is called <i>discovery.</i></p><p>We share this problem with <a href="https://aws.amazon.com/bedrock/agentcore/"><u>Amazon Bedrock AgentCore</u></a>, a comprehensive agentic platform to build, deploy and operate highly capable agents at scale, and their <a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/browser-tool.html"><u>AgentCore Browser</u></a>, a fast, secure, cloud-based browser runtime to enable AI agents to interact with websites at scale. The AgentCore team wants to make it easy for each of their customers to sign <i>their own requests</i>, so that Cloudflare and other operators of CDN infrastructure see agent signatures from individual agents rather than AgentCore as a monolith. (Note: this method does not identify individual users.) In order to do this, Cloudflare needed a way to ingest and register the public keys of AgentCore’s customers at scale. </p><p>In this blog post, we propose a registry of bots and agents as a way to easily discover them on the Internet. We also outline how <a href="https://blog.cloudflare.com/web-bot-auth/"><u>Web Bot Auth</u></a> can be expanded with a registry format. Similar to IP lists that can be authored by anyone and easily imported, the <a href="https://datatracker.ietf.org/doc/draft-meunier-webbotauth-registry/"><u>registry format</u></a> is a list of URLs at which to retrieve agent keys and can be authored and imported easily.</p><p>We believe such registries should foster and strengthen an open ecosystem of curators that website operators can trust.</p>
    <div>
      <h2>A need for more trustworthy authentication</h2>
      <a href="#a-need-for-more-trustworthy-authentication">
        
      </a>
    </div>
    <p>In May, we introduced a protocol proposal called <a href="https://blog.cloudflare.com/web-bot-auth/"><u>Web Bot Auth</u></a>, which describes how bot and agent developers can cryptographically sign requests coming from their infrastructure. </p><p>There have now been multiple implementations of the proposed protocol, from <a href="https://vercel.com/changelog/vercels-bot-verification-now-supports-web-bot-auth"><u>Vercel</u></a> to <a href="https://changelog.shopify.com/posts/authorize-custom-crawlers-and-tools-with-new-crawler-access-keys"><u>Shopify</u></a> to <a href="https://www.cloudflare.com/press/press-releases/2025/cloudflare-collaborates-with-leading-payments-companies-to-secure-and-enable-agentic-commerce/"><u>Visa</u></a>. It has been actively <a href="https://mailarchive.ietf.org/arch/browse/web-bot-auth/"><u>discussed</u></a> and contributions have been made. Web Bot Auth marks a first step towards moving from brittle identification, like IPs and user agents, to more trustworthy cryptographic authentication. However, like IP addresses, cryptographic keys are a pseudonymous form of identity. If you operate a website without the scale and reach of large CDNs, how do you discover the public key of known crawlers?</p><p>The first protocol proposal suggested one approach: bot operators would provide a newly-defined HTTP header Signature-Agent that refers to an HTTP endpoint hosting their keys. Similar to IP addresses, the default is to allow all, but if a particular operator is making too many requests, you can start taking actions: increase their rate limit, contact the operator, etc.</p><p>Here’s an example from <a href="https://help.shopify.com/en/manual/promoting-marketing/seo/crawling-your-store"><u>Shopify's online store</u></a>:</p>
            <pre><code>Signature-Agent: "https://shopify.com"</code></pre>
            
    <div>
      <h2>A registry format</h2>
      <a href="#a-registry-format">
        
      </a>
    </div>
    <p>With all that in mind, we come to the following problem. How can Cloudflare ensure customers have control over the traffic they want to allow, with sensible defaults, while fostering an open curation ecosystem that doesn’t lock in customers or small origins?</p><p>Such an ecosystem exists for lists of IP addresses (e.g.<a href="https://github.com/antoinevastel/avastel-bot-ips-lists/blob/master/avastel-proxy-bot-ips-1day.txt"><u> avestel-bots-ip-lists</u></a>) and robots.txt (e.g.<a href="https://github.com/ai-robots-txt/ai.robots.txt"><u> ai-robots-txt</u></a>). For both, you can find canonical lists on the Internet to easily configure your website to allow or disallow traffic from those IPs. They provide direct configuration for your nginx or haproxy, and you can use it to configure your Cloudflare account. For instance, I could import the robots.txt below:</p>
            <pre><code>User-agent: MyBadBot
Disallow: /</code></pre>
            <p>This is where the registry format comes in, providing a list of URLs pointing to Signature Agent keys:</p>
            <pre><code># AI Crawler
https://chatgpt.com/.well-known/http-message-signatures-directory
https://autorag.ai.cloudflare.com/.well-known/http-message-signatures-directory
 
# Test signature agent card
https://http-message-signatures-example.research.cloudflare.com/.well-known/http-message-signatures-directory</code></pre>
            <p>And that's it. A registry could contain a list of all known signature agents, a curated list for academic research agents, for search agents, etc.</p><p>Anyone can maintain and host these lists. Similar to IP or robots.txt list, you can host such a registry on any public file system. This means you can have a repository on GitHub, put the file on Cloudflare R2, or send it as an email attachment. Cloudflare intends to provide one of the first instances of this registry, so that others can contribute to it or reference it when building their own. </p>
    <div>
      <h2>Learn more about an incoming request</h2>
      <a href="#learn-more-about-an-incoming-request">
        
      </a>
    </div>
    <p>Knowing the Signature-Agent is great, but not sufficient. For instance, to be a verified bot, Cloudflare requires a contact method, in case requests from that infrastructure suddenly fail or change format in a way that causes unexpected errors upstream. In fact, there is a lot of information an origin might want to know: a name for the operator, a contact method, a logo, the expected crawl rate, etc.</p><p>Therefore, to complement the registry format, we have proposed a <a href="https://thibmeu.github.io/http-message-signatures-directory/draft-meunier-webbotauth-registry.html#name-signature-agent-card"><u>signature-agent card format</u> that </a>extends the JWKS directory (<a href="https://www.rfc-editor.org/rfc/rfc7517"><u>RFC 7517</u></a>) with additional metadata. Similar to an old-fashioned contact card, it includes all the important information someone might want to know about your agent or crawler. </p><p>We provide an example below for illustration. Note that the fields may change: introducing jwks-uri, logo being more descriptive, etc.</p>
            <pre><code>{
  "client_name": "Example Bot",
  "client_uri": "https://example.com/bot/about.html",
  "logo_uri": "https://example.com/",
  "contacts": ["mailto:bot-support@example.com"],
  "expected-user-agent": "Mozilla/5.0 ExampleBot",
  "rfc9309-product-token": "ExampleBot",
  "rfc9309-compliance": ["User-Agent", "Allow", "Disallow", "Content-Usage"],
  "trigger": "fetcher",
  "purpose": "tdm",
  "targeted-content": "Cat pictures",
  "rate-control": "429",
  "rate-expectation": "avg=10rps;max=100rps",
  "known-urls": ["/", "/robots.txt", "*.png"],
  "keys": [{
    "kty": "OKP",
    "crv": "Ed25519",
    "kid": "NFcWBst6DXG-N35nHdzMrioWntdzNZghQSkjHNMMSjw",
    "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs",
    "use": "sig",
    "nbf": 1712793600,
    "exp": 1715385600
  }]
}</code></pre>
            
    <div>
      <h2>Operating a registry</h2>
      <a href="#operating-a-registry">
        
      </a>
    </div>
    <p>Amazon Bedrock AgentCore, an agentic platform for building and deploying AI agents at scale, adopted Web Bot Auth for its AgentCore Browser service (learn more in <a href="https://aws.amazon.com/blogs/machine-learning/reduce-captchas-for-ai-agents-browsing-the-web-with-web-bot-auth-preview-in-amazon-bedrock-agentcore-browser/">their post)</a>. AgentCore Browser intends to transition from a service signing key that is currently available in their public preview, to customer-specific keys, once the protocol matures. Cloudflare and other operators of origin protection service will be able to see and validate signatures from individual AgentCore customers rather than AgentCore as a whole.</p><p>Cloudflare also offers a registry for bots and agents it trusts, provided through Radar. It uses the <a href="https://assets.radar.cloudflare.com/bots/signature-agent-registry.txt"><u>registry format</u></a> to allow for the consumption of bots trusted by Cloudflare on your server.</p><p>You can use these registries today – we’ve provided a demo in Go for <a href="https://caddyserver.com/"><u>Caddy server</u></a> that would allow us to import keys from multiple registries. It’s on <a href="https://github.com/cloudflare/web-bot-auth/pull/52"><u>cloudflare/web-bot-auth</u></a>. The configuration looks like this:</p>
            <pre><code>:8080 {
    route {
        # httpsig middleware is used here
        httpsig {
            registry "http://localhost:8787/test-registry.txt"
            # You can specify multiple registries. All tags will be checked independantly
            registry "http://example.test/another-registry.txt"
        }

        # Responds if signature is valid
        handle {
            respond "Signature verification succeeded!" 200
        }
    }
}</code></pre>
            <p>There are several reasons why you might want to operate and curate a registry leveraging the <a href="https://www.ietf.org/archive/id/draft-meunier-webbotauth-registry-01.html#name-signature-agent-card"><u>Signature Agent Card format</u></a>:</p><ol><li><p><b>Monitor incoming </b><code><b>Signature-Agent</b></code><b>s.</b> This should allow you to collect signature-agent cards of agents reaching out to your domain.</p></li><li><p><b>Import them from existing registries, and categorize them yourself.</b> There could be a general registry constructed from the monitoring step above, but registries might be more useful with more categories.</p></li><li><p><b>Establish direct relationships with agents.</b> Cloudflare does this for its<a href="https://radar.cloudflare.com/bots#verified-bots"> <u>bot registry</u></a> for instance, or you might use a public GitHub repository where people can open issues.</p></li><li><p><b>Learn from your users.</b> If you offer a security service, allowing your customers to specify the registries/signature-agents they want to let through allows you to gain valuable insight.</p></li></ol>
    <div>
      <h2>Moving forward</h2>
      <a href="#moving-forward">
        
      </a>
    </div>
    <p>As cryptographic authentication for bots and agents grows, the need for discovery increases.</p><p>With the introduction of a lightweight format and specification to attach metadata to Signature-Agent, and curate them in the form of registries, we begin to address this need. The HTTP Message Signature directory format is being expanded to include some self-certified metadata, and the registry maintains a curation ecosystem.</p><p>Down the line, we predict that clients and origins will choose the signature-agent they trust, use a common format to migrate their configuration between CDN providers, and rely on a third-party registry for curation. We are working towards integrating these capabilities into our bot management and rule engines.</p><p>If you’d like to experiment, our demo is on <a href="https://github.com/cloudflare/web-bot-auth/pull/52"><u>GitHub</u></a>. If you’d like to help us, <a href="https://blog.cloudflare.com/cloudflare-1111-intern-program/"><u>we’re hiring 1,111 interns</u></a> over the course of next year, and have <a href="https://www.cloudflare.com/careers/"><u>open positions</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Bots]]></category>
            <guid isPermaLink="false">3VeTsp2f9v3B1QZF0oglUV</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Maxime Guerreiro</dc:creator>
        </item>
        <item>
            <title><![CDATA[Anonymous credentials: rate-limiting bots and agents without compromising privacy]]></title>
            <link>https://blog.cloudflare.com/private-rate-limiting/</link>
            <pubDate>Thu, 30 Oct 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ As AI agents change how the Internet is used, they create a challenge for security. We explore how Anonymous Credentials can rate limit agent traffic and block abuse without tracking users or compromising their privacy. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>The way we interact with the Internet is changing. Not long ago, ordering a pizza meant visiting a website, clicking through menus, and entering your payment details. Soon, you might just <a href="https://www.cnet.com/tech/services-and-software/i-had-chatgpt-order-me-a-pizza-this-could-change-everything/"><u>ask your phone</u></a> to order a pizza that matches your preferences. A program on your device or on a remote server, which we call an <a href="https://developers.cloudflare.com/agents/concepts/what-are-agents/"><u>AI agent</u></a>, would visit the website and orchestrate the necessary steps on your behalf.</p><p>Of course, agents can do much more than order pizza. Soon we might use them to buy concert tickets, plan vacations, or even write, review, and merge pull requests. While some of these tasks will eventually run locally, for now, most are powered by massive AI models running in the biggest datacenters in the world. As agentic AI increases in popularity, we expect to see a large increase in traffic from these AI platforms and a corresponding drop in traffic from more conventional sources (like your phone).</p><p>This shift in traffic patterns has prompted us to assess how to keep our customers online and secure in the AI era. On one hand, the nature of requests are changing: Websites optimized for human visitors will have to cope with faster, and potentially greedier, agents. On the other hand, AI platforms may soon become a significant source of attacks, originating from malicious users of the platforms themselves.</p><p>Unfortunately, existing tools for managing such (mis)behavior are likely too coarse-grained to manage this transition. For example, <a href="https://blog.cloudflare.com/per-customer-bot-defenses/"><u>when Cloudflare detects that a request is part of a known attack pattern</u></a>, the best course of action often is to block all subsequent requests from the same source. When the source is an AI agent platform, this could mean inadvertently blocking all users of the same platform, even honest ones who just want to order pizza. We started addressing this problem <a href="https://blog.cloudflare.com/web-bot-auth/"><u>earlier this year</u></a>. But as agentic AI grows in popularity, we think the Internet will need more fine-grained mechanisms of managing agents without impacting honest users.</p><p>At the same time, we firmly believe that any such security mechanism must be designed with user privacy at its core. In this post, we'll describe how to use <b>anonymous credentials (AC)</b> to build these tools. Anonymous credentials help website operators to enforce a wide range of security policies, like rate-limiting users or blocking a specific malicious user, without ever having to identify any user or track them across requests.</p><p>Anonymous credentials are <a href="https://mailarchive.ietf.org/arch/msg/privacy-pass/--JXbGvkHnLq1iHQKJAnfn5eH9A/"><u>under development at IETF</u></a> in order to provide a standard that can work across websites, browsers, platforms. It's still in its early stages, but we believe this work will play a critical role in keeping the Internet secure and private in the AI era. We will be contributing to this process as we work towards real-world deployment. This is still early days. If you work in this space, we hope you will follow along and contribute as well.</p>
    <div>
      <h2>Let’s build a small agent</h2>
      <a href="#lets-build-a-small-agent">
        
      </a>
    </div>
    <p>To help us discuss how AI agents are affecting web servers, let’s build an agent ourselves. Our goal is to have an agent that can order a pizza from a nearby pizzeria. Without an agent, you would open your browser, figure out which pizzeria is nearby, view the menu and make selections, add any extras (double pepperoni), and proceed to checkout with your credit card. With an agent, it’s the same flow —except the agent is opening and orchestrating the browser on your behalf.</p><p>In the traditional flow, there’s a human all along the way, and each step has a clear intent: list all pizzerias within 3 Km of my current location; pick a pizza from the menu; enter my credit card; and so on. An agent, on the other hand, has to infer each of these actions from the prompt "order me a pizza."</p><p>In this section, we’ll build a simple program that takes a prompt and can make outgoing requests. Here’s an example of a simple <a href="https://workers.cloudflare.com/"><u>Worker</u></a> that takes a specific prompt and generates an answer accordingly. You can find the code on <a href="https://github.com/cloudflareresearch/mini-ai-agent-demo"><u>GitHub</u></a>:</p>
            <pre><code>export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise&lt;Response&gt; {
       const out = await env.AI.run("@cf/meta/llama-3.1-8b-instruct-fp8", {
           prompt: `I'd like to order a pepperoni pizza with extra cheese.
                    Please deliver it to Cloudflare Austin office.
                    Price should not be more than $20.`,
       });


       return new Response(out.response);
   },
} satisfies ExportedHandler&lt;Env&gt;;</code></pre>
            <p>In this context, the LLM provides its best answer. It gives us a plan and instruction, but does not perform the action on our behalf. You and I are able to take a list of instructions and act upon it because we have agency and can affect the world. To allow our agent to interact with more of the world, we’re going to give it control over a web browser.</p><p>Cloudflare offers a <a href="https://developers.cloudflare.com/browser-rendering"><u>Browser Rendering</u></a> service that can bind directly into our Worker. Let’s do that. The following code uses <a href="https://www.stagehand.dev/"><u>Stagehand</u></a>, an automation framework that makes it simple to control the browser. We pass it an instance of Cloudflare remote browser, as well as a client for <a href="https://developers.cloudflare.com/workers-ai/"><u>Workers AI</u></a>.</p>
            <pre><code>import { Stagehand } from "@browserbasehq/stagehand";
import { endpointURLString } from "@cloudflare/playwright";
import { WorkersAIClient } from "./workersAIClient"; // wrapper to convert cloudflare AI


export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise&lt;Response&gt; {
       const stagehand = new Stagehand({
           env: "LOCAL",
           localBrowserLaunchOptions: { cdpUrl: endpointURLString(env.BROWSER) },
           llmClient: new WorkersAIClient(env.AI),
           verbose: 1,
       });
       await stagehand.init();


       const page = stagehand.page;
       await page.goto("https://mini-ai-agent.cloudflareresearch.com/llm");


       const { extraction } = await page.extract("what are the pizza available on the menu?");
       return new Response(extraction);
   },
} satisfies ExportedHandler&lt;Env&gt;;</code></pre>
            <p>You can access that code for yourself on <a href="https://mini-ai-agent.cloudflareresearch.com/llm"><i><u>https://mini-ai-agent.cloudflareresearch.com/llm</u></i></a>. Here’s the response we got on October 10, 2025:</p>
            <pre><code>Margherita Classic: $12.99
Pepperoni Supreme: $14.99
Veggie Garden: $13.99
Meat Lovers: $16.99
Hawaiian Paradise: $15.49</code></pre>
            <p>Using the screenshot API of browser rendering, we can also inspect what the agent is doing. Here's how the browser renders the page in the example above:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6lXTePCTUORCyyOWNNcwZ8/5978abd1878f78107a2c9606c3a1ef51/image4.png" />
          </figure><p>Stagehand allows us to identify components on the page, such as <code>page.act(“Click on pepperoni pizza”)</code> and <code>page.act(“Click on Pay now”)</code>. This eases interaction between the developer and the browser.</p><p>To go further, and instruct the agent to perform the whole flow autonomously, we have to use the appropriately named <a href="https://docs.stagehand.dev/basics/agent"><u>agent</u></a> mode of Stagehand. This feature is not yet supported by Cloudflare Workers, but is provided below for completeness.</p>
            <pre><code>import { Stagehand } from "@browserbasehq/stagehand";
import { endpointURLString } from "@cloudflare/playwright";
import { WorkersAIClient } from "./workersAIClient";


export default {
   async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise&lt;Response&gt; {
       const stagehand = new Stagehand({
           env: "LOCAL",
           localBrowserLaunchOptions: { cdpUrl: endpointURLString(env.BROWSER) },
           llmClient: new WorkersAIClient(env.AI),
           verbose: 1,
       });
       await stagehand.init();
       
       const agent = stagehand.agent();
       const result = await agent.execute(`I'd like to order a pepperoni pizza with extra cheese.
                                           Please deliver it to Cloudflare Austin office.
                                           Price should not be more than $20.`);


       return new Response(result.message);
   },
} satisfies ExportedHandler&lt;Env&gt;;</code></pre>
            <p>We can see that instead of adding step-by-step instructions, the agent is provided control. To actually pay, it would need access to a payment method such as a <a href="https://en.wikipedia.org/wiki/Controlled_payment_number"><u>virtual credit card</u></a>.</p><p>The prompt had some subtlety in that we’ve scoped the location to Cloudflare’s Austin office. This is because while the agent responds to us, it needs to understand our context. In this case, the agent operates out of Cloudflare edge, a location remote to us. This implies we are unlikely to pick up a pizza from this <a href="https://www.cloudflare.com/learning/cdn/glossary/data-center/"><u>data center</u></a> if it was ever delivered.</p><p>The more capabilities we provide to the agent, the more it has the ability to create some disruption. Instead of someone having to make 5 clicks at a slow rate of 1 request per 10 seconds, they’d have a program running in a data center possibly making all 5 requests in a second.</p><p>This agent is simple, but now imagine many thousands of these — some benign, some not — running at datacenter speeds. This is the challenge origins will face.</p>
    <div>
      <h2>Protecting origins</h2>
      <a href="#protecting-origins">
        
      </a>
    </div>
    <p>For humans to interact with the online world, they need a web browser and some peripherals with which to direct the behavior of that browser. Agents are another way of directing a browser, so it may be tempting to think that not much is actually changing from the origin's point of view. Indeed, the most obvious change from the origin's point of view is merely where traffic comes from:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/304j2MNDUNwAaipqmH2Jbt/35beb792bda327a6cf0db3b642bbc4d6/unnamed-1.png" />
          </figure><p>The reason this change is significant has to do with the tools the server has to manage traffic. Websites generally try to be as permissive as possible, but they also need to manage finite resources (bandwidth, CPU, memory, storage, and so on). There are a few basic ways to do this:</p><ol><li><p><b>Global security policy</b>: A server may opt to slow down, CAPTCHA, or even temporarily block requests from all users. This policy may be applied to an entire site, a specific resource, or to requests classified as being part of a known or likely attack pattern. Such mechanisms may be deployed in reaction to an observed spike in traffic, as in a DDoS attack, or in anticipation of a spike in legitimate traffic, as in <a href="https://developers.cloudflare.com/waiting-room/"><u>Waiting Room</u></a>.</p></li><li><p><b>Incentives</b>: Servers sometimes try to incentivize users to use the site when more resources are available. For instance, a server price may be lower depending on the location or request time. This could be implemented with a <a href="https://developers.cloudflare.com/rules/snippets/when-to-use/"><u>Cloudflare Snippet</u></a>.</p></li></ol><p>While both tools can be effective, they also sometimes cause significant collateral damage. For example, while rate limiting a website's login endpoint <a href="https://developers.cloudflare.com/waf/rate-limiting-rules/best-practices/#protecting-against-credential-stuffing"><u>can help prevent credential stuffing attacks</u></a>, it also degrades the user experience for non-attackers. Before resorting to such measures, servers will first try to apply the security policy (whether a rate limit, a CAPTCHA, or an outright block) to individual users or groups of users.</p><p>However, in order to apply a security policy to individuals, the server needs some way of identifying them. Historically, this has been done via some combination of IP addresses, <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent"><u>User-Agent</u></a>, an account tied to the user identity (if available), and other fingerprints. Like most cloud service providers, Cloudflare has a <a href="https://developers.cloudflare.com/waf/rate-limiting-rules/best-practices/"><u>dedicated offering</u></a> for per-user rate limits based on such heuristics.</p><p>Fingerprinting works for the most part. However, it's unequitably distributed. On mobile, users <a href="https://blog.cloudflare.com/eliminating-captchas-on-iphones-and-macs-using-new-standard/#captchas-dont-work-in-mobile-environments-pats-remove-the-need-for-them"><u>have an especially difficult time solving CAPTCHA</u></a>s, when using a VPN they’re <a href="https://arstechnica.com/tech-policy/2023/07/meta-blocking-vpn-access-to-threads-in-eu/"><u>more</u></a> <a href="https://help.netflix.com/en/node/277"><u>likely</u></a> <a href="https://www.theregister.com/2015/10/19/bbc_cuts_off_vpn_to_iplayer/"><u>to</u></a> <a href="https://torrentfreak.com/hulu-blocks-vpn-users-over-piracy-concerns-140425/"><u>be</u></a> <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/troubleshooting/common-issues/"><u>blocked</u></a>, and when using <a href="https://www.peteresnyder.com/static/papers/speedreader-www2019.pdf"><u>reading mode</u></a> they can mess up their fingerprint, preventing rendering of the page.</p><p>Likewise, agentic AI only exacerbates the limitations of fingerprinting. Not only will more traffic be concentrated on a smaller source IP range, the agents themselves will run the same software and hardware platform, making it harder to distinguish honest from malicious users.</p><p>Something that could help is <a href="https://blog.cloudflare.com/web-bot-auth/"><u>Web Bot Auth</u></a>, which would allow agents to identify to the origin which platform they're operated by. However, we wouldn't want to extend this mechanism — intended for identifying the platform itself — to identifying individual users of the platforms, as this would create an unacceptable privacy risk for these users.</p><p>We need some way of implementing security controls for individual users without identifying them. But how? The Privacy Pass protocol provides <a href="https://blog.cloudflare.com/eliminating-captchas-on-iphones-and-macs-using-new-standard/#captchas-dont-work-in-mobile-environments-pats-remove-the-need-for-them"><u>a partial solution</u></a>.</p>
    <div>
      <h2>Privacy Pass and its limitations</h2>
      <a href="#privacy-pass-and-its-limitations">
        
      </a>
    </div>
    <p>Today, one of the most prominent use cases for Privacy Pass is to <a href="https://www.cloudflare.com/learning/bots/what-is-rate-limiting/"><u>rate limit</u></a> requests from a user to an origin, as we have <a href="https://blog.cloudflare.com/privacy-pass-standard/#privacy-pass-protocol"><u>discussed before</u></a>. The protocol works roughly as follows. The client is <b>issued</b> a number of <b>tokens</b>. Each time it wants to make a request, it <b>redeems</b> one of its tokens to the origin; the origin allows the request through only if the token is <b>fresh</b>, i.e., has never been observed before by the origin.</p><p>In order to use Privacy Pass for per-user rate-limiting, it's necessary to limit the number of tokens issued to each user (e.g., 100 tokens per user per hour). To rate limit an AI agent, this role would be fulfilled by the AI platform. To obtain tokens, the user would log in with the platform, and said platform would allow the user to get tokens from the issuer. The AI platform fulfills the <b>attester</b> role in Privacy Pass <a href="https://datatracker.ietf.org/doc/html/rfc9576"><u>parlance</u></a>. The attester is the party guaranteeing the per-user property of the rate limit. The AI platform, as an attester, is incentivized to enforce this token distribution as it stakes its reputation: Should it allow for too many tokens to be issued, the issuer could distrust them.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/62Rz5eS1UMm2pKorpowEGg/4949220bdf2fa3c39ccfa17d4df70fff/token__1_.png" />
          </figure><p>The issuance and redemption protocols are designed to have two properties:</p><ul><li><p>Tokens are <b>unforgeable</b>: only the issuer can issue valid tokens.</p></li><li><p>Tokens are <b>unlinkable: </b>no party, including the issuer, attester, or origin, can tell which user a token was issued to. </p></li></ul><p>These properties can be achieved using a <a href="https://csrc.nist.gov/glossary/term/cryptographic_primitive"><u>cryptographic primitive</u></a> called a <a href="https://blog.cloudflare.com/privacy-pass-the-math/"><u>blind signature</u></a><b> </b>scheme. In a conventional signature scheme, the signer uses its <b>private key</b> to produce a signature for a message. Later on, a verifier can use the signer’s <b>public key</b> to verify the signature. Blind signature schemes work in the same way, except that the message to be signed is blinded such that the signer doesn't know the message it's signing. The client “blinds” the message to be signed and sends it to the server, which then computes a blinded signature over the blinded message. The client obtains the final signature by unblinding the signature.  </p><p>This is exactly how the standardised Privacy Pass issuance protocols are defined by <a href="https://www.rfc-editor.org/rfc/rfc9578"><u>RFC 9578</u></a>:</p><ul>
  <li>
    <strong>Issuance:</strong> The user generates a random message 
    <strong>$k$</strong> 
    which we call the 
    <strong>nullifier</strong>. Concretely, this is just a random, 32-byte string. It then blinds the nullifier and sends it to the issuer. The issuer replies with a blind signature. Finally, the user unblinds the signature to get 
    <strong>$\sigma$</strong>, 
    a signature for the nullifier 
    <strong>$k$</strong>. The token is the pair 
    <strong>$(k, \sigma)$</strong>.
  </li>
  <li>
    <strong>Redemption:</strong> When the user presents 
    <strong>$(k, \sigma)$</strong>, 
    the origin checks that 
    <strong>$\sigma$</strong> 
    is a valid signature for the nullifier 
    <strong>$k$</strong> 
    and that 
    <strong>$k$</strong> 
    is fresh. If both conditions hold, then it accepts and lets the request through.
  </li>
</ul><p>Blind signatures are simple, cheap, and perfectly suited for many applications. However, they have some limitations that make them unsuitable for our use case.</p><p>First, the communication cost of the issuance protocol is too high. For each token issued, the user sends a 256-byte, blinded nullifier and the issuer replies with a 256-byte blind signature (assuming RSA-2048 is used). That's 0.5KB of additional communication per request, or 500KB for every 1,000 requests. This is manageable as we’ve seen in a <a href="https://eprint.iacr.org/2023/414.pdf"><u>previous experiment</u></a> for Privacy Pass, but not ideal. Ideally, the bandwidth would be sublinear in the rate limit we want to enforce. An alternative to blind signatures with lower compute time are Oblivious Pseudorandom Functions (<a href="https://datatracker.ietf.org/doc/rfc9497/"><u>VOPRF</u></a>), but the bandwidth is still asymptotically linear. We’ve <a href="https://blog.cloudflare.com/privacy-pass-the-math/"><u>discussed them in the past</u></a>, as they served as the basis for early deployments of Privacy Pass.</p><p>Second, blind signatures can't be used to rate-limit on a per-origin basis. Ideally, when issuing $N$ tokens to the client, the client would be able to redeem at most $N$ tokens at any origin server that can verify the token's validity. However, the client can't safely redeem the same token at more than one server because it would be possible for the servers to link those redemptions to the same client. What's needed is some mechanism for what we'll call <b>late origin-binding</b>: transforming a token for redemption at a particular origin in a way that's unlinkable to other redemptions of the same token.</p><p>Third, once a token is issued, it can't be revoked: it remains valid as long as the issuer's public key is valid. This makes it impossible for an origin to block a specific user if it detects an attack, or if its tokens are compromised. The origin can block the offending request, but the user can continue to make requests using its remaining token budget.</p>
    <div>
      <h2>Anonymous credentials and the future of Privacy Pass</h2>
      <a href="#anonymous-credentials-and-the-future-of-privacy-pass">
        
      </a>
    </div>
    <p>As noted by <a href="https://dl.acm.org/doi/pdf/10.1145/4372.4373"><u>Chaum</u></a> in 1985, an <b>anonymous credential</b> system allows users to obtain a credential from an issuer, and later prove possession of this credential, in an unlinkable way, without revealing any additional information. Also, it is possible to demonstrate that some attributes are attached to the credential.</p><p>One way to think of an anonymous credential is as a kind of blind signature with some additional capabilities: late-binding (link a token to an origin after issuance), multi-show (generate multiple tokens from a single issuer response), and expiration distinct from key rotation (token validity decoupled of the issuer cryptographic key validity). In the redemption flow for Privacy Pass, the client presents the unblinded message and signature to the server. To accept the redemption, the server needs to verify the signature. In an AC system, the client only presents a <b>part of the message</b>. In order for the server to accept the request, the client needs to prove to the server that it knows a valid signature for the entire message without revealing the whole thing.</p><p>The flow we described above would therefore include this additional <b>presentation</b> step. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7pb3ZDoAHbDLEt0mxtf67T/b6be11710a7df7a4df7d1c89788285a7/credentials__2_.png" />
          </figure><p>Note that the tokens generated through blind signatures or VOPRFs can only be used once, so they can be regarded as <i>single-use tokens</i>. However, there exists a type of anonymous credentials that allows tokens to be used multiple times. For this to work, the issuer grants a <i>credential</i> to the user, who can later derive at most <i>N</i> many single-use tokens for redemption. Therefore, the user can send multiple requests, at the expense of a single issuance session.  </p><p>The table below describes how blind signatures and anonymous credentials provide features of interest to rate limiting.</p><table><tr><td><p><b>Feature</b></p></td><td><p><b>Blind Signature</b></p></td><td><p><b>Anonymous Credential</b></p></td></tr><tr><td><p><b>Issuing Cost</b></p></td><td><p>Linear complexity: issuing 10 signatures is 10x as expensive as issuing one signature</p></td><td><p>Sublinear complexity: signing 10 attributes is cheaper than 10 individual signatures</p></td></tr><tr><td><p><b>Proof Capability</b></p></td><td><p>Only prove that a message has been signed</p></td><td><p>Allow efficient proving of partial statements (i.e., attributes)</p></td></tr><tr><td><p><b>State Management</b></p></td><td><p>Stateless</p></td><td><p>Stateful</p></td></tr><tr><td><p><b>Attributes</b></p></td><td><p>No attributes</p></td><td><p>Public (e.g. expiry time) and private state</p></td></tr></table><p>
  Let's see how a simple anonymous credential scheme works. The client's message consists of the pair 
  <strong>$(k, C)$</strong>, 
  where 
  <strong>$k$</strong> 
  is a 
  <strong>nullifier</strong> and 
  <strong>$C$</strong> 
  is a 
  <strong>counter</strong> representing the remaining number of times the client can access a resource. The value of the counter is controlled by the server: when the client redeems its credential, it presents both the nullifier and the counter. In response, the server checks that signature of the message is valid and that the nullifier is fresh, as before. Additionally, the server also
</p><ol><li><p>checks that the counter is greater than zero; and</p></li><li><p>decrements the counter issuing a new credential for the updated counter and a fresh nullifier.</p></li></ol><p>A blind signature could be used to meet this functionality. However, whereas the nullifier can be blinded as before, it would be necessary to handle the counter in plaintext so that the server can check that the counter is valid (Step 1) and update it (Step 2). This creates an obvious privacy risk since the server, which is in control of the counter, can use it to link multiple presentations by the same client. For example, when you reach out to buy a pepperoni pizza, the origin could assign you a special counter value, which eases fingerprinting when you present it a second time. Fortunately, there exist anonymous credentials designed to close this kind of privacy gap.</p><p>The scheme above is a simplified version of Anonymous Credit Tokens (<a href="https://datatracker.ietf.org/doc/draft-schlesinger-cfrg-act/"><u>ACT</u></a>), one of the anonymous credential schemes being considered for adoption by the <a href="https://datatracker.ietf.org/wg/privacypass/about/"><u>Privacy Pass working group</u></a> at IETF. The key feature of ACT is its <b>statefulness</b>: upon successful redemption, the server re-issues a new credential with updated nullifier and counter values. This creates a feedback loop between the client and server that can be used to express a variety of security policies.</p><p>By design, it's not possible to present ACT credentials multiple times simultaneously: the first presentation must be completed so that the re-issued credential can be presented in the next request. <b>Parallelism </b>is the key feature of Anonymous Rate-limited Credential (<a href="https://datatracker.ietf.org/doc/html/draft-yun-cfrg-arc-00"><u>ARC</u></a>), another scheme under discussion at the Privacy Pass working group. ARCs can be presented across multiple requests in parallel up to the presentation limit determined during issuance.</p><p>Another important feature of ARC is its support for late origin-binding: when a client is issued an ARC with presentation limit $N$, it can safely use its credential to present up to $N$ times to any origin that can verify the credential.</p><p>These are just examples of relevant features of some anonymous credentials. Some applications may benefit from a subset of them; others may need additional features. Fortunately, both ACT and ARC can be constructed from a small set of cryptographic primitives that can be easily adapted for other purposes.</p>
    <div>
      <h2>Building blocks for anonymous credentials</h2>
      <a href="#building-blocks-for-anonymous-credentials">
        
      </a>
    </div>
    <p>ARC and ACT share two primitives in common: <a href="https://eprint.iacr.org/2013/516.pdf"><b><u>algebraic MACs</u></b></a>, which provide for limited computations on the blinded message; and <a href="https://en.wikipedia.org/wiki/Zero-knowledge_proof"><b><u>zero-knowledge proofs (ZKP)</u></b></a> for proving validity of the part of the message not revealed to the server. Let's take a closer look at each.</p>
    <div>
      <h3>Algebraic MACs</h3>
      <a href="#algebraic-macs">
        
      </a>
    </div>
    <p>A Message Authenticated Code (MAC) is a cryptographic tag used to verify a message's authenticity (that it comes from the claimed sender) and integrity (that it has not been altered). Algebraic MACs are built from mathematical structures like <a href="https://en.wikipedia.org/wiki/Group_action"><u>group actions</u></a>. The algebraic structure gives them some additional functionality, one of them being a <i>homomorphism</i> that we can blind easily to conceal the actual value of the MAC. Adding a random value on an algebraic MAC blinds the value.</p><p>Unlike blind signatures, both ACT and ARC are only <i>privately</i> verifiable, meaning the issuer and the origin must both have the issuer's private key. Taking Cloudflare as an example, this means that a credential issued by Cloudflare can only be redeemed by an origin behind Cloudflare. Publicly verifiable variants of both are possible, but at an additional cost.</p>
    <div>
      <h3>Zero-Knowledge Proofs for linear relations</h3>
      <a href="#zero-knowledge-proofs-for-linear-relations">
        
      </a>
    </div>
    <p>Zero knowledge proofs (ZKP) allow us to prove a statement is true without revealing the exact value that makes the statement true. The ZKP is constructed by a prover in such a way that it can only be generated by someone who actually possesses the secret. The verifier can then run a quick mathematical check on this proof. If the check passes, the verifier is convinced that the prover's initial statement is valid. The crucial property is that the proof itself is just data that confirms the statement; it contains no other information that could be used to reconstruct the original secret.</p><p>For ARC and ACT, we want to prove <i>linear relations</i> of secrets. In ARC, a user needs to prove that different tokens are linked to the same original secret credential. For example, a user can generate a proof showing that a <i>request token</i> was derived from a valid <i>issued credential</i>. The system can verify this proof to confirm the tokens are legitimately connected, all without ever learning the underlying secret credential that ties them together. This allows the system to validate user actions while guaranteeing their privacy.</p><p>Proving simple linear relations can be extended to prove a number of powerful statements, for example that a number is in range. For example, this is useful to prove that you have a positive balance on your account. To prove your balance is positive, you prove that you can encode your balance in binary. Let’s say you can at most have 1024 credits in your account. To prove your balance is non-zero when it is, for example, 12, you prove two things simultaneously: first, that you have a set of binary bits, in this case 12=(1100)<sub>2</sub>, and second, that a linear equation using these bits (8*1 + 4*1 + 2*0 + 1*0) correctly adds up to your total committed balance. This convinces the verifier that the number is validly constructed without them learning the exact value. This is how it works for powers of two, but it can <a href="https://github.com/chris-wood/draft-arc/pull/38"><u>easily be extended to arbitrary ranges</u></a>.</p><p>The mathematical structure of algebraic MACs allows easy blinding and evaluation. The structure also allows for an easy proof that a MAC has been evaluated with the private key without revealing the MAC. In addition, ARC could use ZKPs to prove that a nonce has not been spent before. In contrast, ACT uses ZKPs to prove we have enough of a balance left on our token. The balance is subtracted homomorphically using more group structure.</p>
    <div>
      <h2>How much does this all cost?</h2>
      <a href="#how-much-does-this-all-cost">
        
      </a>
    </div>
    <p>Anonymous credentials allow for more flexibility, and have the potential to reduce the communication cost, compared to blind signatures in certain applications. To identify such applications, we need to measure the concrete communication cost of these new protocols. In addition, we need to understand how their CPU usage compares to blind signatures and oblivious pseudorandom functions.</p><p>We measure the time that each participant spends at each stage of some AC schemes. We also report the size of messages transmitted across the network. For ARC, ACT, and VOPRF, we'll use <a href="https://doi.org/10.17487/RFC9496"><u>ristretto255</u></a> as the prime group and SHAKE128 for hashing. For Blind RSA, we'll use a 2048-bit modulus and SHA-384 for hashing.</p><p>Each algorithm was implemented in Go, on top of the <a href="https://github.com/cloudflare/circl"><u>CIRCL</u></a> library. We plan to open source the code once the specifications of ARC and ACT begin to stabilize.</p><p>Let’s take a look at the most widely used deployment in Privacy Pass: Blind RSA. Redemption time is low, and most of the cost lies with the server at issuance time. Communication cost is mostly constant and in the order of 256 bytes.</p>
<div><table><thead>
  <tr>
    <th><span>Blind RSA</span><br /><a href="https://doi.org/10.17487/RFC9474"><span>RFC9474</span></a><span>(RSA-2048+SHA384)</span></th>
    <th><span>1 Token</span></th>
  </tr>
  <tr>
    <th><span>Time</span></th>
    <th><span>Message Size</span></th>
  </tr></thead>
<tbody>
  <tr>
    <td><span>Issuance</span></td>
    <td><span>Client (Blind)</span></td>
    <td><span>63 µs</span></td>
    <td><span>256 B</span></td>
  </tr>
  <tr>
    <td><span>Server (Evaluate)</span></td>
    <td><span>2.69 ms</span></td>
    <td><span>256 B</span></td>
  </tr>
  <tr>
    <td><span>Client (Finalize)</span></td>
    <td><span>37 µs</span></td>
    <td><span>256 B</span></td>
  </tr>
  <tr>
    <td><span>Redemption</span></td>
    <td><span>Client</span></td>
    <td><span> –</span></td>
    <td><span>300 B</span></td>
  </tr>
  <tr>
    <td><span>Server</span></td>
    <td><span>37 µs</span></td>
    <td><span>–</span></td>
  </tr>
</tbody></table></div><p>When looking at VOPRF, verification time on the server is slightly higher than for Blind RSA, but communication cost and issuance are much faster. Evaluation time on the server is 10x faster for 1 token, and more than 25x faster when using <a href="https://datatracker.ietf.org/doc/draft-ietf-privacypass-batched-tokens/"><u>amortized token issuance</u></a>. Communication cost per token is also more appealing, with a message size at least 3x lower.</p>
<div><table><thead>
  <tr>
    <th><span>VOPRF</span><br /><a href="https://doi.org/10.17487/RFC9497"><span>RFC9497</span></a><span>(Ristretto255+SHA512)</span></th>
    <th><span>1 Token</span></th>
    <th><span>1000 Amortized issuances</span></th>
  </tr>
  <tr>
    <th><span>Time</span></th>
    <th><span>Message Size</span></th>
    <th><span>Time </span><br /><span>(per token)</span></th>
    <th><span>Message Size </span><br /><span>(per token)</span></th>
  </tr></thead>
<tbody>
  <tr>
    <td><span>Issuance</span></td>
    <td><span>Client (Blind)</span></td>
    <td><span>54 µs</span></td>
    <td><span>32 B</span></td>
    <td><span>54 µs</span></td>
    <td><span>32 B</span></td>
  </tr>
  <tr>
    <td><span>Server (Evaluate)</span></td>
    <td><span>260 µs</span></td>
    <td><span>96 B</span></td>
    <td><span>99 µs</span></td>
    <td><span>32.064 B</span></td>
  </tr>
  <tr>
    <td><span>Client (Finalize)</span></td>
    <td><span>376 µs</span></td>
    <td><span>64 B</span></td>
    <td><span>173 µs</span></td>
    <td><span>64 B</span></td>
  </tr>
  <tr>
    <td><span>Redemption</span></td>
    <td><span>Client</span></td>
    <td><span> –</span></td>
    <td><span>96 B</span></td>
    <td><span>–</span></td>
  </tr>
  <tr>
    <td><span>Server</span></td>
    <td><span>57 µs</span></td>
    <td><span>–</span></td>
  </tr>
</tbody></table></div><p>This makes VOPRF tokens appealing for applications requiring a lot of tokens that can accept a slightly higher redemption cost, and that don’t need public verifiability.</p><p>Now, let’s take a look at the figures for ARC and ACT anonymous credential schemes. For both schemes we measure the time to issue a credential that can be presented at most $N=1000$ times.</p>
<div><table><thead>
  <tr>
    <th><span>Issuance</span><br /><span>Credential Generation</span></th>
    <th><span>ARC</span></th>
    <th><span>ACT</span></th>
  </tr>
  <tr>
    <th><span>Time</span></th>
    <th><span>Message Size</span></th>
    <th><span>Time</span></th>
    <th><span>Message Size</span></th>
  </tr></thead>
<tbody>
  <tr>
    <td><span>Client (Request)</span></td>
    <td><span>323 µs</span></td>
    <td><span>224 B</span></td>
    <td><span>64 µs</span></td>
    <td><span>141 B</span></td>
  </tr>
  <tr>
    <td><span>Server (Response)</span></td>
    <td><span>1349 µs</span></td>
    <td><span>448 B</span></td>
    <td><span>251 µs</span></td>
    <td><span>176 B</span></td>
  </tr>
  <tr>
    <td><span>Client (Finalize)</span></td>
    <td><span>1293 µs</span></td>
    <td><span>128 B</span></td>
    <td><span>204 µs</span></td>
    <td><span>176 B</span></td>
  </tr>
  <tr>
    <td></td>
  </tr>
  <tr>
    <td><span>Redemption</span><br /><span>Credential Presentation</span></td>
    <td><span>ARC</span></td>
    <td><span>ACT</span></td>
  </tr>
  <tr>
    <td><span>Time</span></td>
    <td><span>Message Size</span></td>
    <td><span>Time</span></td>
    <td><span>Message Size</span></td>
  </tr>
  <tr>
    <td><span>Client (Present)</span></td>
    <td><span>735 µs</span></td>
    <td><span>288 B</span></td>
    <td><span> 1740 µs</span></td>
    <td><span>1867 B</span></td>
  </tr>
  <tr>
    <td><span>Server (Verify/Refund)</span></td>
    <td><span>740 µs</span></td>
    <td><span>–</span></td>
    <td><span>1785 µs</span></td>
    <td><span>141 B</span></td>
  </tr>
  <tr>
    <td><span>Client (Update)</span></td>
    <td><span>–</span></td>
    <td><span>–</span></td>
    <td><span>508 µs</span></td>
    <td><span>176 B</span></td>
  </tr>
</tbody></table></div><p>As we would hope, the communication cost and the server’s runtime is much lower than a batched issuance with either Blind RSA or VOPRF. For example, a VOPRF issuance of 1000 tokens takes 99 ms (99 µs per token) <i>vs</i> 1.35 ms for issuing one ARC credential that allows for 1000 presentations. This is about 70x faster. The trade-off is that presentation is more expensive, both for the client and server.</p><p>How about ACT? Like ARC, we would expect the communication cost of issuance grows much slower with respect to the credits issued. Our implementation bears this out. However, there are some interesting performance differences between ARC and ACT: issuance is much cheaper for ACT than it is for ARC, but redemption is the opposite.</p><p>What's going on? The answer has largely to do with what each party needs to prove with ZKPs at each step. For example, during ACT redemption, the client proves to the server (in zero-knowledge) that its counter $C$ is in the desired range, i.e., $0 \leq C \leq N$. The proof size is on the order of $\log_{2} N$, which accounts for the larger message size. In the current version, ARC redemption does not involve range proofs, but a range proof may be added in a <a href="http://mailarchive.ietf.org/arch/msg/privacy-pass/A3VHUdHqhslwBzYEQjcaXzYQAxQ/"><u>future version</u></a>. Meanwhile, the statements the client and server need to prove during ARC issuance are a bit more complicated than for ARC presentation, which accounts for the difference in runtime there.</p><p>The advantage of anonymous credentials, as discussed in the previous sections, is that issuance only has to be performed once. When a server evaluates its cost, it takes into account the cost of all issuances and the cost of all verifications. At present, only accounting for credentials costs, it’s cheaper for a server to issue and verify tokens than verify an anonymous credential presentation.</p><p>The advantage of multiple-use anonymous credentials is that instead of the issuer generating $N$ tokens, the bulk of computation is offloaded to the clients. This is more scoped. Late origin binding allows them to work for multiple origins/namespace, range proof to decorrelate expiration from key rotation, and refund to provide a dynamic rate limit. Their current applications are dictated by the limitation of single-use token based schemes, more than by the added efficiency they provide. This seems to be an exciting area to explore, and see if closing the gap is possible.</p>
    <div>
      <h2>Managing agents with anonymous credentials</h2>
      <a href="#managing-agents-with-anonymous-credentials">
        
      </a>
    </div>
    <p>Managing agents will likely require features from both ARC and ACT.</p><p>ARC already has much of the functionality we need: it supports rate limiting, is communication-efficient, and it supports late origin-binding. Its main downside is that, once an ARC credential is issued, it can't be revoked. A malicious user can always make up to <i>N</i> requests to any origin it wants.</p><p>We can allow for a limited form of revocation by pairing ARC with blind signatures (or VOPRF). Each presentation of the ARC credential is accompanied by a Privacy Pass token: upon successful presentation, the client is issued another Privacy Pass token it can use during the next presentation. To revoke a credential, the server would simply not re-issue the token:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6EiHmkbLef6kXsQU473fcX/d1d4018eaf2abd42b9690ae5d01494dc/image1.png" />
          </figure><p>This scheme is already quite useful. However, it has some important limitations:</p><ul><li><p>Parallel presentation across origins is not possible: the client must wait for the request to one origin to succeed before it can initiate a request to a second origin.</p></li><li><p>Revocation is <i>global</i> rather than per-origin, meaning the credential is not only revoked for the origin to whom it was presented, but for every origin it can be presented to. We suspect this will be undesirable in some cases. For example, an origin may want to revoke if a request violates its <code>robots.txt</code> policy; but the same request may have been accepted by other origins.  </p></li></ul><p>A more fundamental limitation of this design is that the decision to revoke can only be made on the basis of a single request — the one in which the credential was presented. It may be risky to decide to block a user on the basis of a single request; in practice, attack patterns may only emerge across many requests. ACT's statefulness enables at least a rudimentary form of this kind of defense. Consider the following scheme:</p><ul><li><p><b>Issuance: </b>The client is issued an ARC with presentation limit $N=1$.</p></li><li><p><b>Presentation:</b></p><ul><li><p>When the client presents its ARC credential to an origin for the first time, the server issues an ACT credential with a valid initial state.</p></li><li><p>When the client presents an ACT with valid state (e.g., credit counter greater than 0), the origin either:</p><ul><li><p>refuses to issue a new ACT, thereby revoking the credential. It would only do so if it had high confidence that the request was part of an attack; or</p></li><li><p>issues a new ACT with state updated to reduce the ACT credit by the amount of resources consumed while processing the request.</p></li></ul></li></ul></li></ul><p>Benign requests wouldn't change the state by much (if at all), but suspicious requests might impact the state in a way that gets the user closer to their rate limit much faster.</p>
    <div>
      <h2>Demo</h2>
      <a href="#demo">
        
      </a>
    </div>
    <p>To see how this idea works in practice, let's look at a working example that uses the <a href="https://developers.cloudflare.com/agents/model-context-protocol/"><u>Model Context Protocol</u></a>. The demo below is built using<a href="https://developers.cloudflare.com/agents/model-context-protocol/tools/"> <u>MCP Tools</u></a>. <a href="https://modelcontextprotocol.info/tools/"><u>Tools</u></a> are extensions the AI agent can call to extend its capabilities. They don't need to be integrated at release time within the MCP client. This provides a nice and easy prototyping avenue for anonymous credentials.</p><p>Tools are offered by the server via an MCP compatible interface. You can see details on how to build such MCP servers in a <a href="https://blog.cloudflare.com/remote-model-context-protocol-servers-mcp/"><u>previous blog</u></a>.</p><p>In our pizza context, this could look like a pizzeria that offers you a voucher. Each voucher gets you 3 pizza slices. Mocking a design, an integration within a chat application could look as follows:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5WD5MYoSMYGyRW2biwe6j4/bde101967276a72d48d9e494a23db5fa/image5.png" />
          </figure>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5SEqaVpwFxS1D21oyjjbN8/80dde2484f43c15e206ecfda991c286a/image9.png" />
          </figure><p>The first panel presents all tools exposed by the MCP server. The second one showcases an interaction performed by the agent calling these tools.</p><p>To look into how such a flow would be implemented, let’s write the MCP tools, offer them in an MCP server, and manually orchestrate the calls with the <a href="https://modelcontextprotocol.io/docs/tools/inspector"><u>MCP Inspector</u></a>.</p><p>The MCP server should provide two tools:</p><ul><li><p><code>act-issue </code>which issues an ACT credential valid for 3 requests. The code used here is an earlier version of the IETF draft which has some limitations.</p></li><li><p><code>act-redeem</code> makes a presentation of the local credential, and fetches our pizza menu.</p></li></ul><p>First, we run <code>act-issue</code>. At this stage, we could ask the agent to run an<a href="https://modelcontextprotocol.info/specification/draft/basic/authorization/"> <u>OAuth flow</u></a>, fetch an internal authentication endpoint, or to compute a proof of work.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6sLS7jMfTHPjVW5vMvsTWX/2d2b10fdb12c64f0e33fee89e09eab85/image10.png" />
          </figure><p>This gives us 3 credits to spend against an origin. Then, we run <code>act-redeem</code></p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1YTc0Wohrsqw3hizAOmJjU/4534cccbc490ad0aa09522a3875693af/image8.png" />
          </figure><p>Et voilà. If we run <code>act-redeem</code> once more, we see we have one fewer credit.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/a0zmBfl46hX33hWoXyGyX/86649d9f435562c95a85ec72fbf33022/image3.png" />
          </figure><p>You can test it yourself, here are the <a href="https://github.com/cloudflareresearch/anonymous-credentials-agent-demo"><u>source codes</u></a> available. The MCP server is written in<a href="https://github.com/modelcontextprotocol/rust-sdk/"> <u>Rust</u></a> to integrate with the <a href="https://github.com/SamuelSchlesinger/anonymous-credit-tokens/stargazers"><u>ACT rust</u></a> library. The <a href="https://act-client-demo.cloudflareresearch.com/"><u>browser-based client</u></a> works similarly, check it out.</p>
    <div>
      <h2>Moving further</h2>
      <a href="#moving-further">
        
      </a>
    </div>
    <p>In this post, we’ve presented a concrete approach to rate limit agent traffic. It is in full control of the client, and is built to protect the user's privacy. It uses emerging standards for anonymous credentials, integrates with MCP, and can be readily deployed on Cloudflare Workers.</p><p>We're on the right track, but there are still questions that remain. As we touched on before, a notable limitation of both ARC and ACT is that they are only <i>privately verifiable</i>. This means that the issuer and origin need to share a private key, for issuing and verifying the credential respectively. There are likely to be deployment scenarios for which this isn't possible. Fortunately, there may be a path forward for these cases using<i> pairing-</i>based cryptography, as in the <a href="https://datatracker.ietf.org/doc/draft-irtf-cfrg-bbs-signatures/"><u>BBS signature specification</u></a> making its way through IETF. We’re also exploring post-quantum implications in a <a href="https://blog.cloudflare.com/pq-anonymous-credentials/"><u>concurrent post</u></a>.</p><p>If you are an agent platform, an agent developer, or a browser, all our code is available on <a href="https://github.com/cloudflareresearch/anonymous-credentials-agent-demo"><u>GitHub</u></a> for you to experiment. Cloudflare is actively working on vetting this approach for real-world use cases.</p><p>The specification and discussion are happening within the IETF and W3C. This ensures the protocols are built in the open, and receive participation from experts. Improvements are still to be made to clarify the right performance-to-privacy tradeoff, or even the story to deploy on the open web.</p><p>If you’d like to help us, <a href="https://blog.cloudflare.com/cloudflare-1111-intern-program/"><u>we’re hiring 1,111 interns</u></a> over the course of next year, and have <a href="https://www.cloudflare.com/careers/early-talent/"><u>open positions</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Rate Limiting]]></category>
            <guid isPermaLink="false">1znqOjDHsm8kxWujPMhsgA</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Christopher Patton</dc:creator>
            <dc:creator>Lena Heimberger</dc:creator>
            <dc:creator>Armando Faz-Hernández</dc:creator>
        </item>
        <item>
            <title><![CDATA[Addressing the unauthorized issuance of multiple TLS certificates for 1.1.1.1]]></title>
            <link>https://blog.cloudflare.com/unauthorized-issuance-of-certificates-for-1-1-1-1/</link>
            <pubDate>Thu, 04 Sep 2025 17:30:00 GMT</pubDate>
            <description><![CDATA[ Unauthorized TLS certificates were issued for 1.1.1.1 by a Certification Authority without permission from Cloudflare. These rogue certificates have now been revoked. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Over the past few days Cloudflare has been notified through our vulnerability disclosure program and the <a href="https://groups.google.com/g/certificate-transparency/c/we_8SNGqA3w/m/ILXqa0hzAgAJ?utm_medium=email&amp;utm_source=footer"><u>certificate transparency mailing list</u></a> that unauthorized certificates were issued by <a href="https://www.fina.hr/"><u>Fina CA</u></a> for 1.1.1.1, one of the IP addresses used by our <a href="https://one.one.one.one/"><u>public DNS resolver service</u></a>. From February 2024 to August 2025, Fina CA <a href="https://crt.sh/?iPAddress=1.1.1.1&amp;match=="><u>issued</u></a> twelve certificates for 1.1.1.1 without our permission. We did not observe unauthorized issuance for any properties managed by Cloudflare other than 1.1.1.1.</p><p>We have no evidence that bad actors took advantage of this error. To impersonate Cloudflare's public DNS resolver 1.1.1.1, an attacker would not only require an unauthorized certificate and its corresponding private key, but attacked users would also need to trust the Fina CA. Furthermore, traffic between the client and 1.1.1.1 would have to be intercepted.</p><p>While this unauthorized issuance is an unacceptable lapse in security by Fina CA, we should have caught and responded to it earlier. After speaking with Fina CA, it appears that they issued these certificates for the purposes of internal testing. However, no CA should be issuing certificates for domains and IP addresses without checking control. At present all certificates have been <a href="http://rdc.fina.hr/RDC2020/FinaRDCCA2020partc1.crl"><u>revoked</u></a>. We are awaiting a full post-mortem from Fina.</p><p>While we regret this situation, we believe it is a useful opportunity to walk through how trust works on the Internet between networks like ourselves, destinations like 1.1.1.1, CAs like Fina, and devices like the one you are using to read this. To learn more about the mechanics, please keep reading.</p>
    <div>
      <h3>Background</h3>
      <a href="#background">
        
      </a>
    </div>
    <p>Cloudflare operates a <a href="https://one.one.one.one/"><u>public DNS resolver 1.1.1.1 service</u></a> that millions of devices use to resolve domain names from a human-readable format such as example.com to an IP address like 192.0.2.42 or 2001:db8::2a.</p><p>The 1.1.1.1 service is accessible using various methods, across multiple domain names, such as <a href="https://cloudflare-dns.com"><u>cloudflare-dns.com</u></a> and <a href="https://one.one.one.one"><u>one.one.one.one</u></a>, and also using various IP addresses, such as 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, and 2606:4700:4700::1001. <a href="https://one.one.one.one/family/"><u>1.1.1.1 for Families</u></a> also provides public DNS resolver services and is hosted on different IP addresses — 1.1.1.2, 1.1.1.3, 1.0.0.2, 1.0.0.3, 2606:4700:4700::1112, 2606:4700:4700::1113, 2606:4700:4700::1002, 2606:4700:4700::1003.</p><p>As originally specified in <a href="https://datatracker.ietf.org/doc/html/rfc1034"><u>RFC 1034</u></a> and <a href="https://datatracker.ietf.org/doc/html/rfc1035"><u>RFC 1035</u></a>, the DNS protocol includes no privacy or authenticity protections. DNS queries and responses are exchanged between client and server in plain text over UDP or TCP. These represent around 60% of queries received by the Cloudflare 1.1.1.1 service. The lack of privacy or authenticity protection means that any intermediary can potentially read the DNS query and response and modify them without the client or the server being aware.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zbEvgOCwZomZTbgSGFuEo/d638f36eebdbf2577ea0b8172dff843e/image1.png" />
          </figure><p>To address these shortcomings, we have helped develop and deploy multiple solutions at the IETF. The two of interest to this post are DNS over TLS (DoT, <a href="https://datatracker.ietf.org/doc/html/rfc7858"><u>RFC 7878</u></a>) and DNS over HTTPS (DoH, <a href="https://datatracker.ietf.org/doc/html/rfc8484"><u>RFC 8484</u></a>). In both cases the DNS protocol itself is mainly unchanged, and the desirable security properties are implemented in a lower layer, replacing the simple use of plain-text in UDP and TCP in the original specification. Both DoH and DoT use TLS to establish an authenticated, private, and encrypted channel over which DNS messages can be exchanged. To learn more you can read <a href="https://blog.cloudflare.com/dns-encryption-explained/"><u>DNS Encryption Explained</u></a>.</p><p>During the <a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/"><u>TLS handshake</u></a>, the server proves its identity to the client by presenting a certificate. The client validates this certificate by verifying that it is signed by a Certification Authority that it already trusts. Only then does it establish a connection with the server. Once connected, TLS provides encryption and integrity for the DNS messages exchanged between client and server. This protects DoH and DoT against eavesdropping and tampering between the client and server.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/21YeKS2nYIFDI9uC3uClXE/6115e00945458d42627d973aef75076c/image2.png" />
          </figure><p>The TLS certificates used in DoT and DoH are the same kinds of certificates HTTPS websites serve. Most website certificates are issued for domain names like <a href="http://example.com"><u>example.com</u></a>. When a client connects to that website, they resolve the name <a href="http://example.com"><u>example.com</u></a> to an IP like 192.0.2.42, then connect to the domain on that IP address. The server responds with a TLS certificate containing <a href="http://example.com"><u>example.com</u></a>, which the device validates.</p><p>However, DNS server certificates tend to be used slightly differently. Certificates used for DoT and DoH have to contain the service IP addresses, not just domain names. This is due to clients being unable to resolve a domain name in order to contact their resolver, like <a href="https://cloudflare-dns.com"><u>cloudflare-dns.com</u></a>. Instead, devices are first set up by connecting to their resolver via a known IP address, such as 1.1.1.1 in the case of Cloudflare public DNS resolver. When this connection uses DoT or DoH, the resolver responds with a TLS certificate issued for that IP address, which the client validates. If the certificate is valid, the client believes that it is talking to the owner of 1.1.1.1 and starts sending DNS queries.</p><p>You can see that the IP addresses are included in the certificate Cloudflare’s public resolver uses for DoT/DoH:</p>
            <pre><code>Certificate:
  Data:
      Version: 3 (0x2)
      Serial Number:
          02:7d:c8:c5:e1:72:94:ae:c9:ed:3f:67:72:8e:8a:08
      Signature Algorithm: sha256WithRSAEncryption
      Issuer: C=US, O=DigiCert Inc, CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1
      Validity
          Not Before: Jan  2 00:00:00 2025 GMT
          Not After : Jan 21 23:59:59 2026 GMT
      Subject: C=US, ST=California, L=San Francisco, O=Cloudflare, Inc., CN=cloudflare-dns.com
      X509v3 extensions:
          X509v3 Subject Alternative Name:
              DNS:cloudflare-dns.com, DNS:*.cloudflare-dns.com, DNS:one.one.one.one, IP Address:1.0.0.1, IP Address:1.1.1.1, IP Address:162.159.36.1, IP Address:162.159.46.1, IP Address:2606:4700:4700:0:0:0:0:1001, IP Address:2606:4700:4700:0:0:0:0:1111, IP Address:2606:4700:4700:0:0:0:0:64, IP Address:2606:4700:4700:0:0:0:0:6400</code></pre>
            
    <div>
      <h3>Rogue certificate issuance</h3>
      <a href="#rogue-certificate-issuance">
        
      </a>
    </div>
    <p>The section above describes normal, expected use of Cloudflare public DNS resolver 1.1.1.1 service, using certificates managed by Cloudflare. However, Cloudflare has been made aware of other, unauthorized certificates being issued for 1.1.1.1. Since certificate validation is the mechanism by which DoH and DoT clients establish the authenticity of a DNS resolver, this is a concern. Let’s now dive a little further in the security model provided by DoH and DoT.</p><p>Consider a client that is preconfigured to use the 1.1.1.1 resolver service using DoT. The client must establish a TLS session with the configured server before it can send any DNS queries. To be trusted, the server needs to present a certificate issued by a CA that the client trusts. The collection of certificates trusted by the client is also called the root store.</p>
            <pre><code>Certificate:
  Data:
      Version: 3 (0x2)
      Serial Number:
          02:7d:c8:c5:e1:72:94:ae:c9:ed:3f:67:72:8e:8a:08
      Signature Algorithm: sha256WithRSAEncryption
      Issuer: C=US, O=DigiCert Inc, CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1</code></pre>
            <p>A Certification Authority (CA) is an organisation, such as DigiCert in the section above, whose role is to receive requests to sign certificates and verify that the requester has control of the domain. In this incident, Fina CA issued certificates for 1.1.1.1 without Cloudflare's involvement. This means that Fina CA did not properly check whether the requestor had legitimate control over 1.1.1.1. According to Fina CA:</p><blockquote><p>“They were issued for the purpose of internal testing of certificate issuance in the production environment. An error occurred during the issuance of the test certificates when entering the IP addresses and as such they were published on Certificate Transparency log servers.”</p></blockquote><p>Although it’s not clear whether Fina CA sees it as an error, we emphasize that it is not an error to publish test certificates on Certificate Transparency (more about what that is later on). Instead, the error at hand is Fina CA using their production keys to sign a certificate for an IP address without permission of the controller. We have <a href="https://ripe84.ripe.net/archives/video/747/"><u>talked about</u></a> misuse of 1.1.1.1 in documentation, lab, and testing environments at length. Instead of the Cloudflare public DNS resolver 1.1.1.1 IP address, Fina should have used an IP address it controls itself.</p><p>Unauthorized certificates are unfortunately not uncommon, whether due to negligence — such as <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1930029"><u>IdenTrust</u></a> in November 2024 — or compromise. Famously in 2011, the Dutch CA DigiNotar was <a href="https://threatpost.com/final-report-diginotar-hack-shows-total-compromise-ca-servers-103112/77170/"><u>hacked</u></a>, and its keys were used to issue hundreds of certificates. This hack was a wake-up call and motivated the introduction of Certificate Transparency (CT), later formalised in <a href="https://datatracker.ietf.org/doc/html/rfc6962"><u>RFC 6962</u></a>. The goal of Certificate Transparency is not to directly prevent misissuance, but to be able to detect any misissuance once it has happened, by making sure every certificate issued by a CA is publicly available for inspection.</p><p>In certificate transparency several independent parties, including <a href="https://blog.cloudflare.com/introducing-certificate-transparency-monitoring/"><u>Cloudflare</u></a>, operate public logs of issued certificates. Many modern browsers do not accept certificates unless they provide proof in the form of signed certificate timestamps (<a href="https://certificate.transparency.dev/howctworks/"><u>SCT</u></a>s) that the certificate has been logged in at least two logs. Domain owners can therefore monitor all public CT logs for any certificate containing domains they care about. If they see a certificate for their domains that they did not authorize, they can raise the alarm. CT is also the data source for public services such as <a href="https://crt.sh"><u>crt.sh</u></a> and Cloudflare Radar’s <a href="https://radar.cloudflare.com/certificate-transparency"><u>certificate transparency page</u></a>.</p><p>Not all clients require proof of inclusion in certificate transparency. Browsers do, but most DNS clients don’t. We were fortunate that Fina CA did submit the unauthorized certificates to the CT logs, which allowed them to be discovered.</p>
    <div>
      <h3>Investigation into potential malicious use</h3>
      <a href="#investigation-into-potential-malicious-use">
        
      </a>
    </div>
    <p>Our immediate concern was that someone had maliciously used the certificates to impersonate the 1.1.1.1 service. Such an attack would require all the following:</p><ol><li><p>An attacker would require a rogue certificate and its corresponding private key.</p></li><li><p>Attacked clients would need to trust the Fina CA.</p></li><li><p>Traffic between the client and 1.1.1.1 would have to be intercepted.</p></li></ol><p>In light of this incident, we have reviewed these requirements one by one:</p><p>1. We know that a certificate was issued without Cloudflare's involvement. We must assume that a corresponding private key exists, which is not under Cloudflare's control. This could be used by an attacker. Fina CA wrote to us that the private keys were exclusively in Fina’s controlled environment and were immediately destroyed even before the certificates were revoked. As we have no way to verify this, we have and continue to take steps to detect malicious use as described in point 3.</p><p>2. Furthermore, some clients trust Fina CA. It is included by default in <a href="https://learn.microsoft.com/en-us/security/trusted-root/participants-list"><u>Microsoft’s root store</u></a> and in an <a href="https://eidas.ec.europa.eu/efda/trust-services/browse/eidas/tls"><u>EU Trust Service provider</u></a>. We can exclude some clients, as the CA certificate is not included by default in the root stores of <a href="https://android.googlesource.com/platform/system/ca-certificates/+/master/files/"><u>Android</u></a>, <a href="https://support.apple.com/en-us/HT209143"><u>Apple</u></a>, <a href="https://wiki.mozilla.org/CA/Included_Certificates"><u>Mozilla</u></a>, or <a href="https://g.co/chrome/root-policy"><u>Chrome</u></a>. These users cannot have been affected with these default settings. For these certificates to be used nefariously, the client’s root store must include the Certification Authority (CA) that issued them. Upon discovering the problem, we immediately reached out to Fina CA, Microsoft, and the <a href="https://eidas.ec.europa.eu/efda/trust-services/browse/eidas/tls/tl/HR"><u>EU Trust Service provider</u></a>. Microsoft responded quickly, and started rolling out an update to their <i>disallowed list</i>, which should cause clients that use it to stop trusting the certificate.</p><p>3. Finally, we have launched an investigation into possible interception between users and 1.1.1.1. The first way this could happen is when the attacker is on-path of the client request. Such man-in-the-middle attacks are likely to be invisible to us. Clients will get responses from their on-path middlebox and we have no reliable way of telling that is happening. On-path interference has been a persistent problem for 1.1.1.1, which we’ve been <a href="https://blog.cloudflare.com/fixing-reachability-to-1-1-1-1-globally/"><u>working on</u></a> ever since we announced 1.1.1.1.</p><p>A second scenario can occur when a malicious actor is off-path, but is able to hijack 1.1.1.1 routing via BGP. These are scenarios we have discussed in a<a href="https://blog.cloudflare.com/bgp-hijack-detection/"> <u>previous blog post</u></a>, and <a href="https://manrs.org/2024/05/rpki-rov-deployment-reaches-major-milestone/"><u>increasing adoption of RPKI route origin validation (ROV)</u></a> makes BGP hijacks with high penetration harder. We looked at the historical BGP announcements involving 1.1.1.1, and have found no evidence that such routing hijacks took place.</p><p>Although we cannot be certain, so far we have seen no evidence that these certificates have been used to impersonate Cloudflare public DNS resolver 1.1.1.1 traffic. In later sections we discuss the steps we have taken to prevent such impersonation in the future, as well as concrete actions you can take to protect your own systems and users.</p>
    <div>
      <h3>A closer look at the unauthorized certificates attributes</h3>
      <a href="#a-closer-look-at-the-unauthorized-certificates-attributes">
        
      </a>
    </div>
    <p>All unauthorized certificates for 1.1.1.1 were valid for exactly one year and included other domain names. Most of these domain names are not registered, which indicates that the certificates were issued without proper domain control validation. This violates sections 3.2.2.4 and 3.2.2.5 of the CA/Browser Forum’s <a href="https://cabforum.org/working-groups/server/baseline-requirements/requirements/#3224-validation-of-domain-authorization-or-control"><u>Baseline Requirements</u></a>, and sections 3.2.2.3 and 3.2.2.4 of the <a href="https://rdc.fina.hr/RDC2015/CPWSA1-12-en.pdf"><u>Fina CA Certificate Policy</u></a>.</p><p>The full list of domain names we identified on the unauthorized certificates are as follows:</p>
            <pre><code>fina.hr
ssltest5
test.fina.hr
test.hr
test1.hr
test11.hr
test12.hr
test5.hr
test6
test6.hr
testssl.fina.hr
testssl.finatest.hr
testssl.hr
testssl1.finatest.hr
testssl2.finatest.hr</code></pre>
            <p>It’s also worth noting that the Subject attribute points to a fictional organisation <b>TEST D.D.</b>, as can be seen on this unauthorized certificate:</p>
            <pre><code>        Serial Number:
            a5:30:a2:9c:c1:a5:da:40:00:00:00:00:56:71:f2:4c
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=HR, O=Financijska agencija, CN=Fina RDC 2015
        Validity
            Not Before: Nov  2 23:45:15 2024 GMT
            Not After : Nov  2 23:45:15 2025 GMT
        Subject: C=HR, O=TEST D.D., L=ZAGREB, CN=testssl.finatest.hr, serialNumber=VATHR-32343828408.306
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:testssl.finatest.hr, DNS:testssl2.finatest.hr, IP Address:1.1.1.1</code></pre>
            
    <div>
      <h3>Incident timeline and impact</h3>
      <a href="#incident-timeline-and-impact">
        
      </a>
    </div>
    <p><i>All timestamps are UTC. All certificates are identified by their date of validity.</i></p><p>The <a href="https://crt.sh/?id=12116084225"><u>first certificate</u></a> was issued to be valid starting February 2024, and revoked 33 min later. 11 certificate issuances with common name 1.1.1.1 followed from February 2024 to August 2025. Public reports have been made on <a href="https://news.ycombinator.com/item?id=45089708"><u>Hacker News</u></a> and on the <a href="https://groups.google.com/g/certificate-transparency/c/we_8SNGqA3w/m/ILXqa0hzAgAJ"><u>certificate-transparency mailing list</u></a> early in September 2025, which Cloudflare responded to.</p><p>While responding to the incident, we identified the full list of misissued certificates, their revocation status, and which clients trust them.</p><p>The full timeline for the incident is as follows.</p><table><tr><td><p><b>Date &amp; Time (UTC)</b></p></td><td><p><b>Event Description</b></p></td></tr><tr><td><p>2024-02-18 11:07:33</p></td><td><p><a href="https://crt.sh/?id=12116084225"><u>First certificate issuance</u></a> revoked on 2024-02-18 11:40:00</p></td></tr><tr><td><p>2024-09-25 08:04:03</p></td><td><p><a href="https://crt.sh/?id=14681939427"><u>Issuance</u></a> revoked on 2024-11-06 07:36:05</p></td></tr><tr><td><p>2024-10-04 07:55:38</p></td><td><p><a href="https://crt.sh/?id=14793030836"><u>Issuance</u></a> revoked on 2024-10-04 07:56:56</p></td></tr><tr><td><p>2024-10-04 08:05:48</p></td><td><p><a href="https://crt.sh/?id=14793121895"><u>Issuance</u></a> revoked on 2024-11-06 07:39:55</p></td></tr><tr><td><p>2024-10-15 06:28:48</p></td><td><p><a href="https://crt.sh/?id=14939369380"><u>Issuance</u></a> revoked on 2024-11-06 07:35:36</p></td></tr><tr><td><p>2024-11-02 23:45:15</p></td><td><p><a href="https://crt.sh/?id=15190039061"><u>Issuance</u></a> revoked on 2024-11-02 23:48:42</p></td></tr><tr><td><p>2025-03-05 09:12:23</p></td><td><p><a href="https://crt.sh/?id=16939550348"><u>Issuance</u></a> revoked on 2025-03-05 09:13:22</p></td></tr><tr><td><p>2025-05-24 22:56:21</p></td><td><p><a href="https://crt.sh/?id=18603461241"><u>Issuance</u></a> revoked on 2025-09-04 06:13:27</p></td></tr><tr><td><p>2025-06-28 23:05:32</p></td><td><p><a href="https://crt.sh/?id=19318694206"><u>Issuance</u></a> revoked on 2025-07-18 07:01:27</p></td></tr><tr><td><p>2025-07-18 07:05:23</p></td><td><p><a href="https://crt.sh/?id=19749594221"><u>Issuance</u></a> revoked on 2025-07-18 07:09:45</p></td></tr><tr><td><p>2025-07-18 07:13:14</p></td><td><p><a href="https://crt.sh/?id=19749721864"><u>Issuance</u></a> revoked on 2025-09-04 06:30:36</p></td></tr><tr><td><p>2025-08-26 07:49:00</p></td><td><p><a href="https://crt.sh/?id=20582951233"><u>Last certificate issuance</u></a> revoked on 2025-09-04 06:33:20</p></td></tr><tr><td><p>2025-09-01 05:23:00</p></td><td><p><a href="https://news.ycombinator.com/item?id=45089708"><u>HackerNews submission</u></a> about a possible unauthorized issuance</p></td></tr><tr><td><p>2025-09-02 04:50:00</p></td><td><p>Report shared with us on HackerOne, but was mistriaged</p></td></tr><tr><td><p>2025-09-03 02:35:00</p></td><td><p>Second report shared with us on HackerOne, but also mistriaged.</p></td></tr><tr><td><p>2025-09-03 10:59:00</p></td><td><p><a href="https://groups.google.com/g/certificate-transparency/c/we_8SNGqA3w/m/ILXqa0hzAgAJ?utm_medium=email&amp;utm_source=footer"><u>Report sent</u></a> on the public <a><u>certificate-transparency@googlegroups.com</u></a> mailing picked up by the team.</p></td></tr><tr><td><p>2025-09-03 11:33:00</p></td><td><p>First response by Cloudflare on the mailing list about starting the investigation</p></td></tr><tr><td><p>2025-09-03 12:08:00</p></td><td><p>Incident declared</p></td></tr><tr><td><p>2025-09-03 12:16:00</p></td><td><p>Notification of an unauthorised issuance sent to Fina CA, Microsoft Root Store, and EU Trust service provider</p></td></tr><tr><td><p>2025-09-03 12:23:00</p></td><td><p>Cloudflare identifies an initial list of nine rogue certificates</p></td></tr><tr><td><p>2025-09-03 12:24:00</p></td><td><p>Outreach to Fina CA to inform them about the unauthorized issuance, requesting revocation</p></td></tr><tr><td><p>2025-09-03 12:26:00</p></td><td><p>Identify the number of requests served on 1.1.1.1 IP address, and associated names/services</p></td></tr><tr><td><p>2025-09-03 12:42:00</p></td><td><p>As a precautionary measure, began investigation to rule out the possibility of a BGP hijack for 1.1.1.1</p></td></tr><tr><td><p>2025-09-03 18:48:00</p></td><td><p>Second notification of the incident to Fina CA</p></td></tr><tr><td><p>2025-09-03 21:27:00</p></td><td><p>Microsoft Root Store notifies us that they are preventing further use of the identified unauthorized certificates by using their quick-revocation mechanism.</p></td></tr><tr><td><p>2025-09-04 06:13:27</p></td><td><p>Fina revoked all certificates.</p></td></tr><tr><td><p>2025-09-04 12:44:00</p></td><td><p>Cloudflare receives a response from Fina indicating “an error occurred during the issuance of the test certificates when entering the IP addresses and as such they were published on Certificate Transparency log servers. [...] Fina will eliminate the possibility of such an error recurring.”</p></td></tr></table>
    <div>
      <h3>Remediation and follow-up steps</h3>
      <a href="#remediation-and-follow-up-steps">
        
      </a>
    </div>
    <p>Cloudflare has invested from the very start in the Certificate Transparency ecosystem. Not only do we operate CT logs ourselves, we also run a CT monitor that we use to <a href="https://developers.cloudflare.com/ssl/edge-certificates/additional-options/certificate-transparency-monitoring/"><u>alert customers when certificates are mis-issued for their domains</u></a>.</p><p>It is therefore disappointing that we failed to properly monitor certificates for our own domain. We failed three times. The first time because 1.1.1.1 is an IP certificate and our system failed to alert on these. The second time because even if we were to receive certificate issuance alerts, as any of our customers can, we did not implement sufficient filtering. With the sheer number of names and issuances we manage it has not been possible for us to keep up with manual reviews. Finally, because of this noisy monitoring, we did not enable alerting for all of our domains. We are addressing all three shortcomings.</p><p>We double-checked all certificates issued for our names, including but not limited to 1.1.1.1, using certificate transparency, and confirmed that as of 3 September, the Fina CA issued certificates are the only unauthorized issuances. We contacted Fina, and the root programs we know that trust them, to ask for revocation and investigation. The certificates have been revoked.</p><p>Despite no indication of usage of these certificates so far, we take this incident extremely seriously. We have identified several steps we can take to address the risk of these sorts of problems occurring in the future, and we plan to start working on them immediately:</p><p><b>Alerting</b>: Cloudflare will improve alerts and escalation for issuance of certificates for missing Cloudflare owned domains including 1.1.1.1 certificates.</p><p><b>Transparency</b>: The issuance of these unauthorised 1.1.1.1 certificates were detected because Fina CA used Certificate Transparency. Transparency inclusion is not enforced by most DNS clients, which implies that this detection was a lucky one. We are working on bringing transparency to non-browser clients, in particular DNS clients that rely on TLS.</p><p><b>Bug Bounty</b>: Our procedure for triaging reports made through our vulnerability disclosure program was the cause for a delayed response. We are working to revise our triaging process to ensure such reports get the right visibility.</p><p><b>Monitoring</b>: During this incident, our team relied on <a href="https://crt.sh"><u>crt.sh</u></a> to provide us a convenient UI to explore CA issued certificates. We’d like to give a shout to the <a href="https://www.sectigo.com/"><u>Sectigo team</u></a> for maintaining this tool. Given Cloudflare is an active CT Monitor, we have started to build a dedicated UI to explore our data <a href="https://radar.cloudflare.com/certificate-transparency"><u>in Radar</u></a>. We are looking to enable exploration of certs with IP addresses as common names to Radar as well.</p>
    <div>
      <h3>What steps should you take?</h3>
      <a href="#what-steps-should-you-take">
        
      </a>
    </div>
    <p>This incident demonstrates the disproportionate impact that the current root store model can have. It is enough for a single certification authority going rogue for everyone to be at risk.</p><p>If you are an IT manager with a fleet of managed devices, you should consider whether you need to take direct action to revoke these unauthorized certificates. We provide the list in the timeline section above. As the certificates have since been revoked, it is possible that no direct intervention should be required; however, system-wide revocation is not instantaneous and automatic and hence we recommend checking.</p><p>If you are tasked to review the policy of a root store that includes Fina CA, you should take immediate actions to review their inclusion in your program. The issue that has been identified through the course of this investigation raises concerns, and requires a clear report and follow-up from the CA. In addition, to make it possible to detect future such incidents, you should consider having a requirement for all CAs in your root store to participate in Certificate Transparency. Without CT logs, problems such as the one we describe here are impossible to address before they result in impact to end users.</p><p>We are not suggesting that you should stop using DoH or DoT. DNS over UDP and TCP are unencrypted, which puts every single query and response at risk of tampering and unauthorised surveillance. However, we believe that DoH and DoT client security could be improved if clients required that server certificates be included in a certificate transparency log.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>This event is the first time we have observed a rogue issuance of a certificate used by our public DNS resolver 1.1.1.1 service. While we have no evidence this was malicious, we know that there might be future attempts that are.</p><p>We plan to accelerate how quickly we discover and alert on these types of issues ourselves. We know that we can catch these earlier, and we plan to do so.</p><p>The identification of these kinds of issues rely on an ecosystem of partners working together to support Certificate Transparency. We are grateful for the monitors who noticed and reported this issue.</p> ]]></content:encoded>
            <category><![CDATA[1.1.1.1]]></category>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[Resolver]]></category>
            <category><![CDATA[DoH]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Certificate Authority]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Certificate Transparency]]></category>
            <guid isPermaLink="false">6dgQ2aH6eirkXOANX0QikR</guid>
            <dc:creator>Joe Abley</dc:creator>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Vicky Shrestha</dc:creator>
            <dc:creator>Bas Westerbaan</dc:creator>
        </item>
        <item>
            <title><![CDATA[Forget IPs: using cryptography to verify bot and agent traffic]]></title>
            <link>https://blog.cloudflare.com/web-bot-auth/</link>
            <pubDate>Thu, 15 May 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ Bots now browse like humans. We're proposing bots use cryptographic signatures so that website owners can verify their identity. Explanations and demonstration code can be found within the post. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>With the rise of traffic from <a href="https://www.cloudflare.com/learning/ai/what-is-agentic-ai/">AI agents</a>, what’s considered a bot is no longer clear-cut. There are some clearly malicious bots, like ones that DoS your site or do <a href="https://www.cloudflare.com/learning/bots/what-is-credential-stuffing/">credential stuffing</a>, and ones that most site owners do want to interact with their site, like the bot that indexes your site for a search engine, or ones that fetch RSS feeds.      </p><p>Historically, Cloudflare has relied on two main signals to verify legitimate web crawlers from other types of automated traffic: user agent headers and IP addresses. The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/User-Agent"><code><u>User-Agent</u></code><u> header</u></a> allows bot developers to identify themselves, i.e. <code>MyBotCrawler/1.1</code>. However, user agent headers alone are easily spoofed and are therefore insufficient for reliable identification. To address this, user agent checks are often supplemented with <a href="https://developers.cloudflare.com/bots/concepts/bot/verified-bots/policy/#ip-validation"><u>IP address validation</u></a>, the inspection of published IP address ranges to confirm a crawler's authenticity. However, the logic around IP address ranges representing a product or group of users is brittle – connections from the crawling service might be shared by multiple users, such as in the case of <a href="https://blog.cloudflare.com/icloud-private-relay/"><u>privacy proxies</u></a> and VPNs, and these ranges, often maintained by cloud providers, change over time.</p><p>Cloudflare will always try to block malicious bots, but we think our role here is to also provide an affirmative mechanism to authenticate desirable bot traffic. By using well-established cryptography techniques, we’re proposing a better mechanism for legitimate agents and bots to declare who they are, and provide a clearer signal for site owners to decide what traffic to permit. </p><p><b>Today, we’re introducing two proposals – HTTP message signatures and request mTLS – for </b><a href="https://blog.cloudflare.com/friendly-bots/"><b><u>friendly bots</u></b></a><b> to authenticate themselves, and for customer origins to identify them. </b>In this blog post, we’ll share how these authentication mechanisms work, how we implemented them, and how you can participate in our closed beta.</p>
    <div>
      <h2>Existing bot verification mechanisms are broken </h2>
      <a href="#existing-bot-verification-mechanisms-are-broken">
        
      </a>
    </div>
    <p>Historically, if you’ve worked on ChatGPT, Claude, Gemini, or any other agent, you’ve had several options to identify your HTTP traffic to other services: </p><ol><li><p>You define a <a href="https://www.rfc-editor.org/rfc/rfc9110#name-user-agent"><u>user agent</u></a>, an HTTP header described in <a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-user-agent"><u>RFC 9110</u></a>. The problem here is that this header is easily spoofable and there’s not a clear way for agents to identify themselves as semi-automated browsers — agents often use the Chrome user agent for this very reason, which is discouraged. The RFC <a href="https://www.rfc-editor.org/rfc/rfc9110.html#section-10.1.5-9"><u>states</u></a>: 
<i>“If a user agent masquerades as a different user agent, recipients can assume that the user intentionally desires to see responses tailored for that identified user agent, even if they might not work as well for the actual user agent being used.” </i> </p></li><li><p>You publish your IP address range(s). This has limitations because the same IP address might be shared by multiple users or multiple services within the same company, or even by multiple companies when hosting infrastructure is shared (like <a href="https://www.cloudflare.com/developer-platform/products/workers/">Cloudflare Workers</a>, for example). In addition, IP addresses are prone to change as underlying infrastructure changes, leading services to use ad-hoc sharing mechanisms like <a href="https://www.cloudflare.com/ips-v4"><u>CIDR lists</u></a>. </p></li><li><p>You go to every website and share a secret, like a <a href="https://www.rfc-editor.org/rfc/rfc6750"><u>Bearer</u></a> token. This is impractical at scale because it requires developers to maintain separate tokens for each website their bot will visit.</p></li></ol><p>We can do better! Instead of these arduous methods, we’re proposing that developers of bots and agents cryptographically sign requests originating from their service. When protecting origins, <a href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/">reverse proxies</a> such as Cloudflare can then validate those signatures to confidently identify the request source on behalf of site owners, allowing them to take action as they see fit. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3yB6h6XcSWNQO5McRWIpL8/edf32f7938b01a4c8f5eedefee2b9328/image2.png" />
          </figure><p>A typical system has three actors:</p><ul><li><p>User: the entity that wants to perform some actions on the web. This may be a human, an automated program, or anything taking action to retrieve information from the web.</p></li><li><p>Agent: an orchestrated browser or software program. For example, Chrome on your computer, or OpenAI’s <a href="https://operator.chatgpt.com/"><u>Operator</u></a> with ChatGPT. Agents can interact with the web according to web standards (HTML rendering, JavaScript, subrequests, etc.).</p></li><li><p>Origin: the website hosting a resource. The user wants to access it through the browser. This is Cloudflare when your website is using our services, and it’s your own server(s) when exposed directly to the Internet.</p></li></ul><p>In the next section, we’ll dive into HTTP Message Signatures and request mTLS, two mechanisms a browser agent may implement to sign outgoing requests, with different levels of ease for an origin to adopt. </p>
    <div>
      <h2>Introducing HTTP Message Signatures</h2>
      <a href="#introducing-http-message-signatures">
        
      </a>
    </div>
    <p><a href="https://www.rfc-editor.org/rfc/rfc9421.html"><u>HTTP Message Signatures</u></a> is a standard that defines the cryptographic authentication of a request sender. It’s essentially a cryptographically sound way to say, “hey, it’s me!”. It’s not the only way that developers can sign requests from their infrastructure — for example, AWS has used <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html"><u>Signature v4</u></a>, and Stripe has a framework for <a href="https://docs.stripe.com/webhooks#verify-webhook-signatures-with-official-libraries"><u>authenticating webhooks</u></a> — but Message Signatures is a published standard, and the cleanest, most developer-friendly way to sign requests.  </p><p>We’re working closely with the wider industry to support these standards-based approaches. For example, OpenAI has started to sign their requests. In their own words:   </p><blockquote><p><i>"Ensuring the authenticity of Operator traffic is paramount. With HTTP Message Signatures (</i><a href="https://www.rfc-editor.org/rfc/rfc9421.html"><i><u>RFC 9421</u></i></a><i>), OpenAI signs all Operator requests so site owners can verify they genuinely originate from Operator and haven’t been tampered with” </i>– Eugenio, Engineer, OpenAI</p></blockquote><p>Without further delay, let’s dive in how HTTP Messages Signatures work to identify bot traffic.</p>
    <div>
      <h3>Scoping standards to bot authentication</h3>
      <a href="#scoping-standards-to-bot-authentication">
        
      </a>
    </div>
    <p>Generating a message signature works like this: before sending a request, the agent signs the target origin with a public key. When fetching <code>https://example.com/path/to/resource</code>, it signs <code>example.com</code>. This public key is known to the origin, either because the agent is well known, because it has previously registered, or any other method. Then, the agent writes a <b>Signature-Input</b> header with the following parameters:</p><ol><li><p>A validity window (<code>created</code> and <code>expires</code> timestamps)</p></li><li><p>A Key ID that uniquely identifies the key used in the signature. This is a <a href="https://www.rfc-editor.org/rfc/rfc7638.html"><u>JSON Web Key Thumbprint</u></a>.  </p></li><li><p>A tag that shows websites the signature’s purpose and validation method, i.e. <code>web-bot-auth</code> for bot authentication.</p></li></ol><p>In addition, the <code>Signature-Agent</code> header indicates where the origin can find the public keys the agent used when signing the request, such as in a directory hosted by <code>signer.example.com</code>. This header is part of the signed content as well.</p><p>Here’s an example:</p>
            <pre><code>GET /path/to/resource HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 Chrome/113.0.0 MyBotCrawler/1.1
Signature-Agent: signer.example.com
Signature-Input: sig=("@authority" "signature-agent");\
             	 created=1700000000;\
             	 expires=1700011111;\
             	 keyid="ba3e64==";\
             	 tag="web-bot-auth"
Signature: sig=abc==</code></pre>
            <p>For those building bots, <a href="https://datatracker.ietf.org/doc/draft-meunier-web-bot-auth-architecture/"><u>we propose</u></a> signing the authority of the target URI, i.e. www.example.com, and a way to retrieve the bot public key in the form of <a href="https://datatracker.ietf.org/doc/draft-meunier-http-message-signatures-directory/"><u>signature-agent</u></a>, if present, i.e. <a href="http://crawler.search.google.com"><u>crawler.search.google.com</u></a> for Google Search, <a href="http://operator.openai.com"><u>operator.openai.com</u></a> for OpenAI Operator, workers.dev for Cloudflare Workers.</p><p>The <code>User-Agent</code> from the example above indicates that the software making the request is Chrome, because it is an agent that uses an orchestrated Chrome to browse the web. You should note that <code>MyBotCrawler/1.1</code> is still present. The <code>User-Agent</code> header can actually contain multiple products, in decreasing order of importance. If our agent is making requests via Chrome, that’s the most important product and therefore comes first.</p><p>At Internet-level scale, these signatures may add a notable amount of overhead to request processing. However, with the right cryptographic suite, and compared to the cost of existing bot mitigation, both technical and social, this seems to be a straightforward tradeoff. This is a metric we will monitor closely, and report on as adoption grows.</p>
    <div>
      <h3>Generating request signatures</h3>
      <a href="#generating-request-signatures">
        
      </a>
    </div>
    <p>We’re making several examples for generating Message Signatures for bots and agents <a href="https://github.com/cloudflareresearch/web-bot-auth/"><u>available on Github</u></a> (though we encourage other implementations!), all of which are standards-compliant, to maximize interoperability. </p><p>Imagine you’re building an agent using a managed Chromium browser, and want to sign all outgoing requests. To achieve this, the <a href="https://github.com/w3c/webextensions"><u>webextensions standard</u></a> provides <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onBeforeSendHeaders"><u>chrome.webRequest.onBeforeSendHeaders</u></a>, where you can modify HTTP headers before they are sent by the browser. The event is <a href="https://developer.chrome.com/docs/extensions/reference/api/webRequest#life_cycle_of_requests"><u>triggered</u></a> before sending any HTTP data, and when headers are available.</p><p>Here’s what that code would look like: </p>
            <pre><code>chrome.webRequest.onBeforeSendHeaders.addListener(
  function (details) {
	// Signature and header assignment logic goes here
      // &lt;CODE&gt;
  },
  { urls: ["&lt;all_urls&gt;"] },
  ["blocking", "requestHeaders"] // requires "installation_mode": "force_installed"
);</code></pre>
            <p>Cloudflare provides a <a href="https://www.npmjs.com/package/web-bot-auth"><u>web-bot-auth</u></a> helper package on npm that helps you generate request signatures with the correct parameters. <code>onBeforeSendHeaders</code> is a Chrome extension hook that needs to be implemented synchronously. To do so, we <code>import {signatureHeadersSync} from “web-bot-auth”</code>. Once the signature completes, both <code>Signature</code> and <code>Signature-Input</code> headers are assigned. The request flow can then continue.</p>
            <pre><code>const request = new URL(details.url);
const created = new Date();
const expired = new Date(created.getTime() + 300_000)


// Perform request signature
const headers = signatureHeadersSync(
  request,
  new Ed25519Signer(jwk),
  { created, expires }
);
// `headers` object now contains `Signature` and `Signature-Input` headers that can be used</code></pre>
            <p>This extension code is available on <a href="https://github.com/cloudflareresearch/web-bot-auth/"><u>GitHub</u></a>, alongside a  debugging server, deployed at <a href="https://http-message-signatures-example.research.cloudflare.com"><u>https://http-message-signatures-example.research.cloudflare.com</u></a>. </p>
    <div>
      <h3>Validating request signatures </h3>
      <a href="#validating-request-signatures">
        
      </a>
    </div>
    <p>Using our <a href="https://http-message-signatures-example.research.cloudflare.com"><u>debug server</u></a>, we can now inspect and validate our request signatures from the perspective of the website we’d be visiting. We should now see the Signature and Signature-Input headers:  </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/18P5OyGxu2fU0Dpyv70Gjz/d82d62355524ad1914deb41b601bcad2/image3.png" />
          </figure><p><sup><i>In this example, the homepage of the debugging server validates the signature from the RFC 9421 Ed25519 verifying key, which the extension uses for signing.</i></sup></p><p>The above demo and code walkthrough has been fully written in TypeScript: the verification website is on Cloudflare Workers, and the client is a Chrome browser extension. We are cognisant that this does not suit all clients and servers on the web. To demonstrate the proposal works in more environments, we have also implemented bot signature validation in Go with a <a href="https://github.com/cloudflareresearch/web-bot-auth/tree/main/examples/caddy-plugin"><u>plugin</u></a> for <a href="https://caddyserver.com/"><u>Caddy server</u></a>.</p>
    <div>
      <h2>Experimentation with request mTLS</h2>
      <a href="#experimentation-with-request-mtls">
        
      </a>
    </div>
    <p>HTTP is not the only way to convey signatures. For instance, one mechanism that has been used in the past to authenticate automated traffic against secured endpoints is <a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/"><u>mTLS</u></a>, the “mutual” presentation of <a href="https://www.cloudflare.com/application-services/products/ssl/">TLS certificates</a>. As described in our <a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/"><u>knowledge base</u></a>:</p><blockquote><p><i>Mutual TLS, or mTLS for short, is a method for</i><a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-authentication/"><i> </i><i><u>mutual authentication</u></i></a><i>. mTLS ensures that the parties at each end of a network connection are who they claim to be by verifying that they both have the correct private</i><a href="https://www.cloudflare.com/learning/ssl/what-is-a-cryptographic-key/"><i> </i><i><u>key</u></i></a><i>. The information within their respective</i><a href="https://www.cloudflare.com/learning/ssl/what-is-an-ssl-certificate/"><i> </i><i><u>TLS certificates</u></i></a><i> provides additional verification.</i></p></blockquote><p>While mTLS seems like a good fit for bot authentication on the web, it has limitations. If a user is asked for authentication via the mTLS protocol but does not have a certificate to provide, they would get an inscrutable and unskippable error. Origin sites need a way to conditionally signal to clients that they accept or require mTLS authentication, so that only mTLS-enabled clients use it.</p>
    <div>
      <h3>A TLS flag for bot authentication</h3>
      <a href="#a-tls-flag-for-bot-authentication">
        
      </a>
    </div>
    <p>TLS flags are an efficient way to describe whether a feature, like mTLS, is supported by origin sites. Within the IETF, we have proposed a new TLS flag called <a href="https://datatracker.ietf.org/doc/draft-jhoyla-req-mtls-flag/"><code><u>req mTLS</u></code></a> to be sent by the client during the establishment of a connection that signals support for authentication via a client certificate. </p><p>This proposal leverages the <a href="https://www.ietf.org/archive/id/draft-ietf-tls-tlsflags-14.html"><u>tls-flags</u></a> proposal under discussion in the IETF. The TLS Flags draft allows clients and servers to send an array of one bit flags to each other, rather than creating a new extension (with its associated overhead) for each piece of information they want to share. This is one of the first uses of this extension, and we hope that by using it here we can help drive adoption.</p><p>When a client sends the <a href="https://datatracker.ietf.org/doc/draft-jhoyla-req-mtls-flag/"><code><u>req mTLS</u></code></a> flag to the server, they signal to the server that they are able to respond with a certificate if requested. The server can then safely request a certificate without risk of blocking ordinary user traffic, because ordinary users will never set this flag. </p><p>Let’s take a look at what an example of such a req mTLS would look like in <a href="https://www.wireshark.org/"><u>Wireshark</u></a>, a network protocol analyser. You can follow along in the packet capture <a href="https://github.com/cloudflareresearch/req-mtls/tree/main/assets/demonstration-capture.pcapng"><u>here</u></a>.</p>
            <pre><code>Extension: req mTLS (len=12)
	Type: req mTLS (65025)
	Length: 12
	Data: 0b0000000000000000000001</code></pre>
            <p>The extension number is 65025, or 0xfe01. This corresponds to an unassigned block of <a href="https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1"><u>TLS extensions</u></a> that can be used to experiment with TLS Flags. Once the standard is adopted and published by the IETF, the number would be fixed. To use the <code>req mTLS</code> flag the client needs to set the 80<sup>th</sup> bit to true, so with our block length of 12 bytes, it should  contain the data 0b0000000000000000000001, which is the case here. The server then responds with a certificate request, and the request follows its course.</p>
    <div>
      <h3>Request mTLS in action</h3>
      <a href="#request-mtls-in-action">
        
      </a>
    </div>
    <p><i>Code for this section is available in GitHub under </i><a href="https://github.com/cloudflareresearch/req-mtls"><i><u>cloudflareresearch/req-mtls</u></i></a></p><p>Because mutual TLS is widely supported in TLS libraries already, the parts we need to introduce to the client and server are:</p><ol><li><p>Sending/parsing of TLS-flags</p></li><li><p>Specific support for the <code>req mTLS</code> flag</p></li></ol><p>To the best of our knowledge, there is no complete public implementation of either scheme. Using it for bot authentication may provide a motivation to do so.</p><p>Using <a href="https://github.com/cloudflare/go"><u>our experimental fork of Go</u></a>, a TLS client could support req mTLS as follows:</p>
            <pre><code>config := &amp;tls.Config{
    	TLSFlagsSupported:  []tls.TLSFlag{0x50},
    	RootCAs:       	rootPool,
    	Certificates:  	certs,
    	NextProtos:    	[]string{"h2"},
}
trans := http.Transport{TLSClientConfig: config, ForceAttemptHTTP2: true}</code></pre>
            <p>This example library allows you to configure Go to send <code>req mTLS 0x50</code> bytes in the <code>TLS Flags</code> extension. If you’d like to test your implementation out, you can prompt your client for certificates against <a href="http://req-mtls.research.cloudflare.com"><u>req-mtls.research.cloudflare.com</u></a> using the Cloudflare Research client <a href="https://github.com/cloudflareresearch/req-mtls"><u>cloudflareresearch/req-mtls</u></a>. For clients, once they set the TLS Flags associated with <code>req mTLS</code>, they are done. The code section taking care of normal mTLS will take over at that point, with no need to implement something new.</p>
    <div>
      <h2>Two approaches, one goal</h2>
      <a href="#two-approaches-one-goal">
        
      </a>
    </div>
    <p>We believe that developers of agents and bots should have a public, standard way to authenticate themselves to CDNs and website hosting platforms, regardless of the technology they use or provider they choose. At a high level, both HTTP Message Signatures and request mTLS achieve a similar goal: they allow the owner of a service to authentically identify themselves to a website. That’s why we’re participating in the standardizing effort for both of these protocols at the IETF, where many other authentication mechanisms we’ve discussed here — from TLS to OAuth Bearer tokens –— been developed by diverse sets of stakeholders and standardized as RFCs.   </p><p>Evaluating both proposals against each other, we’re prioritizing <a href="https://datatracker.ietf.org/doc/html/draft-meunier-web-bot-auth-architecture"><u>HTTP Message Signatures for Bots</u></a> because it relies on the previously adopted <a href="https://datatracker.ietf.org/doc/html/rfc9421"><u>RFC 9421</u></a> with several <a href="https://httpsig.org/"><u>reference implementations</u></a>, and works at the HTTP layer, making adoption simpler. <a href="https://datatracker.ietf.org/doc/draft-jhoyla-req-mtls-flag/"><u>request mTLS</u></a> may be a better fit for site owners with concerns about the additional bandwidth, but <a href="https://datatracker.ietf.org/doc/html/draft-ietf-tls-tlsflags"><u>TLS Flags</u></a> has fewer implementations, is still waiting for IETF adoption, and upgrading the TLS stack has proven to be more challenging than with HTTP. Both approaches share similar discovery and key management concerns, as highlighted in a <a href="https://datatracker.ietf.org/doc/draft-meunier-web-bot-auth-glossary/"><u>glossary</u></a> draft at the IETF. We’re actively exploring both options, and would love to <a href="https://www.cloudflare.com/lp/verified-bots/"><u>hear</u></a> from both site owners and bot developers about how you’re evaluating their respective tradeoffs.</p>
    <div>
      <h2>The bigger picture </h2>
      <a href="#the-bigger-picture">
        
      </a>
    </div>
    <p>In conclusion, we think request signatures and mTLS are promising mechanisms for bot owners and developers of AI agents to authenticate themselves in a tamper-proof manner, forging a path forward that doesn’t rely on ever-changing IP address ranges or spoofable headers such as <code>User-Agent</code>. This authentication can be consumed by Cloudflare when acting as a reverse proxy, or directly by site owners on their own infrastructure. This means that as a bot owner, you can now go to content creators and discuss crawling agreements, with as much granularity as the number of bots you have. You can start implementing these solutions today and test them against the research websites we’ve provided in this post.</p><p>Bot authentication also empowers site owners small and large to have more control over the traffic they allow, empowering them to continue to serve content on the public Internet while monitoring automated requests. Longer term, we will integrate these authentication mechanisms into our <a href="https://blog.cloudflare.com/cloudflare-ai-audit-control-ai-content-crawlers/"><u>AI Audit</u></a> and <a href="https://developers.cloudflare.com/bots/get-started/bot-management/"><u>Bot Management</u></a> products, to provide better visibility into the bots and agents that are willing to identify themselves.</p><p>Being able to solve problems for both origins and clients is key to helping build a better Internet, and we think identification of automated traffic is a step towards that. If you want us to start verifying your message signatures or client certificates, have a compelling use case you’d like us to consider, or any questions, please <a href="https://www.cloudflare.com/lp/verified-bots/"><u>reach out</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Bots]]></category>
            <category><![CDATA[Bot Management]]></category>
            <category><![CDATA[AI Bots]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">2hUP3FdePgIYVDwhgJVLeV</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Mari Galicer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Sometimes I cache: implementing lock-free probabilistic caching]]></title>
            <link>https://blog.cloudflare.com/sometimes-i-cache/</link>
            <pubDate>Thu, 26 Dec 2024 14:00:00 GMT</pubDate>
            <description><![CDATA[ If you want to know what cache revalidation is, how it works, and why it can involve rolling a die, read on. This blog post presents a lock-free probabilistic approach to cache revalidation, along 
 ]]></description>
            <content:encoded><![CDATA[ <p>HTTP caching is conceptually simple: if the response to a request is in the cache, serve it, and if not, pull it from your origin, put it in the cache, and return it. When the response is old, you repeat the process. This is called cache revalidation. If you are worried about too many requests going to your origin at once, you protect it with a <a href="https://developers.cloudflare.com/cache/concepts/revalidation/"><u>cache lock</u></a>: a small program, possibly distinct from your cache, that indicates if a request is already going to your origin. This is called request collapsing.</p><p>In this blog post, we dive into how cache revalidation works, and present a new approach based on probability. For every request going to the origin, we simulate a die roll. If it’s 6, the request can go to the origin. Otherwise, it stays stale to protect our origin from being overloaded. To see how this is built and optimised, read on.</p>
    <div>
      <h2>Background</h2>
      <a href="#background">
        
      </a>
    </div>
    <p>Let's take the example of an online image library. When a client requests an image, the service first checks its cache to see if the resource is present. If it is, it returns it. If it is not, the image server processes the request, places the response into the cache for a day, and returns it. When the cache expires, the process is repeated.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6zdgMhKkU3cVKRk9T2CO2I/5302e6ef68cabd04b8bd65a7e416f033/BLOG-2639_2.png" />
          </figure><p><i>Figure 1: Uncached request goes to the origin</i></p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4J5KIW2CocyvlLXLuVBTWH/1f6174983e1fc1de72b48a9801da160e/BLOG-2639_3.png" />
          </figure><p><i>Figure 2: Cached request stops at the cache</i></p><p>And this is where things get complex. The image of a cat might be quite popular. Let's say it's requested 10 times per second. Let’s also assume the image server cannot handle more than 1 request per second. After a day, the cache expires. 10 requests hit the service. Given there are no up-to-date items in cache, these 10 requests are going to go directly to the image server. This problem is known as <a href="https://en.wikipedia.org/wiki/Cache_stampede"><u>cache stampede</u></a>. When the image server sees these 10 requests all happening at the same time, it gets overloaded.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3xDMJ6iloIjNHWpAbkfXWv/bee11bc4e1bb83a5b330529d8d98fbaa/BLOG-2639_4.png" />
          </figure><p><i>Figure 3: Image server overloaded upon cache expiration. This can happen to one or multiple users, across locations.</i></p><p>This all stops if the cache gets populated, as it can handle a lot more requests than the origin.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7LVi2SItiAUYWdEm3ll3ZH/368c6ff8e5d9017d2d3a8cc96246b73c/BLOG-2639_5.png" />
          </figure><p><i>Figure 4: Cache is populated and can handle the load. The image server is healthy again.</i></p><p>In the following sections, we build this image service, see how it can prevent cache stampede with a cache lock, then dive into probabilistic cache revalidation, and its optimisation.</p>
    <div>
      <h2>Setup</h2>
      <a href="#setup">
        
      </a>
    </div>
    <p>Let's write this image service. We need an image, a server, and a cache. For the image we're going to use a picture of <a href="https://files.research.cloudflare.com/images/cat.jpg"><u>my cat</u></a>, Cloudflare Workers for the server, and the Cloudflare Cache API for caching.</p><p>Note to the reader: On purpose, we aren’t using <a href="https://developers.cloudflare.com/kv/"><u>Cloudflare KV</u></a> or <a href="https://developers.cloudflare.com/cache/"><u>Cloudflare CDN Cache</u></a>, because they already solve our cache validation problem by using a cache lock.</p>
            <pre><code>let cache = caches.default
const CACHE_KEY = new Request('https://cache.local/')
const CACHE_AGE_IN_S = 86_400 // 1 day

function cacheExpirationDate() {
  return new Date(Date.now() + 1000*CACHE_AGE_IN_S)
}

function fetchAndCache(ctx) {
  let response = await fetch('https://files.research.cloudflare.com/images/cat.jpg')
  response = new Response(
	await response.arrayBuffer(),
	{
  	  headers: {
  	    'Content-Type': response.headers.get('Content-Type'),
  	    'Expires': cacheExpirationDate().toUTCString(),
  	  },
	},
  )
  ctx.waitUntil(cache.put(CACHE_KEY, response.clone()))
  return response
}

export default {
  async fetch(request, env, ctx) {
	let cachedResponse = await cache.match(CACHE_KEY)
	if (cachedResponse) {
  	  return cachedResponse
	}
	return fetchAndCache(ctx)
  }
}</code></pre>
            <p><i>Codeblock 1: Image server with a non-collapsing cache</i></p>
    <div>
      <h2>Expectation about cache revalidation</h2>
      <a href="#expectation-about-cache-revalidation">
        
      </a>
    </div>
    <p>The image service is receiving 10 requests per second, and it caches images for a day. It's reasonable to assume we would like to start revalidating the cache 5 minutes before it expires. The code evolves as follows:</p>
            <pre><code>let cache = caches.default
const CACHE_KEY = new Request('https://cache.local/')
const CACHE_AGE_IN_S = 86_400 // 1 day
const CACHE_REVALIDATION_INTERVAL_IN_S = 300

function cacheExpirationDate() {
  // Date constructor in workers takes Unix time in milliseconds
  // Date.now() returns time in milliseconds as well
  return new Date(Date.now() + 1000*CACHE_AGE_IN_S)
}

async function fetchAndCache(ctx) {
  let response = await fetch('https://files.research.cloudflare.com/images/cat.jpg')
  response = new Response(
	await response.arrayBuffer(),
	{
  	  headers: {
  	    'Content-Type': response.headers.get('Content-Type'),
  	    'Expires': cacheExpirationDate().toUTCString(),
  	  },
	},
  )
  ctx.waitUntil(cache.put(CACHE_KEY, response.clone()))
  return response
}

// Revalidation function added here
// This is were we are going to focus our effort: should the request be revalidated ?
function shouldRevalidate(expirationDate) {
  let remainingCacheTimeInS = (expirationDate.getTime() - Date.now()) / 1000

  return remainingCacheTimeInS &lt;= CACHE_REVALIDATION_INTERVAL_IN_S
}

export default {
  async fetch(request, env, ctx) {
	let cachedResponse = await cache.match(CACHE_KEY)
	if (cachedResponse) {
       // revalidation happens only if the request was cached. Otherwise, the resource is fetched anyway
  	  if (shouldRevalidate()) {
    	    ctx.waitUntil(fetchAndCache(ctx))
  	  }
  	  return cachedResponse
	}
	return fetchAndCache(ctx)
  }
}</code></pre>
            <p><i>Codeblock 2: Image server with early-revalidation and a non-collapsing cache</i></p><p>That code works, and we can now revalidate 5 minutes in advance of cache expiration. However, instead of fetching the image from the origin server at expiration time, all requests are going to be made 5 minutes in advance, and that does not solve our cache stampede problem. This happens no matter if requests are coming to a single location or not, given the code above does not collapse requests.</p><p>To solve our cache stampede problem, we need the revalidation process to not send too many requests at the same time. Ideally, we would like only one request to be sent between <code>expiration - 5min</code> and <code>expiration</code>.</p>
    <div>
      <h2>The usual solution: a cache lock</h2>
      <a href="#the-usual-solution-a-cache-lock">
        
      </a>
    </div>
    <p>To make sure there is only one request at a time going to the origin server, the solution that's usually deployed is a cache lock. The idea is that for a specific item, a cat picture in our case, requests to the origin try to obtain a lock. The request obtaining the lock can go to the origin, the others will serve stale content.</p><p>The lock has two methods: <code>try_lock</code> and <code>unlock</code>.</p><ul><li><p><code>try_lock</code> if the lock is free, take it and return <code>true</code>. If not, return <code>false</code>.</p></li><li><p><code>unlock</code> releases the lock.</p></li></ul><p>Such a lock can be implemented as a <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/"><u>Cloudflare RPC service</u></a>:</p>
            <pre><code>import { WorkerEntrypoint } from 'cloudflare:workers'

class Lock extends WorkerEntryPoint {
  async try_lock(key) {
	let value = await this.ctx.storage.get(key)
	if (!value) {
  	  await this.ctx.storage.put(key, true)
  	  return true
	}
	return false
  }

  unlock() {
	return this.ctx.storage.delete(key)
  }
}
</code></pre>
            <p><i>Codeblock 3: Lock service implemented with a Durable Object</i></p><p>That service can then be used as a cache lock.</p>
            <pre><code>// CACHE_LOCK is an instantiation of the above binding
// Assuming the above is deployed as a worker with name `lock`
// It can be bound in wrangler.toml as follows
// services = [ { binding = "CACHE_LOCK", service = "lock" } ]

const LOCK_KEY = "cat_image_service"

async function fetchAndCache(env, ctx) {
  let response = await fetch('...')
  ctx.waitUntil(env.CACHE_LOCK.unlock(LOCK_KEY))
  ...
}

function shouldRevalidate(env, expirationDate) {
  let remainingCacheTimeInS = (expirationDate.getTime() - Date.now()) / 1000

  // check if the expiry window is now, and then if the revalidation lock is available. if it is, take it
  return remainingCacheTimeInS &lt;= CACHE_REVALIDATION_INTERVAL_IN_S &amp;&amp; env.CACHE_LOCK.try_lock(LOCK_KEY)
}
</code></pre>
            <p><i>Codeblock 4: Image server with early-revalidation and a cache using a cache-lock</i></p><p>Now you might say "Et voilà. No need for probabilities and mathematics. Peak engineering has triumphed." And you might be right, in most cases. That's why cache locks are so <a href="https://developers.cloudflare.com/cache/concepts/revalidation/"><u>predominant</u></a>: they are conceptually simple, deterministic for the same key, and scale well with predictable resource usage.</p><p>On the other hand, cache locks add latency and fallibility. To take ownership of a lock, cache revalidation has to contact the lock service. This service is shared across different processes, possibly different machines in different locations. Requests therefore take time. In addition, this service might be unavailable. Probabilistic cache revalidation does not suffer from these, given it does not reach out to an external service but rolls a die with the local randomness generator. It does so at the cost of not guaranteeing the number of requests going to the origin server: maybe zero for an extended period, maybe more than one. On average, this is going to be fine. But there can be border cases, similar to how one can roll a die 10 times and get 10 sixes. It’s unlikely, but not unrealistic, and certain services need that certainty. In the following sections, we dissect this approach.</p>
    <div>
      <h2>First dive into probabilities given a stable request rate</h2>
      <a href="#first-dive-into-probabilities-given-a-stable-request-rate">
        
      </a>
    </div>
    <p>A first approach is to reduce the number of requests going to the origin server. Instead of always sending a request to revalidate, we are going to send 1 out of 10. This means that instead of sending 10 requests per second when the cache is invalidated, we send 1 per second.</p><p>Because we don't have a lock, we do that with probabilities. We set the probability of sending a request to the origin to be $p=\frac{1}{10}$. With a rate $r$ of 10 requests per second, after 1 second, the expectancy of a request being sent to the origin is $1-(1-p)^{10}=65\%$. We draw the evolution of the function $E(r, t)=1-(1-p)^{r \times t}$ representing the expectancy of a request being sent to the server over time.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78UvqHlQ6Se6cifbla3ozw/111decceed55ba1387b78a75e28f04cc/BLOG-2639_6.jpg" />
          </figure><p><i>Figure 5: Revalidation time $E(t)$ with $r=10$ and $p=\frac{1}{10}$. At time $t$, $E(t)$ is the probability that an early revalidation occurred.</i></p><p>The graph moves very quickly towards $1$. This means we might still have space to reduce the number of requests going to our origin server. We can set a lower probability, such as $p_2=\frac{1}{500}$ (1 request every 5 seconds on average). The graph looks as follows:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/TtLqU9nyKqtYxIz5oJefX/fba679de0599854ba344f19bd0b97939/BLOG-2639_7.jpg" />
          </figure><p><i>Figure 6: Revalidation time $E(t)$ with $r=10$ and $p=\frac{1}{500}$.</i></p><p>This looks great. Let's implement it.</p>
            <pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300
const CACHE_REVALIDATION_PROBABILITY = 1/500

function shouldRevalidate(expirationDate) {
  let remainingCacheTimeInS = (expirationDate.getTime() - Date.now()) / 1000

  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) {
	return false
  }
  if (remainingCacheTimeInS &lt;= 0) {
	return true
  }
  return Math.random() &lt; CACHE_REVALIDATION_PROBABILITY
}
</code></pre>
            <p><i>Codeblock 5: Image server with early-revalidation and a probabilistic cache using uniform distribution</i></p><p>That's it. If the cache is not close to expiration, we don't revalidate. If the cache is expired, we revalidate. Otherwise, we revalidate based on a probability.</p>
    <div>
      <h2>Adaptive cache revalidation</h2>
      <a href="#adaptive-cache-revalidation">
        
      </a>
    </div>
    <p>Until now, we assumed the picture of the cat received a stable request rate. However, for a real service, this does not necessarily hold. For instance, if instead of 10 requests per second, imagine the service receives only 1. The expectancy function does not look as good. After 5 minutes (300s), $E(r=1, t=300)=45\%$. On the other hand, if the image service is receiving 10,000 requests per second, $E(r=10000, t = 300) \approx 100\%$, but our server receives on average $10000 \times \frac{1}{500} = 20$ requests per second. It would be ideal to design a probability function that would adapt to the request rate.</p><p>That function would return a low probability when expiration time is far in the future, and increase over time such that the cache is revalidated before it expires. It would cap the request rate going to the origin server.</p><p>Let’s design the variation of probability $p$ over 5 minutes. When far from the expiration, the probability to revalidate should be low. This should help match the high request rate. For example, with a request rate of 10k requests per second, we would like the revalidation probability $p$ to be $\frac{1}{100000}$. This ensures the request rates seen by our server are going to be low on average, at about 1 request every 10 seconds. As time passes, we increase this probability to allow for revalidation even at a lower request rate.</p><table><tr><td><p><b>Time to expiration $t$ (in s)</b></p></td><td><p><b>Revalidation probability $p$</b></p></td><td><p><b>Target request rate $r$ (in rps)</b></p></td></tr><tr><td><p>300</p></td><td><p>1/100000</p></td><td><p>10000</p></td></tr><tr><td><p>240</p></td><td><p>1/10000</p></td><td><p>1000</p></td></tr><tr><td><p>180</p></td><td><p>1/1000</p></td><td><p>100</p></td></tr><tr><td><p>120</p></td><td><p>1/100</p></td><td><p>10</p></td></tr><tr><td><p>60</p></td><td><p>1/10</p></td><td><p>1</p></td></tr><tr><td><p>0</p></td><td><p>1</p></td><td><p>-</p></td></tr></table><p><i>Table 1: Variation of revalidation probability over time</i></p><p>For each of these intervals, there is a high likelihood that a request rate <code>$r$</code> will trigger a cache revalidation, and low likelihood that a lower request rate will trigger it. If it does, it's ok.</p><p>We can update our revalidation function as follows:</p>
            <pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300
const CACHE_REVALIDATION_PROBABILITY_PER_MIN = [1/100_000, 1/10_000, 1/1000, 1/100, 1/10, 1]

function shouldRevalidate(expirationDate) {
  let remainingCacheTimeInS = (expirationDate.getTime() - Date.now()) / 1000

  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) {
	return false
  }
  if (remainingCacheTimeInS &lt;= 0) {
	return true
  }
  let currentMinute = Math.floor(remainingCacheTimeInS/60)
  return Math.random() &lt; CACHE_REVALIDATION_PROBABILITY_PER_MIN[currentMinute]
}
</code></pre>
            <p><i>Codeblock 6: Image server with early-revalidation and a probabilistic cache using piecewise uniform distribution</i></p>
    <div>
      <h2>Optimal cache stampede solution</h2>
      <a href="#optimal-cache-stampede-solution">
        
      </a>
    </div>
    <p>There seems to be a lot of decisions going on here. To solve this, we can reference an academic paper written by A Vattani, T Chierichetti, and K Lowenstein in 2015 called <a href="https://cseweb.ucsd.edu/~avattani/papers/cache_stampede.pdf"><u>Optimal Probabilistic Cache Stampede Prevention</u></a>. If you read it, you'll recognise that what we have been discussing until now is close to what the paper presents. For instance, both the cache revalidation algorithm structure and the early revalidation function look similar.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1MLwwNsci3XxhK0uAvWcFu/62a17cc9056d6b12832160acc9e40fb9/BLOG-2639_8.png" />
          </figure><p><i>Figure 7: Probabilistic early expiration of a cache item as defined by Figure 2 of Optimal Probabilistic Cache Stampede Prevention paper. In our case, $\mathcal{D}=300$</i></p><p>One takeaway from the paper is that instead of discretization, with a probability from 0 to 60s, then from 60s to 120s, …, the probability function can be continuous. Instead of a fixed $p$, there is a function $p(t)$ of time $t$.</p><p>$p(t)=e^{-\lambda (expiry-t)}, \text{ with } expiry=300, \text{ and } t \in [0, 300]$</p><p>We call $\lambda$ the steepness parameter, and set it to $\frac{1}{300}$, $300$ being our early expiration gap.</p><p>The expectancy over time is $E(r, t)=1-e^{-rλt}$. This leads to the expectancy below for various request rates. You can note that when $r=1$, there is not a $100%$ chance that the request will be revalidated before expiry.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3lHElc96ZDNbcMfXVQ9pUm/e70e98b4be158dcde11b95366a736742/BLOG-2639_9.jpg" />
          </figure><p><i>Figure 8: Revalidation time $E(t)$ for multiple $r$ with an exponential distribution.</i></p><p>This leads to the final code snippet:</p>
            <pre><code>const CACHE_REVALIDATION_INTERVAL_IN_S = 300
const REVALIDATION_STEEPNESS = 1/300

function shouldRevalidate(expirationDate) {
  let remainingCacheTimeInS = (expirationDate.getTime() - Date.now()) / 1000

  if (remainingCacheTimeInS &gt; CACHE_REVALIDATION_INTERVAL_IN_S) {
	return false
  }
  if (remainingCacheTimeInS &lt;= 0) {
	return true
  }
// p(t) is evaluated here
  return Math.random() &lt; Math.exp(-REVALIDATION_STEEPNESS*remainingCacheTimeInS)
}
</code></pre>
            <p><i>Codeblock 7: Image server with early-revalidation and a probabilistic cache using exponential distribution</i></p><p>And that's it. Given <code>Date.now(</code>) has a granularity, and is not continuous, it would also be possible to discretise these functions, even though the gains are minimal. This is what we have done in a <a href="https://github.com/cloudflare/privacypass-issuer/blob/main/src/cache.ts#L60-L103"><u>production worker implementation</u></a>, where the number of requests is important. It is a service that benefits from caching for performance consideration, and that cannot use built-in <a href="https://developers.cloudflare.com/workers/runtime-apis/cache/"><u>stale-while-revalidate</u></a> from within Cloudflare workers. Probabilistic cache stampede prevention is well-suited here, as no new component has to be built, and it performs well at different request rates.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We have seen how to solve cache stampede without a lock, its implementation, and why it is optimal. In the real world, you likely will not encounter this issue: either because it’s good enough to optimize your origin service to serve more requests, or because you can leverage a CDN cache. In fact, most HTTP caches provide an API that follows <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"><u>Cache Control</u></a>, and likely have all the tools you need. This primitive is also built into certain products, such as <a href="https://developers.cloudflare.com/kv/platform/limits/"><u>Cloudflare KV</u></a>.</p><p>If you have not done so, you can go and experiment with all the code snippets presented in this blog on the Cloudflare Workers Playground at <a href="https://cloudflareworkers.com"><u>cloudflareworkers.com</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Cache]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">4Xek2BRcXVKNsI4vCa3Zuj</guid>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare helps verify the security of end-to-end encrypted messages by auditing key transparency for WhatsApp]]></title>
            <link>https://blog.cloudflare.com/key-transparency/</link>
            <pubDate>Tue, 24 Sep 2024 13:00:00 GMT</pubDate>
            <description><![CDATA[ Cloudflare is now verifying WhatsApp’s Key Transparency audit proofs to ensure the security of end-to-end encrypted messaging conversations without having to manually check QR codes. We are publishing the results of the proof verification to https://dash.key-transparency.cloudflare.com for independent researchers and security experts to compare against WhatsApp’s. Cloudflare does not have access to underlying public key material or message metadata as part of this infrastructure. ]]></description>
            <content:encoded><![CDATA[ <p>Chances are good that today you’ve sent a message through an <a href="https://www.cloudflare.com/learning/privacy/what-is-end-to-end-encryption"><u>end-to-end encrypted (E2EE)</u></a> messaging app such as WhatsApp, Signal, or iMessage. While we often take the privacy of these conversations for granted, they in fact rely on decades of research, testing, and standardization efforts, the foundation of which is a <a href="https://www.cloudflare.com/learning/ssl/how-does-public-key-encryption-work/"><u>public-private key exchange</u></a>. There is, however, an oft-overlooked implicit trust inherent in this model: that the messaging app infrastructure is distributing the public keys of all of its users correctly.</p><p>Here’s an example: if Joe and Alice are messaging each other on WhatsApp, Joe uses Alice’s phone number to retrieve Alice’s public key from the WhatsApp database, and Alice receives Joe’s public key. Their messages are then encrypted using this key exchange, so that no one — even WhatsApp — can see the contents of their messages besides Alice and Joe themselves. However, in the unlikely situation where an attacker, Bob, manages to register a different public key in WhatsApp’s database, Joe would try to message Alice but unknowingly be messaging Bob instead. And while this threat is most salient for journalists, activists, and those most vulnerable to cyber attacks<i>, </i>we believe that protecting the privacy and integrity of end-to-end encrypted conversations is for everyone.</p><p>There are several methods that end-to-end encrypted messaging apps have deployed thus far to protect the integrity of public key distribution, the most common of which is to do an in-person verification of the QR code fingerprint of your public key (<a href="https://faq.whatsapp.com/2416198805185327?helpref=faq_content"><u>WhatsApp</u></a> and <a href="https://signal.org/blog/safety-number-updates/"><u>Signal</u></a> both have a version of this). As you can imagine, this experience is inconvenient and unwieldy, especially as your number of contacts and group chats increase.</p><p>Over the past few years, there have been significant developments in this area of cryptography, and WhatsApp has paved the way with their <a href="https://engineering.fb.com/2023/04/13/security/whatsapp-key-transparency/"><u>Key Transparency announcement</u></a>. But as an independent third party, Cloudflare can provide stronger reassurance: that’s why we’re excited to announce that we’re now verifying WhatsApp’s Key Transparency audit proofs. </p>
    <div>
      <h2>Auditing: the next frontier of encryption </h2>
      <a href="#auditing-the-next-frontier-of-encryption">
        
      </a>
    </div>
    <p>We didn’t build this in a vacuum: similar to how the web and messaging apps became encrypted over time, we see auditing public key infrastructure as the next logical step in securing Internet infrastructure. This solution builds upon learnings from <a href="https://en.wikipedia.org/wiki/Certificate_Transparency"><u>Certificate Transparency</u></a> and<a href="https://binary.transparency.dev/"><u> Binary Transparency</u></a>, which share some of the underlying data structure and cryptographic techniques, and we’re excited about the formation of a <a href="https://mailarchive.ietf.org/arch/browse/keytrans/"><u>working group at the IETF</u></a> to make multi-party operation of Key Transparency-like systems tractable for a broader set of use cases. </p><p>We see our role here as a pioneer of a real world deployment of this auditing infrastructure, working through and sharing the operational challenges of operating a system that is critical for a messaging app used by billions of people around the world.   </p><p>We’ve also done this before — in 2022, Cloudflare announced <a href="https://blog.cloudflare.com/cloudflare-verifies-code-whatsapp-web-serves-users/"><u>Code Verify</u></a>, a partnership in which we verify that the code delivered in the browser for <a href="https://web.whatsapp.com/"><u>WhatsApp Web</u></a> has not been tampered with. When users run WhatsApp in their browser, the <a href="https://faq.whatsapp.com/639766781216714?cms_platform=web&amp;helpref=faq_content"><u>WhatsApp Code Verify extension</u></a> compares a hash of the code that is executing in the browser with the hash that Cloudflare has of the codebase, enabling WhatsApp web users to easily see whether the code that is executing is the code that was publicly committed to. </p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/451BUpYOdkMZ9KqtGKBbFQ/69edee8fe9e64d124b16908a95bf0933/Code_Verify_-_Blog.png" />
            
            </figure><p><sup><i>In Code Verify, Cloudflare builds a non-mutable chain associating the WhatsApp version with the hash of its code.</i></sup></p><p>Cloudflare’s role in Key Transparency is similar in that we are checking that a tree-based directory of public keys (more on this later) has been constructed correctly, and has been done so consistently over time.</p>
    <div>
      <h2>How Key Transparency works</h2>
      <a href="#how-key-transparency-works">
        
      </a>
    </div>
    <p>The architectural foundation of Key Transparency is the <a href="https://github.com/facebook/akd/"><u>Auditable Key Directory (AKD)</u></a>: a tree-shaped data structure, constructed and maintained by WhatsApp, in which the nodes contain hashed contact details of each user. We’ll explain the basics here but if you’re interested in learning more, check out the <a href="https://eprint.iacr.org/2018/607.pdf"><u>SEEMless</u></a> and <a href="https://eprint.iacr.org/2023/081.pdf"><u>Parakeet</u></a> papers.</p><p>The AKD tree is constructed by building a binary tree, each parent node of which is a hash of each of its left and right child nodes:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5Dl16PIqBNBiKn6qhzanCU/b67a1128bef4ab8733337f720c53f160/Mini_tree_-_Blog.png" />
            
            </figure><p><sup><i>Each child node on the tree contains contact and public key details for a user (shown here for illustrative purposes). In reality, Cloudflare only sees a hash of each node rather than Alice and Bob’s contact info in plaintext.</i></sup></p><p>An epoch describes a specific version of the tree at a given moment in time, identified by its root node. Using a structure similar to Code Verify, the WhatsApp Log stores each root node hash as part of an append-only time structure of updates.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/43FGTWfTV2aIaaMkfyplY2/8576b9c096bead64ede52a034481149b/Key_Transparency_combined_tree_-_Blog.png" />
            
            </figure><p>What kind of changes are valid to be included in a given epoch? When a new person, Brian, joins WhatsApp, WhatsApp inserts a new “B” node in the AKD tree, and a new epoch. If Alice loses her phone and rotates her key, her “version” is updated to <code>v1</code> in the next update.  </p>
    <div>
      <h2>How we built the Auditor on Cloudflare Workers </h2>
      <a href="#how-we-built-the-auditor-on-cloudflare-workers">
        
      </a>
    </div>
    <p>The role of the Auditor is to provide two main guarantees: that epochs are globally unique, and that they are valid. They are, however, quite different: global uniqueness requires consistency on whether an epoch and its associated root hash has been seen, while validity is a matter of computation — is the transition from the previous epoch to the current one a correct tree transformation?</p>
    <div>
      <h3>Timestamping service</h3>
      <a href="#timestamping-service">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5QHtfUaKoIBcIcK5o6H53j/ebaa147f3b22de32a29754d3cd7e73bd/Key_Transparency_Auditor_3_.png" />
            
            </figure><p><sup><i>Timestamping service architecture (Cloudflare Workers in Rust, using a Durable Object for storage)</i></sup></p><p>At regular intervals, the WhatsApp Log puts all new updates into the tree, and cuts a new epoch in the format “{counter}/{previous}/{current}”. The counter is a number, whereby “previous” is a hexadecimal encoded hash of the previous tree root, and “current” is a hexadecimal encoded hash for the new tree root. As a shorthand, epochs can be referred to by their counter only.</p><p>Here’s an example:</p><p><code>1001/d0bbf29c48716f26a951ae2a244eb1d070ee38865c29c8ad8174e8904e3cdc1a/e1006114485e8f0bbe2464e0ebac77af37bce76851745592e8dd5991ff2cd411</code></p><p>Once an epoch is constructed, the WhatsApp Log sends it to the Auditor for cross-signing, to ensure it has only been seen once. The Auditor adds a timestamp as to when this new epoch has been seen. Cloudflare’s Auditor uses a <a href="https://developers.cloudflare.com/durable-objects/platform/known-issues/#global-uniqueness"><u>Durable Object</u></a> for every epoch to create their timestamp. This guarantees the global uniqueness of an epoch, and the possibility of replay in the event the WhatsApp Log experiences an outage or is distributed across multiple locations. WhatsApp’s Log is expected to produce new epochs at regular intervals, given this constrains the propagation of public key updates seen by their users. Therefore, Cloudflare Auditor does not have to keep the durable object state forever. Once replay and consistency have been accounted for, this state is cleared. This is done after a month, thanks to durable object <a href="https://developers.cloudflare.com/durable-objects/api/alarms/"><u>alarms</u></a>.</p><p>Additional checks are performed by the service, such as checking that the epochs are consecutive, or that their digest is unique. This enforces a chain of epochs and their associated digests, provided by the WhatsApp Log and signed by the Auditor, providing a consistent view for all to see.</p><p>We decided to write this service in Rust because Workers rely on <a href="https://github.com/cloudflare/workers-rs"><u>cloudflare/workers-rs</u></a> bindings, and the auditable key directory library is also in Rust (<a href="https://github.com/facebook/akd"><u>facebook/akd</u></a>).</p>
    <div>
      <h3>Tree validation service</h3>
      <a href="#tree-validation-service">
        
      </a>
    </div>
    <p>With the timestamping service above, WhatsApp users (as well as their Log) have assurance that epochs are transparent. WhatsApp’s directory can be audited at any point in time, and if it were to be tampered with by WhatsApp or an intermediary, the WhatsApp Log can be held accountable for it.</p><p>Epochs and their digests are only representations of their underlying key directory. To fully audit the directory, the transition from the previous digest to a current digest has to be validated. To perform validation, we need to run the epoch validation method. Specifically, we want to run <a href="https://github.com/facebook/akd/blob/fcd665aa20f829cd9e06cb3d70cbe0c32ffe6b67/akd/src/auditor.rs#L56"><u>verify_consecutive_append_only</u></a> on every epoch constructed by the Log. The size of an epoch varies with the number of updates it contains, and therefore the number of associated nodes in the tree to construct as well. While Workers are able to run such validation for a small number of updates, this is a compute-intensive task. Therefore, still leveraging the same Rust codebase, the Auditor leverages a container that only performs the tree construction and validation. The Auditor retrieves the updates for a given epoch, copies them into its own R2 bucket, and delegates the validation to a <a href="https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler/src/cloudchamber"><u>container</u></a> running on Cloudflare. Once validated, the epoch is marked as verified.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5fNbebayPfLZPn4pEIoWpP/b8d2da4ac9867aeb44e9e1ff52405be9/Key_Transparency_Auditor_4_.png" />
            
            </figure><p><sup><i>Architecture for Cloudflare’s Plexi Auditor. The proof verification and signatures stored do not contain personally identifiable information such as your phone number, public key, or other metadata tied to your WhatsApp account.</i></sup></p><p>This decouples global uniqueness requirements and epoch validation, which happens at two distinct times. It allows the validation to take more time, and not be latency sensitive.</p>
    <div>
      <h2>How can I verify Cloudflare has signed an epoch?</h2>
      <a href="#how-can-i-verify-cloudflare-has-signed-an-epoch">
        
      </a>
    </div>
    <p>Anyone can perform audit proof verification — <a href="https://dash.key-transparency.cloudflare.com"><u>the proofs are publicly available</u></a> — but Cloudflare will be doing so automatically and publicly to make the results accessible to all. Verify that Cloudflare’s signature matches WhatsApp’s by visiting our <a href="https://dash.key-transparency.cloudflare.com"><u>Key Transparency website</u></a>, or via our <a href="https://github.com/cloudflare/plexi"><u>command line</u></a> tool.</p><p>To use our command line tool, you’ll need to download the <a href="https://github.com/cloudflare/plexi"><u>plexi</u></a> client. It helps construct data structures which are used for signatures, and requires you to have git and cargo installed.</p>
            <pre><code>cargo install plexi</code></pre>
            <p>With the client installed, let’s now check the audit proofs for WhatsApp namespace: <code>whatsapp.key-transparency.v1</code>. Plexi Auditor is represented by one public key, which can verify and vouch for multiple Logs with their own dedicated “namespace.” To validate an epoch, such as epoch 458298 (the epoch at which the log decided to start sharing data), you can run the following command:</p>
            <pre><code>plexi audit --remote-url 'https://akd-auditor.cloudflare.com' --namespace 'whatsapp.key-transparency.v1' --long
Namespace
  Name              	: whatsapp.key-transparency.v1
  Ciphersuite       	: ed25519(protobuf)

Signature (2024-09-23T16:53:45Z)
  Epoch height      	: 489193
  Epoch digest      	: cbe5097ae832a3ae51ad866104ffd4aa1f7479e873fd18df9cb96a02fc91ebfe
  Signature         	: fe94973e19da826487b637c019d3ce52f0c08093ada00b4fe6563e2f8117b4345121342bc33aae249be47979dfe704478e2c18aed86e674df9f934b718949c08
  Signature verification: success
  Proof verification	: success</code></pre>
            
    <div>
      <h2>Interested in having Cloudflare audit your public key infrastructure?</h2>
      <a href="#interested-in-having-cloudflare-audit-your-public-key-infrastructure">
        
      </a>
    </div>
    <p>At the end of the day, security threats shouldn’t become usability problems — everyday messaging app users shouldn’t have to worry about whether the public keys of the people they’re talking to have been compromised. In the same way that <a href="https://ct.cloudflare.com/"><u>certificate transparency</u></a> is now built into the issuance and use of digital certificates to encrypt web traffic, we think that public key transparency and auditing should be built into end-to-end encrypted systems by default, so that users never have to do manual QR code verification again. </p><p>We built our auditing service to be general purpose, reliable, and fast, and WhatsApp’s Key Transparency is just the first of several use cases it will be used for – Cloudflare is interested in helping audit the delivery of code binaries and integrity of all types of end-to-end encrypted infrastructure. If your company or organization is interested in working with us, you can <a href="https://www.cloudflare.com/lp/privacy-edge/"><u>reach out to us here</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Privacy]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Research]]></category>
            <guid isPermaLink="false">4tzeNEI3qyBtnWskn5TbUa</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Mari Galicer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Harnessing chaos in Cloudflare offices]]></title>
            <link>https://blog.cloudflare.com/harnessing-office-chaos/</link>
            <pubDate>Fri, 08 Mar 2024 14:00:24 GMT</pubDate>
            <description><![CDATA[ This blog post will cover the new sources of “chaos” that have been added to LavaRand and how you can make use of that harnessed chaos in your next application ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6VAXGAjHjvvY5IAEG63gPu/4c199f8bb127b03fe613ab8dc6c0016f/image12-1.png" />
            
            </figure><p>In the children’s book <a href="https://en.wikipedia.org/wiki/The_Snail_and_the_Whale">The Snail and Whale</a>, after an unexpectedly far-flung adventure, the principal character returns to declarations of “How time’s flown” and “Haven’t you grown?” It has been about four years since we last wrote about LavaRand and during that time the story of how Cloudflare uses physical sources of entropy to add to the security of the Internet has continued to travel and be a source of interest to many. What was initially just a single species of physical entropy source – lava lamps – has grown and diversified. We want to catch you up a little on the story of LavaRand. This blog post will cover the new sources of “chaos” that have been added to LavaRand and how you can make use of that harnessed chaos in your next application. We’ll cover how public randomness can open up uses of publicly trusted randomness — imagine not needing to take the holders of a “random draw” at their word when they claim the outcome is not manipulated in some way. And finally we’ll discuss timelock encryption which is a way to ensure that a message cannot be decrypted until some chosen time in the future.</p>
    <div>
      <h2>LavaRand origins</h2>
      <a href="#lavarand-origins">
        
      </a>
    </div>
    <p>The entropy sourced from our wall of lava lamps in San Francisco has long played its part in the randomness that secures connections made through Cloudflare.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5XdIuQkEWKat2c9YanaCY0/aa873b127b5eea8cea19982f3552ccc2/image11-3.png" />
            
            </figure><p>Lava lamps with flowing wax.</p><p>Cloudflare’s servers collectively handle upwards of 55 million HTTP requests per second, the <a href="https://radar.cloudflare.com/adoption-and-usage#http-vs-https">vast majority of which are secured via the TLS protocol</a> to ensure authenticity and confidentiality. Under the hood, cryptographic protocols like TLS require an underlying source of secure randomness – otherwise, the security guarantees fall apart.</p><p>Secure randomness used in cryptography needs to be computationally indistinguishable from “true” randomness. For this, it must both pass <a href="https://en.wikipedia.org/wiki/Randomness_test">statistical randomness tests</a>, and the output needs to be unpredictable to any computationally-bounded adversary, no matter how much previous output they’ve already seen. The typical way to achieve this is to take some random ‘seed’ and feed it into a <a href="https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator"><i>Cryptographically Secure Pseudorandom Number Generator</i></a> (CSPRNG) that can produce an essentially-endless stream of unpredictable bytes upon request. The properties of a CSPRNG ensure that all outputs are practically indistinguishable from truly random outputs to anyone that does not know its internal state. However, this all depends on having a secure random seed to begin with. Take a look at <a href="/lavarand-in-production-the-nitty-gritty-technical-details">this blog</a> for more details on true randomness versus pseudorandomness, and this blog for some great examples of <a href="/why-randomness-matters">what can go wrong with insecure randomness</a>.</p><p>For many years, Cloudflare’s servers relied on local sources of entropy (such as the precise timing of packet arrivals or keyboard events) to seed their entropy pools. While there’s no reason to believe that the local entropy sources on those servers are insecure or could be easily compromised, we wanted to hedge our bets against that possibility. Our solution was to set up a system where our servers could periodically refresh their entropy pools with true randomness from an external source.</p><p>That brings us to LavaRand. “Lavarand” has long been the name given to <a href="https://en.wikipedia.org/wiki/Lavarand">systems used for the generation of randomness</a> (first by Silicon Graphics in 1997). Cloudflare <a href="/randomness-101-lavarand-in-production/">launched its instantiation of a LavaRand</a> system in 2017 as a system that collects entropy from the wall of lava lamps in our San Francisco office and makes it available via an internal API. Our servers then periodically query the API to retrieve fresh randomness from LavaRand and incorporate it into their entropy pools. The contributions made by LavaRand can be considered spice added to the entropy pool mix! (For more technical details on <a href="/lavarand-in-production-the-nitty-gritty-technical-details">contributions made by LavaRand</a>, read our previous blog post.)</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1IPp9Lizp0pL83clLWGGNa/19d397787b5a5adbb337f581d9639fce/image10.jpg" />
            
            </figure><p>Lava lamps in Cloudflare’s San Francisco office.</p>
    <div>
      <h2>Adding to the office chaos</h2>
      <a href="#adding-to-the-office-chaos">
        
      </a>
    </div>
    <p>Our lava lamps in San Francisco have been working tirelessly for years to supply fresh entropy to our systems, but they now have siblings across the world to help with their task! As Cloudflare has grown, so has the variety of entropy sources found in and sourced from our offices. <a href="/cloudflare-top-100-most-loved-workplaces-in-2022">Cloudflare’s Places team works hard</a> to ensure that our offices reflect aspects of our values and culture. Several of our larger office locations include installations of physical systems of entropy, and it is these installations that we have worked to incorporate into LavaRand over time. The tangible and exciting draw of these systems is their basis in physical mechanics that we intuitively consider random. The gloops of warmed ascending “lava” floating past cooler sinking blobs within lava lamps attract our attention just as other unpredictable (and often beautiful) dynamic systems capture our interest.</p>
    <div>
      <h3>London’s unpredictable pendulums</h3>
      <a href="#londons-unpredictable-pendulums">
        
      </a>
    </div>
    <p>Visible to visitors of our London office is a wall of double pendulums whose beautiful swings translate to another source of entropy to LavaRand and to the pool of randomness that Cloudflare’s servers pull from.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1JjgKso6GgfvLX74LEyYsE/7688dcdd10f3f3219f0c569724cb42ab/image8.jpg" />
            
            </figure><p>Close-up of double pendulum display in Cloudflare’s London office.</p><p>To the untrained eye the shadows of the pendulum stands and those cast by the rotating arms on the rear wall might seem chaotic. If so, then this installation should be labeled a success! Different light conditions and those shadows add to the chaos that is captured from this entropy source.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2JWrKSqoaPJQC2VSbHygj/e87c2936282e55730a1db4af7d4f7e7f/Screenshot-2024-03-08-at-13.13.12.png" />
            
            </figure><p>Double pendulum display in Cloudflare’s London office with changing light conditions.</p><p>Indeed, even with these arms restricted to motion in two dimensions, the path traced by the arms is mesmerizingly varied, and can be shown to be <a href="https://en.wikipedia.org/wiki/Double_pendulum">mathematically chaotic</a>. Even if we forget air resistance, temperature, and the environment, and then assume that the mutation is completely deterministic, still the resulting long-term motion is hard to predict. In particular the system is very sensitive to initial conditions, this initial state – how they are set in motion – paired with deterministic behavior produces a unique path that is traced until the pendulum comes to rest, and the system is set in motion by a Cloudflare employee in London once again.</p>
    <div>
      <h3>Austin’s mesmerizing mobiles</h3>
      <a href="#austins-mesmerizing-mobiles">
        
      </a>
    </div>
    <p>The beautiful new Cloudflare office in Austin, Texas recently celebrated its first year since opening. This office contributes its own spin on physical entropy: suspended above the entrance of the Cloudflare office in downtown Austin is an installation of translucent rainbow mobiles. These twirl, reflecting the changing light, and cast coloured patterns on the enclosing walls. The display of hanging mobiles and their shadows are very sensitive to a physical environment which includes the opening and closing of doors, HVAC changes, and ambient light. This chaotic system’s mesmerizing and changing scene is captured periodically and fed into the stream of LavaRand randomness.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5mfXP2V8pX0C0CoheE369Q/83fe1b4bdba232b8c8c722bc49987bfe/Screenshot-2024-03-08-at-13.14.22.png" />
            
            </figure><p>Hanging rainbow mobiles in Cloudflare’s Austin office.</p>
    <div>
      <h2>Mixing new sources into LavaRand</h2>
      <a href="#mixing-new-sources-into-lavarand">
        
      </a>
    </div>
    <p>We incorporated the new sources of office chaos into the LavaRand system (still called LavaRand despite including much more than lava lamps) in the same way as the existing lava lamps, which we’ve previously <a href="/lavarand-in-production-the-nitty-gritty-technical-details">described in detail</a>.</p><p>To recap, at repeated intervals, a camera captures an image of the current state of the randomness display. Since the underlying system is truly random, the produced image contains true randomness. Even shadows and changing light conditions play a part in producing something unique and unpredictable! There is another secret that we should share: at a base level, image sensors in the real world are often a source of sufficient noise that even images taken without the lens cap removed could work well as a source of entropy! We consider this added noise to be a serendipitous addition to the beautiful chaotic motion of these installations.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7zrgpZA2xosqvTzU6dk8V/6e1f061640192f7de4585d7f2959f4a7/Screenshot-2024-03-08-at-13.16.23.png" />
            
            </figure><p>Close-up of hanging rainbow mobiles in Cloudflare’s Austin office.</p><p>Once we have a still image that captures the state of the randomness display at a particular point in time, we compute a compact representation – a hash – of the image to derive a fixed-sized output of truly random bytes.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1VjuWFkK83t3EkTjPxYGc6/2ddc9da8c2553a8a1dbb04513de6acbd/image4-26.png" />
            
            </figure><p>Process of converting physical entropy displays into random byte strings.</p><p>The random bytes are then used as an input (along with the previous seed and some randomness from the system’s local entropy sources) to a <i>Key Derivation Function</i> (KDF) to compute a new randomness seed that is fed into a <a href="https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator"><i>Cryptographically Secure Pseudorandom Number Generator</i></a> (CSPRNG) that can produce an essentially-endless stream of unpredictable bytes upon request. The properties of a CSPRNG ensure that all outputs are practically indistinguishable from truly random outputs to anyone that does not know its internal state. LavaRand then exposes this stream of randomness via a simple internal API where clients can request fresh randomness.</p>
            <pre><code>seed = KDF(new image || previous seed || system randomness)
rng = CSPRNG(seed)
…
rand1 = rng.random()
rand2 = rng.random()</code></pre>
            
    <div>
      <h2>How can I use LavaRand?</h2>
      <a href="#how-can-i-use-lavarand">
        
      </a>
    </div>
    <p>Applications typically use secure randomness in one of two flavors: private and public.</p><p><b>Private randomness</b> is used for generating passwords, cryptographic keys, user IDs, and other values that are meant to stay secret forever. As we’ve <a href="/lavarand-in-production-the-nitty-gritty-technical-details">previously described</a>, our servers periodically request fresh private randomness from LavaRand to help to update their entropy pools. Because of this, randomness from LavaRand is essentially available to the outside world! One easy way for developers to tap into private randomness from LavaRand is to use the <a href="https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#methods">Web Crypto API’s getRandomValues function</a> from a Cloudflare Worker, or use one that someone has already built, like <a href="https://csprng.xyz/">csprng.xyz</a> (<a href="https://github.com/ejcx/csprng.xyz">source</a>).</p><p><b>Public randomness</b> consists of unpredictable and unbiased random values that are made available to everyone once they are published, and for this reason <b><i>should not be used for generating cryptographic keys</i></b>. The winning lottery numbers and the coin flip at the start of a sporting event are some examples of public random values. A double-headed coin would <i>not</i> be an unbiased and unpredictable source of entropy and would have drastic impacts on the sports betting world.</p><p>In addition to being unpredictable and unbiased, it’s also desirable for public randomness to be <i>trustworthy</i> so that consumers of the randomness are assured that the values were faithfully produced. Not many people would buy lottery tickets if they believed that the winning ticket was going to be chosen unfairly! Indeed, there are known cases of corrupt insiders subverting public randomness for personal gain, like the <a href="https://www.nytimes.com/interactive/2018/05/03/magazine/money-issue-iowa-lottery-fraud-mystery.html">state lottery employee</a> who co-opted the lottery random number generator, allowing his friends and family to win millions of dollars.</p><p>A fundamental challenge of public randomness is that one must trust the authority producing the random outputs. Trusting a well-known authority like <a href="https://beacon.nist.gov/home">NIST</a> may suffice for many applications, but could be problematic for others (especially for applications where decentralization is important).</p>
    <div>
      <h2>drand: distributed and verifiable public randomness</h2>
      <a href="#drand-distributed-and-verifiable-public-randomness">
        
      </a>
    </div>
    <p>To help solve this problem of trust, Cloudflare joined forces with seven other independent and geographically distributed organizations back in 2019 to form the <a href="/league-of-entropy/">League of Entropy</a> to launch a public randomness beacon using the <a href="/inside-the-entropy">drand</a> (pronounced dee-rand) protocol. Each organization contributes its own unique source of randomness into the joint pool of entropy used to seed the drand network – with Cloudflare using randomness from LavaRand, of course!</p><p>While the League of Entropy started out as an experimental network, with the guidance and support from the drand team at <a href="https://protocol.ai/">Protocol Labs</a>, it’s become a reliable and production-ready core Internet service, relied upon by applications ranging from <a href="https://spec.filecoin.io/libraries/drand/">distributed file storage</a> to <a href="https://twitter.com/etherplay/status/1734875536608882799">online gaming</a> to <a href="https://medium.com/tierion/tierion-joins-the-league-of-entropy-replaces-nist-randomness-beacon-with-drand-in-chainpoint-9f3c32f0cd9b">timestamped proofs</a> to <a href="https://drand.love/docs/timelock-encryption/">timelock encryption</a> (discussed further below). The League of Entropy has also grown, and there are now 18 organizations across four continents participating in the drand network.</p><p>The League of Entropy’s drand beacons (each of which runs with different parameters, such as how frequently random values are produced and whether the randomness is <i>chained</i> – more on this below) have two important properties that contribute to their trustworthiness: they are <i>decentralized</i> and <i>verifiable</i>. Decentralization ensures that one or two bad actors cannot subvert or bias the randomness beacon, and verifiability allows anyone to check that the random values are produced according to the drand protocol and with participation from a threshold (at least half, but usually more) of the participants in the drand network. Thus, with each new member, the trustworthiness and reliability of the drand network continues to increase.</p><p>We give a brief overview of how drand achieves these properties using distributed key generation and threshold signatures below, but for an in-depth dive see our <a href="/inside-the-entropy">previous blog post</a> and some of the <a href="https://drand.love/blog/">excellent posts</a> from the drand team.</p>
    <div>
      <h3>Distributed key generation and threshold signatures</h3>
      <a href="#distributed-key-generation-and-threshold-signatures">
        
      </a>
    </div>
    <p>During the initial setup of a drand beacon, nodes in the network run a distributed key generation (DKG) protocol based on the <a href="https://en.wikipedia.org/wiki/Distributed_key_generation">Pedersen commitment scheme</a>, the result of which is that each node holds a “share” (a keypair) for a distributed group key, which remains fixed for the lifetime of the beacon. In order to do something useful with the group secret key like signing a message, at least a threshold (for example 7 out of 9) of nodes in the network must participate in constructing a <a href="https://en.wikipedia.org/wiki/BLS_digital_signature">BLS threshold signature</a>. The group information for the <a href="https://drand.love/blog/2023/10/16/quicknet-is-live/">quicknet</a> beacon on the League of Entropy’s mainnet drand network is shown below:</p>
            <pre><code>curl -s https://drand.cloudflare.com/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/info | jq
{
  "public_key": "83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a",
  "period": 3,
  "genesis_time": 1692803367,
  "hash": "52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
  "groupHash": "f477d5c89f21a17c863a7f937c6a6d15859414d2be09cd448d4279af331c5d3e",
  "schemeID": "bls-unchained-g1-rfc9380",
  "metadata": {
    "beaconID": "quicknet"
  }
}</code></pre>
            <p>(The hex value 52db9b… in the URL above is the hash of the beacon’s configuration. Visit <a href="https://drand.cloudflare.com/chains">https://drand.cloudflare.com/chains</a> to see all beacons supported by our mainnet drand nodes.)</p><p>The nodes in the network are configured to periodically (every 3s for quicknet) work together to produce a signature over some agreed-upon message, like the current round number and previous round signature (more on this below). Each node uses its share of the group key to produce a partial signature over the current round message, and broadcasts it to other nodes in the network. Once a node has enough partial signatures, it can aggregate them to produce a group signature for the given round.</p>
            <pre><code>curl -s https://drand.cloudflare.com/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/public/13335 | jq
{
  "round": 13335,
  "randomness": "f4eb2e59448d155b1bc34337f2a4160ac5005429644ba61134779a8b8c6087b6",
  "signature": "a38ab268d58c04ce2d22b8317e4b66ecda5fa8841c7215bf7733af8dbaed6c5e7d8d60b77817294a64b891f719bc1b40"
}</code></pre>
            <p>The group signature for a round <i>is</i> the randomness (in the output above, the randomness value is simply the sha256 hash of the signature, for applications that prefer a shorter, fixed-sized output). The signature is unpredictable in advance as long as enough (at least a majority, but can be configured to be higher) of the nodes in the drand network are honest and do not collude. Further, anyone can validate the signature for a given round using the beacon’s group public key. It’s recommended that developers use the drand client <a href="https://drand.love/developer/clients/">libraries</a> or <a href="https://drand.love/developer/drand-client/">CLI</a> to perform verification on every value obtained from the beacon.</p>
    <div>
      <h3>Chained vs unchained randomness</h3>
      <a href="#chained-vs-unchained-randomness">
        
      </a>
    </div>
    <p>When the League of Entropy launched its first generation of drand beacons in 2019, the per-round message over which the group signature was computed included the previous round’s signature. This creates a chain of randomness rounds all the way to the first “genesis” round. Chained randomness provides some nice properties for single-source randomness beacons, and is included as a requirement in <a href="https://csrc.nist.gov/projects/interoperable-randomness-beacons">NIST’s spec for interoperable public randomness beacons</a>.</p><p>However, back in 2022 the drand team introduced the notion of <a href="https://drand.love/blog/2022/02/21/multi-frequency-support-and-timelock-encryption-capabilities/#unchained-randomness-timed-encryption">unchained randomness</a>, where the message to be signed is <i>predictable</i> and doesn’t depend on any randomness from previous rounds, and showed that it provides the same security guarantees as chained randomness for the drand network (both require an honest threshold of nodes). In the implementation of unchained randomness in the <a href="https://drand.love/blog/2023/10/16/quicknet-is-live/">quicknet</a>, the message to be signed simply consists of the round number.</p>
            <pre><code># chained randomness
signature = group_sign(round || previous_signature)

# unchained randomness
signature = group_sign(round)</code></pre>
            <p>Unchained randomness provides some powerful properties and usability improvements. In terms of usability, a consumer of the randomness beacon does not need to reconstruct the full chain of randomness to the genesis round to fully validate a particular round – the only information needed is the current round number and the group public key. This provides much more flexibility for clients, as they can choose how frequently they consume randomness rounds without needing to continuously follow the randomness chain.</p><p>Since the messages to be signed are known in advance (since they’re just the round number), unchained randomness also unlocks a powerful new property: timelock encryption.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5PVw1hyLALNYG3p20U2f2D/eeac0fd2fe805cabc1b75055cc0b0076/image7-7.png" />
            
            </figure><p>Rotating double pendulums.</p>
    <div>
      <h2>Timelock encryption</h2>
      <a href="#timelock-encryption">
        
      </a>
    </div>
    <p>Timelock (or “timed-release”) encryption is a method for encrypting a message such that it cannot be decrypted until a certain amount of time has passed. Two basic approaches to timelock encryption were described by <a href="https://dspace.mit.edu/bitstream/handle/1721.1/149822/MIT-LCS-TR-684.pdf">Rivest, Shamir, and Wagner</a>:</p><p> There are two natural approaches to implementing timed release cryptography:</p><p>  - Use “time-lock puzzles” – computational problems that cannot be solved without running a computer continuously for at least a certain amount of time.</p><p>  - Use trusted agents who promise not to reveal certain information until a specified date.</p><p>Using trusted agents has the obvious problem of ensuring that the agents are trustworthy. Secret sharing approaches can be used to alleviate this concern.</p><p>The drand network is a group of independent agents using secret sharing for trustworthiness, and the ‘certain information’ not to be revealed until a specified date sounds a lot like the per-round randomness! We describe next how timelock encryption can be implemented on top of a drand network with unchained randomness, and finish with a practical demonstration. While we don’t delve into the bilinear groups and pairings-based cryptography that make this possible, if you’re interested we encourage you to read <a href="https://eprint.iacr.org/2023/189">tlock: Practical Timelock Encryption from Threshold BLS</a> by Nicolas Gailly, Kelsey Melissaris, and Yolan Romailler.</p>
    <div>
      <h3>How to timelock your secrets</h3>
      <a href="#how-to-timelock-your-secrets">
        
      </a>
    </div>
    <p>First, identify the randomness round that, once revealed, will allow your timelock-encrypted message to be decrypted. An important observation is that since drand networks produce randomness at fixed intervals, each round in a drand beacon is closely tied to a specific timestamp (modulo small delays for the network to actually produce the beacon) which can be easily computed taking the beacon’s genesis timestamp and then adding the round number multiplied by the beacon’s period.</p><p>Once the round is decided upon, the properties of bilinear groups allow you to encrypt your message to some round with the drand beacon’s group public key.</p>
            <pre><code>ciphertext = EncryptToRound(msg, round, beacon_public_key)</code></pre>
            <p>After the nodes in the drand network cooperate to derive the randomness for the round (really, just the signature on the round number using the beacon’s group secret key), <i>anyone</i> can decrypt the ciphertext (this is where the magic of bilinear groups comes in).</p>
            <pre><code>random = Randomness(round)
message = Decrypt(ciphertext,random)</code></pre>
            <p>To make this practical, the timelocked message is actually the secret key for a symmetric scheme. This means that we encrypt the message with a symmetric key and encrypt the key with timelock, allowing for a decryption in the future.</p><p>Now, for a practical demonstration of timelock encryption, we use a tool that one of our own engineers built on top of Cloudflare Workers. The <a href="https://github.com/thibmeu/tlock-worker">source code</a> is publicly available if you’d like to take a look under the hood at how it works.</p>
            <pre><code># 1. Create a file
echo "A message from the past to the future..." &gt; original.txt

# 2. Get the drand round 1 minute into the future (20 rounds) 
BEACON="52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971"
ROUND=$(curl "https://drand.cloudflare.com/$BEACON/public/latest" | jq ".round+20")

# 3. Encrypt and require that round number
curl -X POST --data-binary @original.txt --output encrypted.pem https://tlock-worker.crypto-team.workers.dev/encrypt/$ROUND

# 4. Try to decrypt it (and only succeed 20 rounds x 3s later)
curl -X POST --data-binary @encrypted.pem --fail --show-error https://tlock-worker.crypto-team.workers.dev/decrypt</code></pre>
            
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>We hope you’ve enjoyed revisiting the tale of LavaRand as much as we have, and are inspired to visit one of Cloudflare’s offices in the future to see the randomness displays first-hand, and to use verifiable public randomness and timelock encryption from drand in your next project.</p><p>Chaos is required by the encryption that secures the Internet. LavaRand at Cloudflare will continue to turn the chaotic beauty of our physical world into a randomness stream – even as new sources are added – for novel uses all of us explorers – just like that snail – have yet to dream up.</p><p>And she gazed at the sky, the sea, the landThe waves and the caves and the golden sand.She gazed and gazed, amazed by it all,And she said to the whale, “I feel so small.”</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/aUx8oEz7t6W649nYlAmzD/f4658fe8a6b467804f2e6c21c9dec2cb/image1-30.png" />
            
            </figure><p>A snail on a whale.</p><div>
  
</div><p>Tune in for more news, announcements and thought-provoking discussions! Don't miss the full <a href="https://cloudflare.tv/shows/security-week">Security Week hub page</a>.</p> ]]></content:encoded>
            <category><![CDATA[Security Week]]></category>
            <category><![CDATA[Randomness]]></category>
            <category><![CDATA[LavaRand]]></category>
            <category><![CDATA[Research]]></category>
            <guid isPermaLink="false">2V4nElKOJ2taKnxH7Q9pw6</guid>
            <dc:creator>Cefan Daniel Rubin</dc:creator>
            <dc:creator>Luke Valenta</dc:creator>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[Privacy Pass: upgrading to the latest protocol version]]></title>
            <link>https://blog.cloudflare.com/privacy-pass-standard/</link>
            <pubDate>Thu, 04 Jan 2024 16:07:22 GMT</pubDate>
            <description><![CDATA[ In this post, we explore the latest changes to Privacy Pass protocol. We are also excited to introduce a public implementation of the latest IETF draft of the Privacy Pass protocol — including a set of open-source templates that can be used to implement Privacy Pass Origins, Issuers, and Attesters ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2LZJxp89GI8PxGwGSPRQJL/9cfe61e756369dcad6cb78f5ad89ec1f/image9.png" />
            
            </figure>
    <div>
      <h2>Enabling anonymous access to the web with privacy-preserving cryptography</h2>
      <a href="#enabling-anonymous-access-to-the-web-with-privacy-preserving-cryptography">
        
      </a>
    </div>
    <p>The challenge of telling humans and bots apart is almost as old as the web itself. From online ticket vendors to dating apps, to ecommerce and finance — there are many legitimate reasons why you'd want to know if it's a person or a machine knocking on the front door of your website.</p><p>Unfortunately, the tools for the web have traditionally been clunky and sometimes involved a bad user experience. None more so than the CAPTCHA — an irksome solution that humanity wastes a <a href="/introducing-cryptographic-attestation-of-personhood/">staggering</a> amount of time on. A more subtle but intrusive approach is IP tracking, which uses IP addresses to identify and take action on suspicious traffic, but that too can come with <a href="/consequences-of-ip-blocking/">unforeseen consequences</a>.</p><p>And yet, the problem of distinguishing legitimate human requests from automated bots remains as vital as ever. This is why for years Cloudflare has invested in the Privacy Pass protocol — a novel approach to establishing a user’s identity by relying on cryptography, rather than crude puzzles — all while providing a streamlined, privacy-preserving, and often frictionless experience to end users.</p><p>Cloudflare began <a href="/cloudflare-supports-privacy-pass/">supporting Privacy Pass</a> in 2017, with the release of browser extensions for Chrome and Firefox. Web admins with their sites on Cloudflare would have Privacy Pass enabled in the Cloudflare Dash; users who installed the extension in their browsers would see fewer CAPTCHAs on websites they visited that had Privacy Pass enabled.</p><p>Since then, Cloudflare <a href="/end-cloudflare-captcha/">stopped issuing CAPTCHAs</a>, and Privacy Pass has come a long way. Apple uses a version of Privacy Pass for its <a href="https://developer.apple.com/news/?id=huqjyh7k">Private Access Tokens</a> system which works in tandem with a device’s secure enclave to attest to a user’s humanity. And Cloudflare uses Privacy Pass as an important signal in our Web Application Firewall and Bot Management products — which means millions of websites natively offer Privacy Pass.</p><p>In this post, we explore the latest changes to Privacy Pass protocol. We are also excited to introduce a public implementation of the latest IETF draft of the <a href="https://www.ietf.org/archive/id/draft-ietf-privacypass-protocol-16.html">Privacy Pass protocol</a> — including a <a href="https://github.com/cloudflare?q=pp-&amp;type=all&amp;language=&amp;sort=#org-repositories">set of open-source templates</a> that can be used to implement Privacy Pass <a href="https://github.com/cloudflare/pp-origin"><i>Origins</i></a><i>,</i> <a href="https://github.com/cloudflare/pp-issuer"><i>Issuers</i></a>, and <a href="https://github.com/cloudflare/pp-attester"><i>Attesters</i></a>. These are based on Cloudflare Workers, and are the easiest way to get started with a new deployment of Privacy Pass.</p><p>To complement the updated implementations, we are releasing a new version of our Privacy Pass browser extensions (<a href="https://addons.mozilla.org/en-US/firefox/addon/privacy-pass/">Firefox</a>, <a href="https://chromewebstore.google.com/detail/privacy-pass/ajhmfdgkijocedmfjonnpjfojldioehi">Chrome</a>), which are rolling out with the name: <i>Silk - Privacy Pass Client</i>. Users of these extensions can expect to see fewer bot-checks around the web, and will be contributing to research about privacy preserving signals via a set of trusted attesters, which can be configured in the extension’s settings panel.</p><p>Finally, we will discuss how Privacy Pass can be used for an array of scenarios beyond differentiating bot from human traffic.</p><p><b>Notice to our users</b></p><ul><li><p>If you use the Privacy Pass API that controls Privacy Pass configuration on Cloudflare, you can remove these calls. This API is no longer needed since Privacy Pass is now included by default in our Challenge Platform. Out of an abundance of caution for our customers, we are doing a <a href="https://developers.cloudflare.com/fundamentals/api/reference/deprecations/">four-month deprecation notice</a>.</p></li><li><p>If you have the Privacy Pass extension installed, it should automatically update to <i>Silk - Privacy Pass Client</i> (<a href="https://addons.mozilla.org/en-US/firefox/addon/privacy-pass/">Firefox</a>, <a href="https://chromewebstore.google.com/detail/privacy-pass/ajhmfdgkijocedmfjonnpjfojldioehi">Chrome</a>) over the next few days. We have renamed it to keep the distinction clear between the protocol itself and a client of the protocol.</p></li></ul>
    <div>
      <h2>Brief history</h2>
      <a href="#brief-history">
        
      </a>
    </div>
    <p>In the last decade, we've seen the <a href="/next-generation-privacy-protocols/">rise of protocols</a> with privacy at their core, including <a href="/building-privacy-into-internet-standards-and-how-to-make-your-app-more-private-today/">Oblivious HTTP (OHTTP)</a>, <a href="/deep-dive-privacy-preserving-measurement/">Distributed aggregation protocol (DAP)</a>, and <a href="/unlocking-quic-proxying-potential/">MASQUE</a>. These protocols improve privacy when browsing and interacting with services online. By protecting users' privacy, these protocols also ask origins and website owners to revise their expectations around the data they can glean from user traffic. This might lead them to reconsider existing assumptions and mitigations around suspicious traffic, such as <a href="/consequences-of-ip-blocking/">IP filtering</a>, which often has unintended consequences.</p><p>In 2017, Cloudflare announced <a href="/cloudflare-supports-privacy-pass/">support for Privacy Pass</a>. At launch, this meant improving content accessibility for web users who would see a lot of interstitial pages (such as <a href="https://www.cloudflare.com/learning/bots/how-captchas-work/">CAPTCHAs</a>) when browsing websites protected by Cloudflare. Privacy Pass tokens provide a signal about the user’s capabilities to website owners while protecting their privacy by ensuring each token redemption is unlinkable to its issuance context. Since then, the technology has turned into a <a href="https://datatracker.ietf.org/wg/privacypass/documents/">fully fledged protocol</a> used by millions thanks to academic and industry effort. The existing browser extension accounts for hundreds of thousands of downloads. During the same time, Cloudflare has dramatically evolved the way it allows customers to challenge their visitors, being <a href="/end-cloudflare-captcha/">more flexible about the signals</a> it receives, and <a href="/turnstile-ga/">moving away from CAPTCHA</a> as a binary legitimacy signal.</p><p>Deployments of this research have led to a broadening of use cases, opening the door to different kinds of attestation. An attestation is a cryptographically-signed data point supporting facts. This can include a signed token indicating that the user has successfully solved a CAPTCHA, having a user’s hardware attest it’s untampered, or a piece of data that an attester can verify against another data source.</p><p>For example, in 2022, Apple hardware devices began to offer Privacy Pass tokens to websites who wanted to reduce how often they show CAPTCHAs, by using the hardware itself as an attestation factor. Before showing images of buses and fire hydrants to users, CAPTCHA providers can request a <a href="https://developer.apple.com/news/?id=huqjyh7k">Private Access Token</a> (PAT). This native support does not require installing extensions, or any user action to benefit from a smoother and more private web browsing experience.</p><p>Below is a brief overview of changes to the protocol we participated in:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3YImfph78oDPj3kgEcyvV6/37bcd89ffcfff8b636b00c8e931f3218/image8.png" />
            
            </figure><p>The timeline presents cryptographic changes, community inputs, and industry collaborations. These changes helped shape better standards for the web, such as VOPRF (<a href="https://www.rfc-editor.org/rfc/rfc9497">RFC 9497</a>), or RSA Blind Signatures (<a href="https://www.rfc-editor.org/rfc/rfc9474">RFC 9474</a>). In the next sections, we dive in the Privacy Pass protocol to understand its ins and outs.</p>
    <div>
      <h2>Anonymous credentials in real life</h2>
      <a href="#anonymous-credentials-in-real-life">
        
      </a>
    </div>
    <p>Before explaining the protocol in more depth, let's use an analogy. You are at a music festival. You bought your ticket online with a student discount. When you arrive at the gates, an agent scans your ticket, checks your student status, and gives you a yellow wristband and two drink tickets.</p><p>During the festival, you go in and out by showing your wristband. When a friend asks you to grab a drink, you pay with your tickets. One for your drink and one for your friend. You give your tickets to the bartender, they check the tickets, and give you a drink. The characteristics that make this interaction private is that the drinks tickets cannot be traced back to you or your payment method, but they can be verified as having been unused and valid for purchase of a drink.</p><p>In the web use case, the Internet is a festival. When you arrive at the gates of a website, an agent scans your request, and gives you a session cookie as well as two Privacy Pass tokens. They could have given you just one token, or more than two, but in our example ‘two tokens’ is the given website’s policy. You can use these tokens to attest your humanity, to authenticate on certain websites, or even to confirm the legitimacy of your hardware.</p><p>Now, you might wonder if this is a technique we have been using for years, why do we need fancy cryptography and standardization efforts? Well, unlike at a real-world music festival where most people don’t carry around photocopiers, on the Internet it is pretty easy to copy tokens. For instance, how do we stop people using a token twice? We could put a unique number on each token, and check it is not spent twice, but that would allow the gate attendant to tell the bartender which numbers were linked to which person. So, we need cryptography.</p><p>When another website presents a challenge to you, you provide your Privacy Pass token and are then allowed to view a gallery of beautiful cat pictures. The difference with the festival is this challenge might be interactive, which would be similar to the bartender giving you a numbered ticket which would have to be signed by the agent before getting a drink. The website owner can verify that the token is valid but has no way of tracing or connecting the user back to the action that provided them with the Privacy Pass tokens. With Privacy Pass terminology, you are a Client, the website is an Origin, the agent is an Attester, and the bar an Issuer. The next section goes through these in more detail.</p>
    <div>
      <h2>Privacy Pass protocol</h2>
      <a href="#privacy-pass-protocol">
        
      </a>
    </div>
    <p>Privacy Pass specifies an extensible protocol for creating and redeeming anonymous and transferable tokens. In fact, Apple has their own implementation with Private Access Tokens (PAT), and later we will describe another implementation with the Silk browser extension. Given PAT was the first to implement the IETF defined protocol, Privacy Pass is sometimes referred to as PAT in the literature.</p><p>The protocol is generic, and defines four components:</p><ul><li><p>Client: Web user agent with a Privacy Pass enabled browser. This could be your <a href="/eliminating-captchas-on-iphones-and-macs-using-new-standard/">Apple device with PAT</a>, or your web browser with <a href="https://github.com/cloudflare/pp-browser-extension">the Silk extension installed</a>. Typically, this is the actor who is requesting content and is asked to share some attribute of themselves.</p></li><li><p>Origin: Serves content requested by the Client. The Origin trusts one or more Issuers, and presents Privacy Pass challenges to the Client. For instance, Cloudflare Managed Challenge is a Privacy Pass origin serving two Privacy Pass challenges: one for Apple PAT Issuer, one for Cloudflare Research Issuer.</p></li><li><p>Issuer: Signs Privacy Pass tokens upon request from a trusted party, either an Attester or a Client depending on the deployment model. Different Issuers have their own set of trusted parties, depending on the security level they are looking for, as well as their privacy considerations. An Issuer validating device integrity should use different methods that vouch for this attribute to acknowledge the diversity of Client configurations.</p></li><li><p>Attester: Verifies an attribute of the Client and when satisfied requests a signed Privacy Pass token from the Issuer to pass back to the Client. Before vouching for the Client, an Attester may ask the Client to complete a specific task. This task could be a CAPTCHA, a location check, or age verification or some other check that will result in a single binary result. The Privacy Pass token will then share this one-bit of information in an unlinkable manner.</p></li></ul><p>They interact as illustrated below.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7tX1xRQv6Ltif1NRj2fCOa/eeb412fa39d73e2232f4b062d95cd708/Frame-699-1-.png" />
            
            </figure><p>Let's dive into what's really happening with an example. The User wants to access an Origin, say store.example.com. This website has suffered attacks or abuse in the past, and the site is using Privacy Pass to help avoid these going forward. To that end, the Origin returns <a href="https://www.rfc-editor.org/rfc/rfc9110#field.www-authenticate">an authentication request</a> to the Client: <code>WWW-Authenticate: PrivateToken challenge="A==",token-key="B=="</code>. In this way, the Origin signals that it accepts tokens from the Issuer with public key “B==” to satisfy the challenge. That Issuer in turn trusts reputable Attesters to vouch for the Client not being an attacker by means of the presence of a cookie, CAPTCHA, Turnstile, or <a href="/introducing-cryptographic-attestation-of-personhood/">CAP challenge</a> for example. For accessibility reasons for our example, let us say that the Client likely prefers the Turnstile method. The User’s browser prompts them to solve a Turnstile challenge. On success, it contacts the Issuer “B==” with that solution, and then replays the initial requests to store.example.com, this time sending along the token header <code>Authorization: PrivateToken token="C=="</code>, which the Origin accepts and returns your desired content to the Client. And that’s it.</p><p>We’ve described the Privacy Pass authentication protocol. While Basic authentication (<a href="https://www.rfc-editor.org/rfc/rfc7617">RFC 7671</a>) asks you for a username and a password, the PrivateToken authentication scheme allows the browser to be more flexible on the type of check, while retaining privacy. The Origin store.example.com does not know your attestation method, they just know you are reputable according to the token issuer. In the same spirit, the Issuer "B==" does not see your IP, nor the website you are visiting. This separation between issuance and redemption, also referred to as unlinkability, is what <a href="https://www.ietf.org/archive/id/draft-ietf-privacypass-architecture-16.html">makes Privacy Pass private</a>.</p>
    <div>
      <h2>Demo time</h2>
      <a href="#demo-time">
        
      </a>
    </div>
    <p>To put the above in practice, let’s see how the protocol works with Silk, a browser extension providing Privacy Pass support. First, download the relevant <a href="https://chromewebstore.google.com/detail/privacy-pass/ajhmfdgkijocedmfjonnpjfojldioehi">Chrome</a> or <a href="https://addons.mozilla.org/en-US/firefox/addon/privacy-pass/">Firefox</a> extension.</p><p>Then, head to <a href="https://demo-pat.research.cloudflare.com/login">https://demo-pat.research.cloudflare.com/login</a>. The page returns a 401 Privacy Pass Token not presented. In fact, the origin expects you to perform a PrivateToken authentication. If you don’t have the extension installed, the flow stops here. If you have the extension installed, the extension is going to orchestrate the flow required to get you a token requested by the Origin.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ZPDrhytZNVoB81Q7RILu5/7c115c9ed069aa09694373ec1adcc4d0/image10.png" />
            
            </figure><p>With the extension installed, you are directed to a new tab <a href="https://pp-attester-turnstile.research.cloudflare.com/challenge">https://pp-attester-turnstile.research.cloudflare.com/challenge</a>. This is a page provided by an Attester able to deliver you a token signed by the Issuer request by the Origin. In this case, the Attester checks you’re able to solve a Turnstile challenge.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7fmDWo3548oMK8jgZ7V0Kd/94ee9ab9bc1df6fee6e6a76dc4fb3e02/image2.png" />
            
            </figure><p>You click, and that’s it. The Turnstile challenge solution is sent to the Attester, which upon validation, sends back a token from the requested Issuer. This page appears for a very short time, as once the extension has the token, the challenge page is no longer needed.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3KROIlp9njiXlfceDzRU7W/d1e306da3012c949e3fa5b80934f83a4/image11.png" />
            
            </figure><p>The extension, now having a token requested by the Origin, sends your initial request for a second time, with an Authorization header containing a valid Issuer PrivateToken. Upon validation, the Origin allows you in with a 200 Privacy Pass Token valid!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3qOSkMc5wIqS50CuNNNoZY/b36b88ba01ffa1c5f4d78727e602062f/image3.png" />
            
            </figure><p>If you want to check behind the scenes, you can right-click on the extension logo and go to the preference/options page. It contains a list of attesters trusted by the extension, one per line. You can add your own attestation method (API described below). This allows the Client to decide on their preferred attestation methods.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/78BCHYQuOBC2aFlnPshu83/c6ee6b54d1d24b6f92f34577267a1146/image7.png" />
            
            </figure>
    <div>
      <h2>Privacy Pass protocol — extended</h2>
      <a href="#privacy-pass-protocol-extended">
        
      </a>
    </div>
    <p>The Privacy Pass protocol is new and not a standard yet, which implies that it’s not uniformly supported on all platforms. To improve flexibility beyond the existing standard proposal, we are introducing two mechanisms: an API for Attesters, and a replay API for web clients. The API for attesters allows developers to build new attestation methods, which only need to provide their URL to interface with the Silk browser extension. The replay API for web clients is a mechanism to enable websites to cooperate with the extension to make PrivateToken authentication work on browsers with Chrome user agents.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2TLz1CPx9OHczqLabCRmyc/c54b0b4bb637a97812c637ca0eebc78c/image12.png" />
            
            </figure><p>Because more than one Attester may be supported on your machine, your Client needs to understand which Attester to use depending on the requested Issuer. As mentioned before, you as the Client do not communicate directly with the Issuer because you don’t necessarily know their relation with the attester, so you cannot retrieve its public key. To this end, the Attester API exposes all Issuers reachable by the said Attester via an endpoint: /v1/private-token-issuer-directory. This way, your client selects an appropriate Attester - one in relation with an Issuer that the Origin trusts, before triggering a validation.</p><p>In addition, we propose a replay API. Its goal is to allow clients to fetch a resource a second time if the first response presented a Privacy pass challenge. Some platforms do this automatically, like Silk on Firefox, but some don’t. That’s the case with the Silk Chrome extension for instance, which in its support of <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/manifest_version">manifest v3</a> cannot block requests and only supports Basic authentication in the onAuthRequired extension event. The Privacy Pass Authentication scheme proposes the request to be sent once to get a challenge, and then a second time to get the actual resource. Between these requests to the Origin, the platform orchestrates the issuance of a token. To keep clients informed about the state of this process, we introduce a <code>private-token-client-replay: UUID header</code> alongside WWW-Authenticate. Using a platform defined endpoint, this UUID informs web clients of the current state of authentication: pending, fulfilled, not-found.</p><p>To learn more about how you can use these today, and to deploy your own attestation method, read on.</p>
    <div>
      <h2>How to use Privacy Pass today?</h2>
      <a href="#how-to-use-privacy-pass-today">
        
      </a>
    </div>
    <p>As seen in the section above, Privacy Pass is structured around four components: Origin, Client, Attester, Issuer. That’s why we created four repositories: <a href="https://github.com/cloudflare/pp-origin">cloudflare/pp-origin</a>, <a href="https://github.com/cloudflare/pp-browser-extension">cloudflare/pp-browser-extension</a>, <a href="https://github.com/cloudflare/pp-attester">cloudflare/pp-attester</a>, <a href="https://github.com/cloudflare/pp-issuer">cloudflare/pp-issuer</a>. In addition, the underlying cryptographic libraries are available <a href="https://github.com/cloudflare/privacypass-ts">cloudflare/privacypass-ts</a>, <a href="https://github.com/cloudflare/blindrsa-ts">cloudflare/blindrsa-ts</a>, and <a href="https://github.com/cloudflare/voprf-ts">cloudflare/voprf-ts</a>. In this section, we dive into how to use each one of these depending on your use case.</p><blockquote><p>Note: All examples below are designed in JavaScript and targeted at Cloudflare Workers. Privacy Pass is also implemented in <a href="https://github.com/ietf-wg-privacypass/base-drafts#existing-implementations">other languages</a> and can be deployed with a configuration that suits your needs.</p></blockquote>
    <div>
      <h3>As an Origin - website owners, service providers</h3>
      <a href="#as-an-origin-website-owners-service-providers">
        
      </a>
    </div>
    <p>You are an online service that people critically rely upon (health or messaging for instance). You want to provide private payment options to users to maintain your users’ privacy. You only have one subscription tier at $10 per month. You have <a href="https://datatracker.ietf.org/doc/html/draft-davidson-pp-architecture-00#autoid-60">heard</a> people are making privacy preserving apps, and want to use the latest version of Privacy Pass.</p><p>To access your service, users are required to prove they've paid for the service through a payment provider of their choosing (that you deem acceptable). This payment provider acknowledges the payment and requests a token for the user to access the service. As a sequence diagram, it looks as follows:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3CDt5NsDY4c2DuYbggdleT/c2084b1b7cb141a8b528de78392833b3/image4.png" />
            
            </figure><p>To implement it in Workers, we rely on the <a href="https://www.npmjs.com/package/@cloudflare/privacypass-ts"><code>@cloudflare/privacypass-ts</code></a> library, which can be installed by running:</p>
            <pre><code>npm i @cloudflare/privacypass-ts</code></pre>
            <p>This section is going to focus on the Origin work. We assume you have an Issuer up and running, which is described in a later section.</p><p>The Origin defines two flows:</p><ol><li><p>User redeeming token</p></li><li><p>User requesting a token issuance</p></li></ol>
            <pre><code>import { Client } from '@cloudflare/privacypass-ts'

const issuer = 'static issuer key'

const handleRedemption =&gt; (req) =&gt; {
    const token = TokenResponse.parse(req.headers.get('authorization'))
    const isValid = token.verify(issuer.publicKey)
}

const handleIssuance = () =&gt; {
    return new Response('Please pay to access the service', {
        status: 401,
        headers: { 'www-authenticate': 'PrivateToken challenge=, token-key=, max-age=300' }
    })
}

const handleAuth = (req) =&gt; {
    const authorization = req.headers.get('authorization')
    if (authorization.startsWith(`PrivateToken token=`)) {
        return handleRedemption(req)
    }
    return handleIssuance(req)
}

export default {
    fetch(req: Request) {
        return handleAuth(req)
    }
}</code></pre>
            <p>From the user’s perspective, the overhead is minimal. Their client (possibly the Silk browser extension) receives a WWW-Authenticate header with the information required for a token issuance. Then, depending on their client configuration, they are taken to the payment provider of their choice to validate their access to the service.</p><p>With a successful response to the PrivateToken challenge a session is established, and the traditional web service flow continues.</p>
    <div>
      <h3>As an Attester - CAPTCHA providers, authentication provider</h3>
      <a href="#as-an-attester-captcha-providers-authentication-provider">
        
      </a>
    </div>
    <p>You are the author of a new attestation method, such as <a href="/introducing-cryptographic-attestation-of-personhood/">CAP,</a> a new CAPTCHA mechanism, or a new way to validate cookie consent. You know that website owners already use Privacy Pass to trigger such challenges on the user side, and an Issuer is willing to trust your method because it guarantees a high security level. In addition, because of the Privacy Pass protocol you never see which website your attestation is being used for.</p><p>So you decide to expose your attestation method as a Privacy Pass Attester. An Issuer with public key B== trusts you, and that's the Issuer you are going to request a token from. You can check that with the Yes/No Attester below, whose code is on <a href="https://cloudflareworkers.com/#eedc5a7a6560c44b23a24cc1414b29d7:https://tutorial.cloudflareworkers.com/v1/challenge">Cloudflare Workers playground</a></p>
            <pre><code>const ISSUER_URL = 'https://pp-issuer-public.research.cloudflare.com/token-request'

const b64ToU8 = (b) =&gt;  Uint8Array.from(atob(b), c =&gt; c.charCodeAt(0))

const handleGetChallenge = (req) =&gt; {
    return new Response(`
    &lt;html&gt;
    &lt;head&gt;
      &lt;title&gt;Challenge Response&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
    	&lt;button onclick="sendResponse('Yes')"&gt;Yes&lt;/button&gt;
		&lt;button onclick="sendResponse('No')"&gt;No&lt;/button&gt;
	&lt;/body&gt;
	&lt;script&gt;
	function sendResponse(choice) {
		fetch(location.href, { method: 'POST', headers: { 'private-token-attester-data': choice } })
	}
	&lt;/script&gt;
	&lt;/html&gt;
	`, { status: 401, headers: { 'content-type': 'text/html' } })
}

const handlePostChallenge = (req) =&gt; {
    const choice = req.headers.get('private-token-attester-data')
    if (choice !== 'Yes') {
        return new Response('Unauthorised', { status: 401 })
    }

    // hardcoded token request
    // debug here https://pepe-debug.research.cloudflare.com/?challenge=PrivateToken%20challenge=%22AAIAHnR1dG9yaWFsLmNsb3VkZmxhcmV3b3JrZXJzLmNvbSBE-oWKIYqMcyfiMXOZpcopzGBiYRvnFRP3uKknYPv1RQAicGVwZS1kZWJ1Zy5yZXNlYXJjaC5jbG91ZGZsYXJlLmNvbQ==%22,token-key=%22MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEApqzusqnywE_3PZieStkf6_jwWF-nG6Es1nn5MRGoFSb3aXJFDTTIX8ljBSBZ0qujbhRDPx3ikWwziYiWtvEHSLqjeSWq-M892f9Dfkgpb3kpIfP8eBHPnhRKWo4BX_zk9IGT4H2Kd1vucIW1OmVY0Z_1tybKqYzHS299mvaQspkEcCo1UpFlMlT20JcxB2g2MRI9IZ87sgfdSu632J2OEr8XSfsppNcClU1D32iL_ETMJ8p9KlMoXI1MwTsI-8Kyblft66c7cnBKz3_z8ACdGtZ-HI4AghgW-m-yLpAiCrkCMnmIrVpldJ341yR6lq5uyPej7S8cvpvkScpXBSuyKwIDAQAB%22
    const body = b64ToU8('AALoAYM+fDO53GVxBRuLbJhjFbwr0uZkl/m3NCNbiT6wal87GEuXuRw3iZUSZ3rSEqyHDhMlIqfyhAXHH8t8RP14ws3nQt1IBGE43Q9UinwglzrMY8e+k3Z9hQCEw7pBm/hVT/JNEPUKigBYSTN2IS59AUGHEB49fgZ0kA6ccu9BCdJBvIQcDyCcW5LCWCsNo57vYppIVzbV2r1R4v+zTk7IUDURTa4Mo7VYtg1krAWiFCoDxUOr+eTsc51bWqMtw2vKOyoM/20Wx2WJ0ox6JWdPvoBEsUVbENgBj11kB6/L9u2OW2APYyUR7dU9tGvExYkydXOfhRFJdKUypwKN70CiGw==')
    // You can perform some check here to confirm the body is a valid token request

    console.log('requesting token for tutorial.cloudflareworkers.com')
    return fetch(ISSUER_URL, {
      method: 'POST',
      headers: { 'content-type': 'application/private-token-request' },
      body: body,
    })
}

const handleIssuerDirectory = async () =&gt; {
    // These are fake issuers
    // Issuer data can be fetch at https://pp-issuer-public.research.cloudflare.com/.well-known/private-token-issuer-directory
    const TRUSTED_ISSUERS = {
        "issuer1": { "token-keys": [{ "token-type": 2, "token-key": "A==" }] },
        "issuer2": { "token-keys": [{ "token-type": 2, "token-key": "B==" }] },
    }
    return new Response(JSON.stringify(TRUSTED_ISSUERS), { headers: { "content-type": "application/json" } })
}

const handleRequest = (req) =&gt; {
    const pathname = new URL(req.url).pathname
    console.log(pathname, req.url)
    if (pathname === '/v1/challenge') {
        if (req.method === 'POST') {
            return handlePostChallenge(req)
        }
        return handleGetChallenge(req)
    }
    if (pathname === '/v1/private-token-issuer-directory') {
        return handleIssuerDirectory()
    }
    return new Response('Not found', { status: 404 })
}

addEventListener('fetch', event =&gt; {
    event.respondWith(handleRequest(event.request))
})</code></pre>
            <p>The validation method above is simply checking if the user selected yes. Your method might be more complex, the wrapping stays the same.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5PnBuinoRKUpYjrBsHQbn/966c266e7de411503c5bf9a5dc9a184d/Screenshot-2024-01-04-at-10.30.04.png" />
            
            </figure><p><i>Screenshot of the Yes/No Attester example</i></p><p>Because users might have multiple Attesters configured for a given Issuer, we recommend your Attester implements one additional endpoint exposing the keys of the issuers you are in contact with. You can try this code on <a href="https://cloudflareworkers.com/#4eeeef2fa895e519addb3ae442ee351d:https://tutorial.cloudflareworkers.com/v1/private-token-issuer-directory">Cloudflare Workers playground</a>.</p>
            <pre><code>const handleIssuerDirectory = () =&gt; {
    const TRUSTED_ISSUERS = {
        "issuer1": { "token-keys": [{ "token-type": 2, "token-key": "A==" }] },
        "issuer2": { "token-keys": [{ "token-type": 2, "token-key": "B==" }] },
    }
    return new Response(JSON.stringify(TRUSTED_ISSUERS), { headers: { "content-type": "application/json" } })
}

export default {
    fetch(req: Request) {
        const pathname = new URL(req.url).pathname
        if (pathname === '/v1/private-token-issuer-directory') {
            return handleIssuerDirectory()
        }
    }
}</code></pre>
            <p>Et voilà. You have an Attester that can be used directly with the Silk browser extension (<a href="https://addons.mozilla.org/en-US/firefox/addon/privacy-pass/">Firefox</a>, <a href="https://chromewebstore.google.com/detail/privacy-pass/ajhmfdgkijocedmfjonnpjfojldioehi">Chrome</a>). As you progress through your deployment, it can also be directly integrated into your applications.</p><p>If you would like to have a more advanced Attester and deployment pipeline, look at <a href="https://github.com/cloudflare/pp-attester">cloudflare/pp-attester</a> template.</p>
    <div>
      <h3>As an Issuer - foundation, consortium</h3>
      <a href="#as-an-issuer-foundation-consortium">
        
      </a>
    </div>
    <p>We've mentioned the Issuer multiple times already. The role of an Issuer is to select a set of Attesters it wants to operate with, and communicate its public key to Origins. The whole cryptographic behavior of an Issuer is specified <a href="https://www.ietf.org/archive/id/draft-ietf-privacypass-protocol-16.html">by the IETF</a> draft. In contrast to the Client and Attesters which have discretionary behavior, the Issuer is fully standardized. Their opportunity is to choose a signal that is strong enough for the Origin, while preserving privacy of Clients.</p><p>Cloudflare Research is operating a public Issuer for experimental purposes to use on <a href="https://pp-issuer-public.research.cloudflare.com">https://pp-issuer-public.research.cloudflare.com</a>. It is the simplest solution to start experimenting with Privacy Pass today. Once it matures, you can consider joining a production Issuer, or deploying your own.</p><p>To deploy your own, you should:</p>
            <pre><code>git clone github.com/cloudflare/pp-issuer</code></pre>
            <p>Update wrangler.toml with your Cloudflare Workers account id and zone id. The open source Issuer API works as follows:</p><ul><li><p>/.well-known/private-token-issuer-directory returns the issuer configuration. Note it does not expose non-standard token-key-legacy</p></li><li><p>/token-request returns a token. This endpoint should be gated (by Cloudflare Access for instance) to only allow trusted attesters to call it</p></li><li><p>/admin/rotate to generate a new public key. This should only be accessible by your team, and be called prior to the issuer being available.</p></li></ul><p>Then, <code>wrangler publish</code>, and you're good to onboard Attesters.</p>
    <div>
      <h2>Development of Silk extension</h2>
      <a href="#development-of-silk-extension">
        
      </a>
    </div>
    <p>Just like the protocol, the browser technology on which Privacy Pass was proven viable has changed as well. For 5 years, the protocol got deployed along with a browser extension for Chrome and Firefox. In 2021, Chrome released a new version of extension configurations, usually referred to as <a href="https://developer.chrome.com/docs/extensions/mv3/intro/platform-vision/">Manifest version 3</a> (MV3). Chrome also started enforcing this new configuration for all newly released extensions.</p><p>Privacy Pass <i>the extension</i> is based on an agreed upon Privacy Pass <a href="https://datatracker.ietf.org/doc/draft-ietf-privacypass-auth-scheme/"><i>authentication protocol</i></a>. Briefly looking at <a href="https://developer.chrome.com/docs/extensions/reference/webRequest/">Chrome’s API documentation</a>, we should be able to use the onAuthRequired event. However, with PrivateToken authentication not yet being standard, there are no hooks provided by browsers for extensions to add logic to this event.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iQsRopHuLfmHqjsppwImc/1a379a0cdd3de3e17de04811b1c08ac0/Screenshot-2024-01-04-at-10.32.44.png" />
            
            </figure><p><i>Image available under CC-BY-SA 4.0 provided by</i> <a href="https://developer.chrome.com/docs/extensions/reference/webRequest/"><i>Google For Developers</i></a></p><p>The approach we decided to use is to define a client side replay API. When a response comes with 401 WWW-Authenticate PrivateToken, the browser lets it through, but triggers the private token redemption flow. The original page is notified when a token has been retrieved, and replays the request. For this second request, the browser is able to attach an authorization token, and the request succeeds. This is an active replay performed by the client, rather than a transparent replay done by the platform. A specification is available on <a href="https://github.com/cloudflare/pp-browser-extension#chrome-support-via-client-replay-api">GitHub</a>.</p><p>We are looking forward to the standard progressing, and simplifying this part of the project. This should improve diversity in attestation methods. As we see in the next section, this is key to identifying new signals that can be leveraged by origins.</p>
    <div>
      <h2>A standard for anonymous credentials</h2>
      <a href="#a-standard-for-anonymous-credentials">
        
      </a>
    </div>
    <p>IP remains as a key identifier in the anti abuse system. At the same time, IP fingerprinting techniques have become a bigger concern and platforms have started to remove some of these ways of tracking users. To enable anti abuse systems to not rely on IP, while ensuring user privacy, Privacy Pass offers a reasonable alternative to deal with potentially abusive or suspicious traffic. The attestation methods vary and can be chosen as needed for a particular deployment. For example, Apple decided to back their attestation with hardware when using Privacy Pass as the authorization technology for iCloud Private Relay. Another example is Cloudflare Research which decided to deploy a Turnstile attester to signal a successful solve for Cloudflare’s challenge platform.</p><p>In all these deployments, Privacy Pass-like technology has allowed for specific bits of information to be shared. Instead of sharing your location, past traffic, and possibly your name and phone number simply by connecting to a website, your device is able to prove specific information to a third party in a privacy preserving manner. Which user information and attestation methods are sufficient to prevent abuse is an open question. We are looking to empower researchers with the release of this software to help in the quest for finding these answers. This could be via new experiments such as testing out new attestation methods, or fostering other privacy protocols by providing a framework for specific information sharing.</p>
    <div>
      <h2>Future recommendations</h2>
      <a href="#future-recommendations">
        
      </a>
    </div>
    <p>Just as we expect this latest version of Privacy Pass to lead to new applications and ideas we also expect further evolution of the standard and the clients that use it. Future development of Privacy Pass promises to cover topics like batch token issuance and rate limiting. From our work building and deploying this version of Privacy Pass we have encountered limitations that we expect to be resolved in the future as well.</p><p>The division of labor between Attesters and Issuers and the clear directions of trust relationships between the Origin and Issuer, and the Issuer and Attester make reasoning about the implications of a breach of trust clear. Issuers can trust more than one Attester, but since many current deployments of Privacy Pass do not identify the Attester that lead to issuance, a breach of trust in one Attester would render all tokens issued by any Issuer that trusts the Attester untrusted. This is because it would not be possible to tell which Attester was involved in the issuance process. Time will tell if this promotes a 1:1 correspondence between Attesters and Issuers.</p><p>The process of developing a browser extension supported by both Firefox and Chrome-based browsers can at times require quite baroque (and brittle) code paths. Privacy Pass the protocol seems a good fit for an extension of the <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onAuthRequired">webRequest.onAuthRequired</a> browser event. Just as Privacy Pass appears as an alternate authentication message in the WWW-Authenticate HTTP header, browsers could fire the onAuthRequired event for Private Token authentication too and include and allow request blocking support within the onAuthRequired event. This seems a natural evolution of the use of this event which currently is limited to the now rather long-in-the-tooth Basic authentication.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Privacy Pass provides a solution to one of the longstanding challenges of the web: anonymous authentication. By leveraging cryptography, the protocol allows websites to get the information they need from users, and solely this information. It's already used by millions to help distinguish human requests from automated bots in a manner that is privacy protective and often seamless. We are excited by the protocol’s broad and growing adoption, and by the novel use cases that are unlocked by this latest version.</p><p>Cloudflare’s Privacy Pass implementations are available on GitHub, and are compliant with the standard. We have open-sourced a <a href="https://github.com/cloudflare?q=pp-&amp;type=all&amp;language=&amp;sort=#org-repositories">set of templates</a> that can be used to implement Privacy Pass <a href="https://github.com/cloudflare/pp-origin"><i>Origins</i></a><i>,</i> <a href="https://github.com/cloudflare/pp-issuer"><i>Issuers</i></a>, and <a href="https://github.com/cloudflare/pp-attester"><i>Attesters</i></a>, which leverage Cloudflare Workers to get up and running quickly.</p><p>For those looking to try Privacy Pass out for themselves right away, download the <i>Silk - Privacy Pass Client</i> browser extensions (<a href="https://addons.mozilla.org/en-US/firefox/addon/privacy-pass/">Firefox</a>, <a href="https://chromewebstore.google.com/detail/privacy-pass/ajhmfdgkijocedmfjonnpjfojldioehi">Chrome</a>, <a href="https://github.com/cloudflare/pp-browser-extension">GitHub</a>) and start browsing a web with fewer bot checks today.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Privacy Pass]]></category>
            <category><![CDATA[Firefox]]></category>
            <category><![CDATA[Chrome]]></category>
            <category><![CDATA[Privacy]]></category>
            <guid isPermaLink="false">47vZ5BZfqt5cU38XabKyUA</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>Cefan Daniel Rubin</dc:creator>
            <dc:creator>Armando Faz-Hernández</dc:creator>
        </item>
        <item>
            <title><![CDATA[Serving Cloudflare Pages sites to the IPFS network]]></title>
            <link>https://blog.cloudflare.com/cloudflare-pages-on-ipfs/</link>
            <pubDate>Mon, 16 May 2022 12:57:44 GMT</pubDate>
            <description><![CDATA[ Today, we're announcing we're bridging the two. We will make it possible for our customers to serve their sites on the IPFS network ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Four years ago, <a href="/distributed-web-gateway/">Cloudflare went Interplanetary</a> by offering a gateway to the IPFS network. This meant that if you hosted content on IPFS, we offered to make it available to every user of the Internet through HTTPS and with Cloudflare protection. IPFS allows you to choose a storage provider you are comfortable with, while providing a standard interface for Cloudflare to serve this data.</p><p>Since then, businesses have new tools to streamline web development. <a href="https://workers.dev">Cloudflare Workers</a>, <a href="https://pages.cloudflare.com">Pages</a>, and <a href="/introducing-r2-object-storage/">R2</a> are enabling developers to bring services online in a matter of minutes, with built-in scaling, security, and analytics.</p><p>Today, we're announcing we're bridging the two. We will make it possible for our customers to serve their sites on the IPFS network.</p><p>In this post, we'll learn how you will be able to build your website with Cloudflare Pages, and leverage the IPFS integration to make your content accessible and available across multiple providers.</p>
    <div>
      <h2>A primer on IPFS</h2>
      <a href="#a-primer-on-ipfs">
        
      </a>
    </div>
    <p>The InterPlanetary FileSystem (IPFS) is a peer-to-peer network for storing content on a distributed file system. It is composed of a set of computers called nodes that store and relay content using a common addressing system. In short, a set of participants agree to maintain a shared index of content the network can provide, and where to find it.</p><p>Let's take two random participants in the network: Alice, a cat person, and Bob, a dog person.</p><p>As a participant in the network, Alice keeps connections with a subset of participants, referred to as her peers. When Alice is making her content 🐱 available on IPFS, it means she announces to her peers she has content 🐱, and these peers stored in their routing table 🐱 is provided by Alice's node.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6BzC2QWnSrnF6lIqzMd0S8/df749e6c4e59acccb288c078235cab46/image7-8.png" />
            
            </figure><p>Each node has a routing table, and a datastore. The routing table retains a mapping of content to peers, and the datastore retains the content a given node stores. In the above case, only Alice has content, a 🐱.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1JKs4dKwaokLGutycmasSr/ee51d2f5c4b313c920f8f9ff22778b55/image1-41.png" />
            
            </figure><p>When Bob wants to retrieve 🐱, he tells his peers they want 🐱. These peers point him to Alice. Alice then provides 🐱 to Bob. Bob can verify 🐱 is the content they were looking for, because the content identifier he requested is derived from the 🐱 content itself, using a secure, cryptographic hash function.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6kYdWRivzzXiVbC9LsDWPf/9bdcb0ae5393a7c3551b7395ab5efd61/image3-28.png" />
            
            </figure><p>Even better, if Bob becomes a cat person, they can announce to their peers they are also providing a cat. Bob's love for cats could be genuine, or because they have interest in providing the content, such as a contract with Alice. IPFS provides a common ground to share content, without being opinionated on how this content has to be stored and its guarantees.</p>
    <div>
      <h2>How Pages websites are made available on IPFS</h2>
      <a href="#how-pages-websites-are-made-available-on-ipfs">
        
      </a>
    </div>
    <p>Content is made available as follows.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7y0PyVwr6OWWm4Ql8BDeZz/22401175f3cc9f85635a155ad1b4c78c/image2-37.png" />
            
            </figure><p>The components are:</p><ul><li><p>Pages storage: Storage solution for Cloudflare Pages.</p></li><li><p>IPFS Index Proxy: Service maintaining a map between IPFS CID and location of the data. This is operated on Cloudflare Workers and using Workers KV to store the mapping.</p></li><li><p>IPFS node: Cloudflare-hosted IPFS node serving Pages content. It has an in-house datastore module, able to communicate with the IPFS Index Proxy.</p></li><li><p>IPFS network: The rest of the IPFS network.</p></li></ul><p>When you opt in serving your Cloudflare Page on IPFS, a call is made to the IPFS index proxy. This call first fetches your Pages content, transforms it into a CID, then both populates IndexDB to associate the CID with the content and reaches out to Cloudflare IPFS node to tell them they are able to provide the CID.</p><p>For example, imagine your website structure is as follows:</p><ul><li><p>/</p><ul><li><p>index.html</p></li><li><p>static/</p><ul><li><p>cats.txt</p></li><li><p>beautiful_cats.txt</p></li></ul></li></ul></li></ul><p>To provide this website on IPFS, Cloudflare has to compute a CID for /. CIDs are built recursively. To compute the CID for a given folder /, one needs to have the CID of <code>index.html</code> and <code>static</code>/. <code>index.html</code> CID is derived from its binary representation, and static/ from cats.txt and beautiful_cats.txt.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7stjDpQPAhOugUqBcwRV8H/1bf1f181f61793fa0d6c1d1c2a860d77/image6-13.png" />
            
            </figure><p>This works similarly to a Merkle tree, except nodes can reference each other as long as they still form a Directed Acyclic Graph (DAG). This structure is therefore referred to as a <a href="https://docs.ipfs.io/concepts/merkle-dag/">MerkleDAG</a>.</p><p>In our example, it's not unlikely for <code>cats.txt</code> and <code>beautiful_cats.txt</code> to have data in common. In this case, Cloudflare can be smart in the way it builds the MerkleDAG.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6mqAMRlu7HoiESker0Tiur/49e0b2c53cdf847dc283391335408f15/image4-22.png" />
            
            </figure><p>This reduces the storage and bandwidth requirement when accessing the website on IPFS.</p><p><i>If you want to learn more about how you can model a file system on IPFS, you can check the</i> <a href="https://github.com/ipfs/specs/blob/master/UNIXFS.md"><i>UnixFS</i></a> <i>specification.</i></p><p>Cloudflare stores every CID and the content it references in IndexDB. This allows Cloudflare IPFS nodes to serve Cloudflare Pages assets when requested.</p>
    <div>
      <h2>Let's put this together</h2>
      <a href="#lets-put-this-together">
        
      </a>
    </div>
    <p>Let’s take an example: pages-on-ipfs.com is hosted on IPFS. It is built using Hugo, a static site generator, and Cloudflare Pages with the <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-hugo-site/">public documentation template</a>. Its source is available on <a href="https://github.com/thibmeu/pages-on-ipfs">GitHub</a>. If you have an IPFS compatible client, you can access it at ipns://pages-on-ipfs.com as well.</p><p>1. Read Cloudflare Pages deployment documentation</p><p>For the purpose of this blog, I want to create a simple Cloudflare page website. I have experience with Hugo, so I choose it as my framework for the project.</p><p>I type "<a href="https://lmddgtfy.net/?q=cloudflare%20pages">cloudflare pages</a>" in the search bar of my web browser, then head to the Read the docs &gt; Framework Guide &gt; <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-hugo-site/">Deploy a Hugo site</a>.</p><p>2. Create a site</p><p>This is where I use Hugo, and your configuration might differ. In short, I use hugo new site pages-on-ipfs, create an index and two static resources, et voilà. The result is available on the source <a href="https://github.com/thibmeu/pages-on-ipfs">GitHub</a> for this project.</p><p>3. Deploy using Cloudflare Pages</p><p>On the Cloudflare Dashboard, I go to Account Home &gt; Pages &gt; Create a project. I select the GitHub repository I created, and configure the build tool to build Hugo website. Basically, I follow what's written on <a href="https://developers.cloudflare.com/pages/framework-guides/deploy-a-hugo-site/#deploying-with-cloudflare-pages">Cloudflare Pages documentation</a>.</p><p>Upon clicking Save and Deploy, my website is deployed on pages-on-ipfs.pages.dev. I also configure it to be available at pages-on-ipfs.com</p><p>4. Serve my content on IPFS</p><p>First, I opt in my zone on Cloudflare Pages integration with IPFS. This feature is not available yet for everyone to try out.</p><p>This allows Cloudflare to index the content of my website. Once indexed, I get the CID for my deployment baf...1. I can check that my content is available at this hash on IPFS using an IPFS gateway <a href="https://bafybeig7hluox6xefqdgmwcntvsguxcziw2oeogg2fbvygex2aj6qcfo64.ipfs.cf-ipfs.com">https://baf...1.ipfs.cf-ipfs.com/</a>.</p><p>5. Make my IPFS website available at pages-on-ipfs.com</p><p>Having one domain name to access both Cloudflare Pages and IPFS version, depending on if the client supports IPFS or not is ideal. Fortunately, the IPFS ecosystem supports such a feature via DNSLink. DNSLink is a way to specify the IPFS content a domain is associated with.</p><p>For pages-on-ipfs.com, I create a TXT record on _dnslink.pages-on-ipfs.com with value dnslink=/ipfs/baf...1. Et voilà. I can now access ipns://pages-on-ipfs.com via an IPFS client.</p><p>6. (Optional) Replicate my website</p><p>The content of my website can now easily be replicated and <a href="https://docs.ipfs.io/how-to/pin-files/">pinned</a> by other IPFS nodes. This can either be done at home via an IPFS client or using a pinning service such as <a href="https://www.pinata.cloud/">Pinata</a>.</p>
    <div>
      <h2>What's next</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>We'll make this service available later this year as it is being refined. We are committed to make information move freely and help build a better Internet. Cloudflare Pages work of solving developer problems continues, as developers are now able to make their site accessible to more users.</p><p>Over the years, IPFS has been used by more and more people. While Cloudflare started by making IPFS content available to web users through an HTTP interface, we now think it's time to give back. Allowing Cloudflare assets to be served over a public distributed network extends developers and users capability on an open web.</p>
    <div>
      <h2>Common questions</h2>
      <a href="#common-questions">
        
      </a>
    </div>
    <ul><li><p>I am already hosting my website on IPFS. Can I pin it using Cloudflare?</p><ul><li><p>No. This project aims at serving <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">Cloudflare hosted content</a> via IPFS. We are still investigating how to best replicate and re-provide already-existing IPFS content via Cloudflare infrastructure.</p></li></ul></li><li><p>Does this make IPFS more centralized?</p><ul><li><p>No. Cloudflare does not have the authority to decide who can be a node operator nor what content they provide.</p></li></ul></li><li><p>Are there guarantees the content is going to be available?</p><ul><li><p>Yes. As long as you choose Cloudflare to host your website on IPFS, it will be available on IPFS. Should you move to another provider, it would be your responsibility to make sure the content remains available. IPFS allows for this transition to be smooth using a pinning service.</p></li></ul></li><li><p>Is IPFS private?</p><ul><li><p>It depends. Generally, no. IPFS is a p2p protocol. The nodes you peer with and request content from would know the content you are looking for. The privacy depends on the trust you have in your peers to not snoop on the data you request.</p></li></ul></li><li><p>Can users verify the integrity of my website?</p><ul><li><p>Yes. They need to access your website through an IPFS compatible client. Ideally, IPFS content integrity is turned into a web standard, similar to <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity">subresource integrity</a>.</p></li></ul></li></ul><p></p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Cloudflare Pages]]></category>
            <category><![CDATA[Distributed Web]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[IPFS]]></category>
            <guid isPermaLink="false">yHRMEOkly3EmYimxcRF3u</guid>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[Gaining visibility in IPFS systems]]></title>
            <link>https://blog.cloudflare.com/ipfs-measurements/</link>
            <pubDate>Mon, 16 May 2022 12:57:39 GMT</pubDate>
            <description><![CDATA[ We've developed the IPFS Gateway monitor, an observability tool that runs various IPFS scenarios on a given gateway endpoint.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>We have been operating an IPFS gateway for the last four years. It started as a <a href="/distributed-web-gateway/">research experiment in 2018</a>, providing <a href="/e2e-integrity/">end-to-end integrity with IPFS</a>. A year later, we made <a href="/continuing-to-improve-our-ipfs-gateway/">IPFS content faster to fetch</a>. Last year, we announced we were committed to <a href="/announcing-web3-gateways/">making IPFS gateway part of our product offering</a>. Through this process, we needed to inform our design decisions to know how our setup performed.</p><p>To this end, we've developed the IPFS Gateway monitor, an observability tool that runs various IPFS scenarios on a given gateway endpoint. In this post, you'll learn how we use this tool and go over discoveries we made along the way.</p>
    <div>
      <h2>Refresher on IPFS</h2>
      <a href="#refresher-on-ipfs">
        
      </a>
    </div>
    <p>IPFS is a distributed system for storing and accessing files, websites, applications, and data. It's different from a traditional centralized file system in that IPFS is completely distributed. Any participant can join and leave at any time without the loss of overall performance.</p><p>However, in order to access any file in IPFS, users cannot just use web browsers. They need to run an IPFS node to access the file from IPFS using its own protocol. IPFS Gateways play the role of enabling users to do this using only web browsers.</p><p>Cloudflare provides an IPFS gateway at <a href="https://cloudflare-ipfs.com">https://cloudflare-ipfs.com</a>, so anyone can just access IPFS files by using the gateway URL in their browsers.</p><p>As IPFS and the Cloudflare IPFS Gateway have become more and more popular, we need a way to know how performant it is: how much time it takes to retrieve IPFS-hosted content and how reliable it is. However, IPFS gateways are not like normal websites which only receive HTTP requests and return HTTP responses. The gateways need to run IPFS nodes internally and sometimes do content routing and peer routing to find the nodes which provide IPFS contents. They sometimes also need to resolve IPNS names to discover the contents. So, in order to measure the performance, we need to do measurements many times for many scenarios.</p>
    <div>
      <h2>Enter the IPFS Gateway monitor</h2>
      <a href="#enter-the-ipfs-gateway-monitor">
        
      </a>
    </div>
    <p><a href="https://github.com/cloudflare/ipfs-gateway-monitor">IPFS Gateway monitor</a> is this tool. It allows anyone to check the performance of their gateway and export it to the Prometheus monitoring system.</p><p>This monitor is composed of three independent binaries:</p><ol><li><p>ipfs-gw-measure is the tool that calls the gateway URL and does the measurement scenarios.</p></li><li><p>ipfs-gw-monitor is a way to call the measurement tool multiple times.</p></li><li><p>Prometheus Exporter exposes prometheus-readable metrics.</p></li></ol><p>To interact with the IPFS network, the codebase also provides a way to start an IPFS node.</p><p>A scenario is a set of instructions a user performs given the state of our IPFS system. For instance, we want to know how fast newly uploaded content can be found by the gateway, or if popular content has a low query time. We'll discuss more of this in the next section.</p><p>Putting this together, the system is the following.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7nUi5dEwj15NtiSduijehE/75a34120b8d85e155bd2c21c83c5e155/image4-20.png" />
            
            </figure><p>During this experience, we have operated both the IPFS Monitor, and a test IPFS node. The IPFS node allows the monitor to provide content to the IPFS network. This allows us to be sure that the content provided is fresh, and actually hosted. Peers have not been fixed, and leverage the IPFS default peer discovery mechanism.</p><p>Cloudflare IPFS Gateway is treated as an opaque system. The monitor performs end-to-end tests by contacting the gateway via its public API, either <a href="https://cloudflare-ipfs.com">https://cloudflare-ipfs.com</a> or via a custom domain registered with the gateway.</p><p>The following scenarios have been run on consumer hardware in March. They are not representative of all IPFS users. All values provided below have been sourced against Cloudflare’s IPFS gateway endpoint.</p>
    <div>
      <h3>First scenarios: Gateway to serve immutable IPFS contents</h3>
      <a href="#first-scenarios-gateway-to-serve-immutable-ipfs-contents">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/qrn6V5qZnqdJzL5V1qzFl/c9bf76a05f738831ba8737918b062e79/image3-26.png" />
            
            </figure><p>IPFS contents are the most primitive contents being served by the IPFS network and IPFS gateways. By their nature, they are immutable and addressable only by the hash of the content. Users can access the IPFS contents by putting the Content IDentifier (CID) in the URL path of the gateway. For example, <a href="https://cloudflare-ipfs.com/ipfs/bafybeig7hluox6xefqdgmwcntvsguxcziw2oeogg2fbvygex2aj6qcfo64">ipfs://bafybeig7hluox6xefqdgmwcntvsguxcziw2oeogg2fbvygex2aj6qcfo64</a>. We measure three common scenarios that users will often encounter.</p><p>The first one is when users fetch popular content which has a high probability of being found in our cache already. During our experiment, we measured a response time for such content is around 116ms.</p><p>The second one is the case where the users create and upload the content to the IPFS network, such as via the integration between <a href="/cloudflare-pages-on-ipfs/">Cloudflare Pages and IPFS</a>. This scenario is a lot slower than the first because the content is not in our cache yet, and it takes some time to discover the content. The content that we upload during this measurement is a random piece of 32-byte content.</p><p>The last measurement is when users try to download content that does not exist. This one is the slowest. Because of the nature of content routing of IPFS, there is no indication that tells us that content doesn't exist. So, setting the timeout is the only way to tell if the content exists or not. Currently, the Cloudflare IPFS gateway has a timeout of around five minutes.</p><table><tr><td><p><b></b></p></td><td><p><b>Scenario</b></p></td><td><p><b>Min (s)</b></p></td><td><p><b>Max (s)</b></p></td><td><p><b>Avg (s)</b></p></td></tr><tr><td><p>1</p></td><td><p>ipfs/newly-created-content</p></td><td><p>0.276</p></td><td><p>343</p></td><td><p>44.4</p></td></tr><tr><td><p>2</p></td><td><p>ipfs/in-cache-content</p></td><td><p>0.0825</p></td><td><p>0.539</p></td><td><p>0.116</p></td></tr><tr><td><p>3</p></td><td><p>ipfs/unavailable-cid</p></td><td><p>90</p></td><td><p>341</p></td><td><p>279</p></td></tr></table>
    <div>
      <h3>Second scenarios: Gateway to serve mutable IPNS named contents</h3>
      <a href="#second-scenarios-gateway-to-serve-mutable-ipns-named-contents">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/8qZ6yQPbI8x5Y3iMrkKbh/9b74a004d5c414ecd0dfa09126179bc6/image1-40.png" />
            
            </figure><p>Since IPFS contents are immutable, when users want to change the content, the only way to do so is to create new content and distribute the new CID to other users. Sometimes distributing the new CID is hard, and is out of scope of IPFS. The InterPlanetary Naming System (IPNS) tries to solve this. IPNS is a naming system that — instead of locating the content using the CID — allows users to locate the content using the IPNS name instead. This name is a hash of a user's public key. Internally, IPNS maintains a section of the IPFS DHT which maps from a name to a CID. Therefore, when the users want to download the contents using names through the gateway, the gateway has to first resolve the name to get the CID, then use the CID to query the IPFS content as usual.</p><p>The example for fetching the IPNS named content is at ipns://k51qzi5uqu5diu2krtwp4jbt9u824cid3a4gbdybhgoekmcz4zhd5ivntan5ey</p><p>We measured many scenarios for IPNS as shown in the table below. Three scenarios are similar to the ones involving IPFS contents. There are two more scenarios added: the first one is measuring the response time when users query the gateway using an existing IPNS name, and the second one is measuring the response time when users query the gateway immediately after new content is published under the name.</p><table><tr><td><p></p></td><td><p><b>Scenarios</b></p></td><td><p><b>Min (s)</b></p></td><td><p><b>Max (s)</b></p></td><td><p><b>Avg (s)</b></p></td></tr><tr><td><p>1</p></td><td><p>ipns/newly-created-name</p></td><td><p>5.50</p></td><td><p>110</p></td><td><p>33.7</p></td></tr><tr><td><p>2</p></td><td><p>ipns/existing-name</p></td><td><p>7.19</p></td><td><p>113</p></td><td><p>28.0</p></td></tr><tr><td><p>3</p></td><td><p>ipns/republished-name</p></td><td><p>5.62</p></td><td><p>80.4</p></td><td><p>43.8</p></td></tr><tr><td><p>4</p></td><td><p>ipns/in-cache-content</p></td><td><p>0.0353</p></td><td><p>0.0886</p></td><td><p>0.0503</p></td></tr><tr><td><p>5</p></td><td><p>ipns/unavailable-name</p></td><td><p>60.0</p></td><td><p>146</p></td><td><p>81.0</p></td></tr></table>
    <div>
      <h3>Third scenarios: Gateway to serve DNSLink websites</h3>
      <a href="#third-scenarios-gateway-to-serve-dnslink-websites">
        
      </a>
    </div>
    <p>Even though users can use IPNS to provide others a stable address to fetch the content, the address can still be hard to remember. This is what DNSLink is for. Users can address their content using DNSLink, which is just a normal <a href="https://www.cloudflare.com/learning/dns/glossary/what-is-a-domain-name/">domain name</a> in the Domain Name System (DNS). As a domain owner, you only have to create a TXT record with the value dnslink=/ipfs/baf…1, and your domain can be fetched from a gateway.</p><p>There are two ways to access the DNSLink websites using the gateway. The first way is to access the website using the domain name as a URL hostname, for example, <a href="https://ipfs.example.com">https://ipfs.example.com</a>. The second way is to put the domain name as a URL path, for example, <a href="https://cloudflare-ipfs.com/ipns/ipfs.example.com">https://cloudflare-ipfs.com/ipns/ipfs.example.com</a>.</p><table><tr><td><p></p></td><td><p><b>Scenarios</b></p></td><td><p><b>Min (s)</b></p></td><td><p><b>Max (s)</b></p></td><td><p><b>Avg (s)</b></p></td></tr><tr><td><p>1</p></td><td><p>dnslink/ipfs-domain-as-url-hostname</p></td><td><p>0.251</p></td><td><p>18.6</p></td><td><p>0.831</p></td></tr><tr><td><p>2</p></td><td><p>dnslink/ipfs-domain-as-url-path</p></td><td><p>0.148</p></td><td><p>1.70</p></td><td><p>0.346</p></td></tr><tr><td><p>3</p></td><td><p>dnslink/ipns-domain-as-url-hostname</p></td><td><p>7.87</p></td><td><p>44.2</p></td><td><p>21.0</p></td></tr><tr><td><p>4</p></td><td><p>dnslink/ipns-domain-as-url-path</p></td><td><p>6.87</p></td><td><p>72.6</p></td><td><p>19.0</p></td></tr></table>
    <div>
      <h2>What does this mean for regular IPFS users?</h2>
      <a href="#what-does-this-mean-for-regular-ipfs-users">
        
      </a>
    </div>
    <p>These measurements highlight that IPFS content is fetched best when cached. This is an order of magnitude faster than fetching new content. This result is expected as content publication on IPFS can take time for nodes to retrieve, as highlighted in <a href="https://youtu.be/yylsaXz00_g?t=823">previous studies</a>. Then, when it comes to naming IPFS resources, leveraging DNSLink appears to be the faster strategy. This is likely due to the poor connection of the IPFS node used in this setup, preventing IPNS name from propagating rapidly. Overall, IPNS names would benefit from using a resolver to speed up resolution without losing the trust they provide.</p><p>As we mentioned in September, IPFS use has seen important growth. So has our tooling. The IPFS Gateway monitor can be found on <a href="https://github.com/cloudflare/ipfs-gateway-monitor">GitHub</a>, and we will keep looking at improving this first set of metrics.</p><p>At the time of writing, using IPFS via a gateway seems to provide lower retrieval times, while allowing for finer grain control over security settings in the browser context. This configuration preserves the content validity properties offered by IPFS, but reduces the number of nodes a user is peering with to one: the gateway. Ideally, we would like users to peer with Cloudflare because we're offering the best service, while still having the possibility to retrieve content from external sources if they want to. We'll be conducting more measurements to better understand how to best leverage Cloudflare presence in 270 cities to better serve the IPFS network.</p> ]]></content:encoded>
            <category><![CDATA[Platform Week]]></category>
            <category><![CDATA[Distributed Web]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[IPFS]]></category>
            <guid isPermaLink="false">4jdX3TTEDdxnin4XGswBv1</guid>
            <dc:creator>Pop Chunhapanya</dc:creator>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[Web3 — A vision for a decentralized web]]></title>
            <link>https://blog.cloudflare.com/what-is-web3/</link>
            <pubDate>Fri, 01 Oct 2021 12:59:31 GMT</pubDate>
            <description><![CDATA[ In this blog we start to explain Web3 in the context of the web's evolution, and how Cloudflare might help to support it. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3k6VIEkUCQIjvEUmgilCba/039389ac2ae80961acc14f6b359533f9/image1-1.png" />
            
            </figure><p>By reading this, you are a participant of the web. It's amazing that we can write this blog and have it appear to you without operating a server or writing a line of code. In general, the web of today empowers us to participate more than we could at any point in the past.</p><p>Last year, <a href="/internet-privacy/">we mentioned</a> the next phase of the Internet would be always on, always secure, always private. Today, we dig into a similar trend for the web, referred to as Web3. In this blog we'll start to explain Web3 in the context of the web's evolution, and how Cloudflare might help to support it.</p>
    <div>
      <h3>Going from Web 1.0 to Web 2.0</h3>
      <a href="#going-from-web-1-0-to-web-2-0">
        
      </a>
    </div>
    <p>When <a href="https://webfoundation.org/about/vision/history-of-the-web/">Sir Tim Berners-Lee</a> wrote his seminal 1989 document “<a href="https://www.w3.org/History/1989/proposal.html">Information Management: A Proposal</a>”, he outlined a vision of the “web” as a network of information systems interconnected via hypertext links. It is often assimilated to the Internet, which is the computer network it operates on. Key practical requirements for this web included being able to access the network in a decentralized manner through remote machines and allowing systems to be linked together without requiring any central control or coordination.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1XimrXMTgt5iEuXbsJreOz/8d6427517dada20a3a3cd8d462acb9b9/image4-3.png" />
            
            </figure><p>The original proposal for what we know as the web, fitting in one diagram - Source: <a href="https://www.w3.org/History/1989/proposal.html">w3</a></p><p>This vision materialized into an initial version of the web that was composed of interconnected <b>static</b> resources delivered via a distributed network of servers and accessed primarily on a read-only basis from the client side — “Web 1.0”. Usage of the web soared with the number of websites growing well over 1,000% in the ~2 years following the introduction of the Mosaic graphical browser in 1993, based on data from the <a href="https://www.mit.edu/people/mkgray/growth/">World Wide Web Wanderer</a>.</p><p>The early 2000s marked an inflection point in the growth of the web and a key period of its development, as technology companies that survived the dot-com crash evolved to deliver value to customers in new ways amidst heightened skepticism around the web:</p><ul><li><p>Desktop browsers like Netscape became commoditized and paved the way for native web services for discovering content like search engines.</p></li><li><p>Network effects that were initially driven by hyperlinks in web directories like Yahoo! were hyperscaled by platforms that enabled user engagement and harnessed collective intelligence like review sites.</p></li><li><p>The massive volume of data generated by Internet activity and the growing realization of its competitive value forced companies to become experts at database management.</p></li></ul><p>O’Reilly Media coined the concept of <a href="https://www.oreilly.com/pub/a/web2/archive/what-is-web-20.html?page=1">Web 2.0</a> in an attempt to capture such shifts in design principles, which were transformative to the usability and <b>interactiveness</b> of the web and continue to be core building blocks for Internet companies nearly two decades later.</p><p>However, in the midst of the web 2.0 transformation, the web fell out of touch with one of its initial core tenets — decentralization.</p><blockquote><p><i>Decentralization: No permission is needed from a central authority to post anything on the web, there is no central controlling node, and so no single point of failure … and no “kill switch”!— History of the web by</i> <a href="https://webfoundation.org/about/vision/history-of-the-web/"><i>Web Foundation</i></a></p></blockquote>
    <div>
      <h3>A new paradigm for the Internet</h3>
      <a href="#a-new-paradigm-for-the-internet">
        
      </a>
    </div>
    <p>This is where Web3 comes in. The last two decades have proven that building a scalable system that decentralizes content is a challenge. While the technology to build such systems exists, no content platform achieves decentralization at scale.</p><p>There is one notable exception: Bitcoin. Bitcoin was conceptualized in a 2008 <a href="https://bitcoin.org/bitcoin.pdf">whitepaper</a> by <a href="https://en.wikipedia.org/wiki/Satoshi_Nakamoto">Satoshi Nakamoto</a> as a type of distributed ledger known as a blockchain designed so that a peer-to-peer (P2P) network could transact in a public, consistent, and tamper-proof manner.</p><p>That’s a lot said in one sentence. Let’s break it down by term:</p><ul><li><p>A peer-to-peer network is a network architecture. It consists of a set of computers, called nodes, that store and relay information. Each node is equally privileged, preventing one node from becoming a single point of failure. In the Bitcoin case, nodes can send, receive, and process Bitcoin transactions.</p></li><li><p>A ledger is a collection of accounts in which transactions are recorded. For Bitcoin, the ledger records Bitcoin transactions.</p></li><li><p>A distributed ledger is a ledger that is shared and synchronized among multiple computers. This happens through a consensus, so each computer holds a similar replica of the ledger. With Bitcoin, the consensus process is performed over a P2P network, the Bitcoin network.</p></li><li><p>A blockchain is a type of distributed ledger that stores data in “blocks” that are cryptographically linked together into an immutable chain that preserves their chronological order. Bitcoin leverages blockchain technology to establish a shared, single source of truth of transactions and the sequence in which they occurred, thereby mitigating the <a href="https://en.wikipedia.org/wiki/Double-spending">double-spending problem</a>.</p></li></ul><p>Bitcoin — which currently has <a href="https://luke.dashjr.org/programs/bitcoin/files/charts/software.html">over 40,000 nodes</a> in its network and processes <a href="https://coinmarketcap.com/currencies/bitcoin/">over $30B in transactions</a> each day — demonstrates that an application can be run in a distributed manner at scale, without compromising security. It inspired the development of other blockchain projects such as Ethereum which, in addition to transactions, allows participants to deploy code that can verifiably run on each of its nodes.</p><p>Today, these programmable blockchains are seen as <a href="https://www.coindesk.com/web3-transform-the-web">ideal open and trustless platforms</a> to serve as the infrastructure of a distributed Internet. They are home to a rich and growing ecosystem of <a href="https://dappradar.com/rankings">nearly 7,000 decentralized applications</a> (“Dapps”) that do not rely on any single entity to be available. This provides them with greater flexibility on how to best serve their users in all jurisdictions.</p>
    <div>
      <h3>The web is for the end user</h3>
      <a href="#the-web-is-for-the-end-user">
        
      </a>
    </div>
    <p>Distributed systems are inherently different from centralized systems. They should not be thought about in the same way. Distributed systems enable the data and its processing to not be held by a single party. This is useful for companies to provide resilience, but it’s also useful for P2P-based networks where data can stay in the hands of the participants.</p><p>For instance, if you were to host a blog the old-fashioned way, you would put up a server, expose it to the Internet (via <a href="/dyi-web-server-raspberry-pi-cloudflare/">Cloudflare :D</a>), <i>et voilà</i>. Nowadays, your blog would be hosted on a platform like WordPress, Ghost, Notion, or even Twitter. If these companies were to have an outage, this affects a lot more people. In a distributed fashion, via IPFS for instance, your blog content can be <a href="https://www.cloudflare.com/developer-platform/solutions/hosting/">hosted</a> and served from multiple locations operated by different entities.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Eu8UmmUj6bkyAw4o4U8vM/bc7a2d1e14e089c96b8e2ba23d744fdd/image5-2.png" />
            
            </figure><p>Web 1.0</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2NW1nw9JDPAFBcqoJ6fQpy/b17c7a09c6c022492725a5ce4ad03725/image2-2.png" />
            
            </figure><p>Web 2.0</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1STcnM6O3g2IGbIoIxMMyC/5fa32e4b4a59d146edf9071a662aa512/image3-1.png" />
            
            </figure><p>Web3</p><p>Each participant in the network can choose what they host/provide and can be home to different content. Similar to your home network, you are in control of what you share, and you don’t share everything.</p><p>This is a core tenet of decentralized identity. The same cryptographic principles underpinning cryptocurrencies like Bitcoin and Ethereum are being leveraged by applications to provide secure, cross-platform identity services. This is fundamentally different from other authentication systems such as OAuth 2.0, where a trusted party has to be reached to assess one's identity. This materializes in the form of “Login with ” buttons. These cloud providers are the only ones with enough data, resources, and technical expertise.</p><p>In a decentralised web, each participant holds a secret key. They can then use it to identify each other. You can learn about this cryptographic system in a <a href="/introducing-cryptographic-attestation-of-personhood/#the-technical-explanation">previous blog</a>. In a Web3 setting where web participants own their data, they can selectively share these data with applications they interact with. Participants can also leverage this system to prove interactions they had with one another. For example, if a college issues you a <a href="https://www.w3.org/TR/did-core/">Decentralized Identifier</a> (DID), you can later prove you have been registered at this college without reaching out to the college again. Decentralized Identities can also serve as a placeholder for a public profile, where participants agree to use a blockchain as a source of trust. This is what projects such as ENS or Unlock aim to provide: a way to verify your identity online based on your control over a public key.</p><p>This trend of proving ownership via a shared source of trust is key to the NFT craze. We have <a href="/cloudflare-stream-now-supports-nfts/">discussed NFTs</a> before on this blog. Blockchain-based NFTs are a medium of conveying ownership. Blockchain enables this information to be publicly verified and updated. If the blockchain states a public key I control is the owner of an NFT, I can refer to it on other platforms to prove ownership of it. For instance, if my profile picture on social media is a cat, I can prove the said cat is associated with my public key. What this means depends on what I want to prove, especially with the proliferation of NFT contracts. If you want to understand how an NFT contract works, you can <a href="https://blog.mycrypto.com/so-you-wanna-build-your-own-pfp-nft-project/">build your own</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3xVWfY7VlFkOM2cuYhef8b/2c0467e47fb32ff4c582e44f1f681a41/image6-1.png" />
            
            </figure>
    <div>
      <h3>How does Cloudflare fit in Web3?</h3>
      <a href="#how-does-cloudflare-fit-in-web3">
        
      </a>
    </div>
    <p>Decentralization and privacy are challenges we are tackling at Cloudflare as part of our mission to help build a better Internet.</p><p>In a <a href="/next-generation-privacy-protocols/">previous post</a>, Nick Sullivan described Cloudflare’s contributions to enabling privacy on the web. We launched initiatives to fix information leaks in HTTPS through <a href="/encrypted-client-hello">Encrypted Client Hello (ECH)</a>, make DNS even more private by supporting <a href="/oblivious-dns">Oblivious DNS-over-HTTPS (ODoH)</a>, and develop <a href="/opaque-oblivious-passwords">OPAQUE</a> which makes password breaches less likely to occur. We have also released our <a href="/introducing-the-cloudflare-data-localization-suite/">data localization suite</a> to help businesses navigate the ever evolving <a href="/data-privacy-day-2021-looking-ahead-at-the-always-on-always-secure-always-private-internet/">regulatory landscape</a> by giving them control over where their data is stored without compromising performance and security. We’ve even built a <a href="/introducing-zero-knowledge-proofs-for-private-web-attestation-with-cross-multi-vendor-hardware/">privacy-preserving attestation</a> that is based on the same zero-knowledge proof techniques that are core to distributed systems such as <a href="https://electriccoin.co/blog/explaining-halo-2/">ZCash</a> and <a href="https://filecoin.io/blog/posts/filecoin-zk-snarks-zero-knowledge-but-a-lot-of-zero-knowledge/">Filecoin</a>.</p><p>It’s exciting to think that there are already ways we can change the web to improve the experience for its users. However, there are some limitations to build on top of the exciting infrastructure. This is why projects such as Ethereum and IPFS build on their own architecture. They are still relying on the Internet but do not operate with the web as we know it. To ease the transition, Cloudflare operates <a href="https://www.cloudflare.com/distributed-web-gateway/">distributed web gateways</a>. These gateways provide an HTTP interface to Web3 protocols: Ethereum and IPFS. Since HTTP is core to the web we know today, distributed content can be accessed securely and easily without requiring the user to operate experimental software.</p>
    <div>
      <h3>Where do we go next?</h3>
      <a href="#where-do-we-go-next">
        
      </a>
    </div>
    <p>The journey to a different web is long but exciting. The infrastructure built over the last two decades is truly stunning. The Internet and the web are now part of 4.6 billion people's lives. At the same time, the top 35 websites had <a href="https://www.ncta.com/whats-new/the-expanding-consolidation-of-the-consumer-internet-3">more visits</a> than all others (circa 2014). Users have less control over their data and are even more reliant on a few players.</p><p>The early Web was static. Then Web 2.0 came to provide interactiveness and service we use daily at the cost of centralisation. Web3 is a trend that tries to challenge this. With distributed networks built on open protocols, users of the web are empowered to participate.</p><p>At Cloudflare, we are embracing this distributed future. Applying the knowledge and experience we have gained from running one of the largest edge networks, we are making it easier for users and businesses to benefit from Web3. This includes operating a <a href="/announcing-web3-gateways">distributed web product suite</a>, contributing to <a href="/cloudflares-approach-to-research/">open standards</a>, and <a href="/internet-privacy/">moving privacy forward</a>.</p><p>If you would like to help build a better web with us, we are <a href="https://www.cloudflare.com/careers/jobs/">hiring</a>.</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Distributed Web]]></category>
            <category><![CDATA[Privacy]]></category>
            <guid isPermaLink="false">5YXVZmOkyscnB5e0JOZAY5</guid>
            <dc:creator>Thibault Meunier</dc:creator>
            <dc:creator>In-Young Jo</dc:creator>
        </item>
        <item>
            <title><![CDATA[How Cloudflare provides tools to help keep IPFS users safe]]></title>
            <link>https://blog.cloudflare.com/cloudflare-ipfs-safe-mode/</link>
            <pubDate>Wed, 29 Sep 2021 23:02:00 GMT</pubDate>
            <description><![CDATA[ The Cloudflare IPFS module protects users from threats like phishing and ransomware. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Cloudflare's journey with IPFS started in 2018 when we announced a <a href="/distributed-web-gateway/">public gateway for the distributed web</a>. Since then, the number of infrastructure providers for the InterPlanetary FileSystem (IPFS) has grown and matured substantially. This is a huge benefit for users and application developers as they have the ability to choose their infrastructure providers.</p><p>Today, we’re excited to announce new secure filtering capabilities in IPFS. The Cloudflare IPFS module is a tool to protect users from threats like phishing and ransomware. We believe that other participants in the network should have the same ability. We are releasing that software as open source, for the benefit of the entire community.</p><p>Its code is available on <a href="https://github.com/cloudflare/go-ipfs/tree/v0.9.1-safemode">github.com/cloudflare/go-ipfs</a>. To understand how we built it and how to use it, read on.</p>
    <div>
      <h3>A brief introduction on IPFS content retrieval</h3>
      <a href="#a-brief-introduction-on-ipfs-content-retrieval">
        
      </a>
    </div>
    <p>Before we get to understand how IPFS filtering works, we need to dive a little deeper into the operation of an IPFS node.</p><p>The InterPlanetary FileSystem (IPFS) is a peer-to-peer network for storing content on a distributed file system. It is composed of a set of computers called nodes that store and relay content using a common addressing system.</p><p>Nodes communicate with each other over the Internet using a Peer-to-Peer (P2P) architecture, preventing one node from becoming a single point of failure. This is even more true given that anyone can operate a node with limited resources. This can be light hardware such as a Raspberry Pi, a server at a cloud provider, or even your web browser.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7D6yuQR7r8BmcBPQS6YSjk/02c4a5bb7a86be4cebdc52bd54ae532f/image2-4.png" />
            
            </figure><p>This creates a challenge since not all nodes may support the same protocols, and networks may block some types of connections. For instance, your web browser does not expose a TCP API and your home router likely doesn’t allow inbound connections. This is where <a href="https://libp2p.io/">libp2p</a> comes to help.</p><p>libp2p is a modular system of <i>protocols</i>, <i>specifications</i>, and <i>libraries</i> that enable the development of peer-to-peer network applications - <a href="https://docs.libp2p.io/introduction/what-is-libp2p/">libp2p documentation</a></p><p>That’s exactly what four IPFS nodes need to connect to the IPFS network. From a node point of view, the architecture is the following:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KWwoCkKQL46RFHelilMtE/a5718f571f330746fc421f49a20cc76f/image6-2.png" />
            
            </figure><p>Any node that we maintain a connection with is a peer. A peer that does not have ? content can ask their peers, including you, they WANT?. If you do have it, you will provide the ? to them. If you don’t have it, you can give them information about the network to help them find someone who might have it. As each node chooses the resources they store, it means some might be stored on a limited number of nodes.</p><p>For instance, everyone likes ?, so many nodes will dedicate resources to store it. However, ? is less popular. Therefore, only a few nodes will provide it.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6lZKi9WAAYORStwkYGTnD1/88b6e06f42bf6d5ac7585ddd3d337874/image3-3.png" />
            
            </figure><p>This assumption does not hold for public gateways like Cloudflare. A gateway is an HTTP interface to an IPFS node. On our gateway, we allow a user of the Internet to retrieve arbitrary content from IPFS. If a user asks for ?, we provide ?. If they ask for ?, we’ll find ? for them.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7Aj6yGIAk8iAzBoMZAuayV/025e8fe16774f5fe81abffa46c519ed4/image1-6.png" />
            
            </figure><p>Cloudflare’s IPFS gateway is simply a cache in front of IPFS. Cloudflare does not have the ability to modify or remove content from the IPFS network. However, IPFS is a decentralized and open network, so there is the possibility of users sharing threats like phishing or malware. This is content we do not want to provide to the P2P network or to our HTTP users.</p><p>In the next section, we describe how an IPFS node can protect its users from such threats.</p><p><i>If you would like to learn more about the inner workings of libp2p, you can go to</i> <a href="https://proto.school/introduction-to-libp2p"><i>ProtoSchool</i></a> <i>which has a great tutorial about it.</i></p>
    <div>
      <h3>How IPFS filtering works</h3>
      <a href="#how-ipfs-filtering-works">
        
      </a>
    </div>
    <p>As we described earlier, an IPFS node provides content in two ways: to its peers through the IPFS P2P network and to its users via an HTTP gateway.</p><p>Filtering content of the HTTP interface is no different from the current protection Cloudflare already has in place. If ? is considered malicious and is available at cloudflare-ipfs.com/ipfs/?, we can filter these requests, so the end user is kept safe.</p><p>The P2P layer is different. We cannot filter URLs because that’s not how the content is requested. IPFS is content-addressed. This means that instead of asking for a specific location such as cloudflare-ipfs.com/ipfs/?, peers request the content directly using its Content IDentifiers (CID), ?.</p><p>More precisely, ? is an abstraction of the content address. A CID looks like QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy (QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy happens to be the hash of a .txt file containing the string "I’m trying out IPFS''). CID is a convenient way to refer to content in a cryptographically verifiable manner.</p><p>This is great, because it means that when peers ask for malicious ? content, we can prevent our node from serving it. This includes both the P2P layer and the HTTP gateway.</p><p>In addition, the working of IPFS makes it, so content can easily be reused. On directories for instance, the address is a CID based on the CID of its files. This way, a file can be shared across multiple directories, and still be referred to by the same CID. It allows IPFS nodes to efficiently store content without duplicating it. This can be used to share <a href="https://blog.ipfs.io/2020-02-14-improved-bitswap-for-container-distribution/">docker container layers</a> for example.</p><p>In the filtering use case, it means that if ? content is included in other IPFS content, our node can also prevent content linking to malicious ? content from being served. This results in ?, a mix of valid and malicious content.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/CDrcC6XQcEbIs3DcdkA49/c12890df760859ad3f2ea2129bfc090a/image5-3.png" />
            
            </figure><p>This cryptographic method of linking content together is known as MerkleDAG. You can learn more about it on <a href="https://proto.school/merkle-dags">ProtoSchool</a>, and Consensys did an article explaining the <a href="https://media.consensys.net/ever-wonder-how-merkle-trees-work-c2f8b7100ed3">basic cryptographic construction with bananas</a> ?.</p>
    <div>
      <h3>How to use IPFS secure filtering</h3>
      <a href="#how-to-use-ipfs-secure-filtering">
        
      </a>
    </div>
    <p>By now, you should have an understanding of how an IPFS node retrieves and provides content, as well as how we can protect peers and users from shared nodes accessing threats. Using this knowledge, Cloudflare went on to implement IPFS Safemode, a node protection layer on top of <a href="https://github.com/ipfs/go-ipfs">go-ipfs</a>. It is up to every node operator to build their own list of threats to be blocked based on their policy.</p><p>To use it, we are going to follow the instructions available on <a href="https://github.com/cloudflare/go-ipfs/tree/v0.9.1-safemode#build-from-source">cloudflare/go-ipfs repository</a>.</p><p>First, you need to clone the git repository</p>
            <pre><code>git clone https://github.com/cloudflare/go-ipfs.git
cd go-ipfs/</code></pre>
            <p>Then, you have to check out the commit where IPFS safemode is implemented. This version is based on v0.9.1 of go-ipfs.</p>
            <pre><code>git checkout v0.9.1-safemode</code></pre>
            <p>Now that you have the source code on your machine, we need to <a href="https://github.com/cloudflare/go-ipfs/tree/v0.9.1-safemode#build-from-source">build the IPFS client from source</a>.</p>
            <pre><code>make build</code></pre>
            <p><i>Et voilà</i>. You are ready to use your IPFS node, with safemode capabilities.</p>
            <pre><code># alias ipfs command to make it easier to use
alias ipfs=’./cmd/ipfs/ipfs’
# run an ipfs daemon
ipfs daemon &amp;
# understand how to use IPFS safemode
ipfs safemode --help
USAGE
ipfs safemode - Interact with IPFS Safemode to prevent certain CIDs from being provided.
...</code></pre>
            
    <div>
      <h3>Going further</h3>
      <a href="#going-further">
        
      </a>
    </div>
    <p>IPFS nodes are running in a diverse set of environments and operated by parties at various scales. The same software has to accommodate configuration in which it is accessed by a single-user, and others where it is shared by thousands of participants.</p><p>At Cloudflare, we believe that decentralization is going to be the next major step for content networks, but there is still work to be done to get these technologies in the hands of everyone. Content filtering is part of this story. If the community aims at embedding a P2P node in every computer, there needs to be ways to prevent nodes from serving harmful content. Users need to be able to give consent on the content they are willing to serve, and the one they aren’t.</p><p>By providing an IPFS safemode tool, we hope to make this protection more widely available.</p> ]]></content:encoded>
            <category><![CDATA[Birthday Week]]></category>
            <category><![CDATA[IPFS]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Distributed Web]]></category>
            <guid isPermaLink="false">2Rfcw9nEZ4DUBHIp1OOLXm</guid>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[Humanity wastes about 500 years per day on CAPTCHAs. It’s time to end this madness]]></title>
            <link>https://blog.cloudflare.com/introducing-cryptographic-attestation-of-personhood/</link>
            <pubDate>Thu, 13 May 2021 13:00:00 GMT</pubDate>
            <description><![CDATA[ We want to remove CAPTCHAs completely. The idea is rather simple: a real human should be able to touch or look at their device to prove they are human, without revealing their identity. Let's explore! ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Select all the buses. Click on bikes. Does this photo have traffic lights? As ridiculous as these questions are, you’re almost guaranteed to have seen one recently. They are a way for online services to separate humans from bots, and they’re called <a href="https://en.wikipedia.org/wiki/CAPTCHA">CAPTCHAs</a>. CAPTCHAs strengthen the security of online services. But while they do that, there’s a very real cost associated with them.</p><p>Based on our data, it takes a user on average 32 seconds to complete a CAPTCHA challenge. There are 4.6 billion global Internet users. We assume a typical Internet user sees approximately one CAPTCHA every 10 days.</p><p>This very simple back of the envelope math equates to somewhere in the order of 500 human years wasted every single day — just for us to prove our humanity.</p><p>Today, we are launching an experiment to end this madness. We want to get rid of CAPTCHAs completely. The idea is rather simple: a real human should be able to touch or look at their device to prove they are human, without revealing their identity. We want you to be able to prove that you are human without revealing which human you are! You may ask if this is even possible? And the answer is: Yes! We’re starting with trusted USB keys (like <a href="https://www.yubico.com/">YubiKey</a>) that have been around for a while, but increasingly phones and computers come equipped with this ability by default.</p><p>Today marks the beginning of the end for fire hydrants, cross walks, and traffic lights on the Internet.</p>
    <div>
      <h2>Why CAPTCHAs?</h2>
      <a href="#why-captchas">
        
      </a>
    </div>
    <p>In many instances, businesses need a way to tell whether an online user is human or not. Typically, those reasons relate to security, or abuse of an online service. Back at the turn of the century, CAPTCHAs were created to do just that. The first one <a href="https://en.wikipedia.org/wiki/CAPTCHA#:~:text=The%20term%20was%20coined%20in,two%20groups%20working%20in%20parallel.">was developed back in 1997</a>, and the term ("Completely Automated Public Turing test to tell Computers and Humans Apart") was coined in 2003 by Luis von Ahn, Manuel Blum, Nicholas J. Hopper, and John Langford.</p><p>By their very nature, the challenge-response nature of CAPTCHAs have to be automated: so they can scale across both humans and the bots they need to catch.</p>
    <div>
      <h2>Why get rid of CAPTCHAs?</h2>
      <a href="#why-get-rid-of-captchas">
        
      </a>
    </div>
    <p>Put simply: we all hate them.</p><p>The best we’ve been able to do to date has been to minimize them. For example, at Cloudflare, we’ve continuously <a href="/cloudflare-bot-management-machine-learning-and-more/">improved our Bot management solution</a> to get as smart as possible about when to serve a CAPTCHA to the user. However, over the years the web moved from simple CAPTCHAs based on text recognition against backgrounds to OCRing old books to identifying objects from pictures as <a href="https://www.cloudflare.com/learning/ai/what-is-artificial-intelligence/">AI</a> has improved (see <a href="https://arxiv.org/abs/1312.6082">Google paper on Street Numbers</a>). This creates some real problems for the human users of the Internet:</p><ol><li><p>Productivity: Time is lost — as is focus on the task at hand — and often in exchange for some frustration.</p></li><li><p>Accessibility: Users are assumed to have the physical and cognitive capabilities required to solve the tests, which may not be the case. A visual disability, for example, may make it impossible to perform a CAPTCHA-solving task.</p></li><li><p>Cultural Knowledge: The people on the planet who have seen a US fire hydrant are in the minority, as are the number who speak English. Cabs are yellow in New York City, and black in London — heck, ‘cabs’ are only cabs in a few places, and ‘taxis’ everywhere else!</p></li><li><p>Interactions on Mobile Devices: Phones and mobile devices are the primary — and most often only — means of Internet access for a large part of the world. CAPTCHAs put a strain on their data plans and battery usage, in addition to being more difficult on small screens.</p></li></ol><p>In fact, the World Wide Web Consortium (W3C) worked on multiple drafts — as early as 2003 — pointing out the <a href="https://www.w3.org/TR/turingtest/">inaccessibility of CAPTCHAs</a>.</p><p><i>And this is just from the user side</i>. Inflicting all these costs on users has very real costs for businesses, too. There’s a reason why businesses spend so much time optimizing the performance and layout of their websites and applications. That work stops users from bouncing when you want them to register. It stops shopping carts getting abandoned when you want them to end in the checkout. In general, you want to stop customers from getting frustrated and simply not come back.</p><p>CAPTCHAs are effectively businesses putting friction in front of their users, and as anyone who has managed a high performing online business will tell you, it’s not something you want to do unless you have no choice.</p><p>We started tackling these issues when we <a href="/moving-from-recaptcha-to-hcaptcha/">moved from Google reCAPTCHA to hCAPTCHA</a>. Today, we are going further.</p>
    <div>
      <h2>CAPTCHA without Picture: Cryptographic Attestation of Personhood</h2>
      <a href="#captcha-without-picture-cryptographic-attestation-of-personhood">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1WeboSgc6BWaS2HxVOGRcb/590fba693766943506c4587a3172ed15/image4-4.png" />
            
            </figure><p>Hardware security keys are devices with an embedded secret that can connect to your computer or your phone</p><p>From a user perspective, a Cryptographic Attestation of Personhood works as follows:</p><ol><li><p>The user accesses a website protected by Cryptographic Attestation of Personhood, such as <a href="http://cloudflarechallenge.com">cloudflarechallenge.com</a>.</p></li><li><p>Cloudflare serves a challenge.</p></li><li><p>The user clicks I am human (beta) and gets prompted for a security device.</p></li><li><p>User decides to use a Hardware Security Key.</p></li><li><p>The user plugs the device into their computer or taps it to their phone for wireless signature (using NFC).</p></li><li><p>A cryptographic attestation is sent to Cloudflare, which allows the user in upon verification of the <a href="https://w3c.github.io/webauthn/#test-of-user-presence">user presence test</a>.</p></li></ol><p>Completing this flow takes five seconds. More importantly, this challenge protects users' privacy since the attestation is not uniquely linked to the user device. All device manufacturers trusted by Cloudflare are part of the FIDO Alliance. As such, each hardware key shares its identifier with other keys manufactured in the same batch (see <a href="https://fidoalliance.org/specs/fido-u2f-overview-ps-20150514.pdf">Universal 2nd Factor Overview, Section 8</a>). From Cloudflare’s perspective, your key looks like all other keys in the batch.</p><p>There are at most three clicks required to complete a Cryptographic Attestation of Personhood. There is no looping, where a user is asked to click on buses 10 times in a row.</p><p>While there is a variety of hardware security keys, our initial rollout is limited to a set of USB and NFC keys that are both certified by the FIDO alliance and have no known security issues according to the FIDO metadata service (MDS). Our demo only includes support for YubiKeys, which we had the chance to use and test; HyperFIDO keys; and Thetis FIDO U2F keys.</p><blockquote><p>“Driving open authentication standards like WebAuthn has long been at the heart of Yubico’s mission to deliver powerful security with a delightful user experience,” said Christopher Harrell, Chief Technology Officer at Yubico. “By offering a CAPTCHA alternative via a single touch backed by YubiKey hardware and public key cryptography, Cloudflare’s Cryptographic Attestation of Personhood experiment could help further reduce the cognitive load placed on users as they interact with sites under strain or attack. I hope this experiment will enable people to accomplish their goals with minimal friction and strong privacy, and that the results will show it is worthwhile for other sites to consider using hardware security for more than just authentication.”</p></blockquote>
    <div>
      <h2>How does it work?</h2>
      <a href="#how-does-it-work">
        
      </a>
    </div>
    <p>The Cryptographic Attestation of Personhood relies on <a href="https://www.w3.org/TR/webauthn-2/#sctn-attestation">Web Authentication (WebAuthn) Attestation</a>. This is an API that has been standardized at the W3C and is already implemented in most modern web browsers and operating systems. It aims to provide a standard interface to authenticate users on the web and use the cryptography capability of their devices.</p><p>As the need for stronger security with improved usability increases, we envision the deployment instances of WebAuthn to rise.</p><table><tr><td><p><b>Platform</b></p></td><td><p><b>Compatible Browsers</b></p></td></tr><tr><td><p>iOS 14.5</p></td><td><p>All browsers</p></td></tr><tr><td><p>Android 10 and later</p></td><td><p>Chrome</p></td></tr><tr><td><p>Windows</p></td><td><p>All browsers</p></td></tr><tr><td><p>macOS</p></td><td><p>All browsers</p></td></tr><tr><td><p>Ubuntu</p></td><td><p>All browsers</p></td></tr></table><p>Assuming you are using a hardware device with a compatible configuration, you might be wondering what is happening behind the scenes.</p>
    <div>
      <h3>The elevator pitch</h3>
      <a href="#the-elevator-pitch">
        
      </a>
    </div>
    <p>The short version is that your device has an embedded secure module containing a unique secret sealed by your manufacturer. The security module is capable of proving it owns such a secret without revealing it. Cloudflare asks you for proof and checks that your manufacturer is legitimate.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5msss4WaXkkCMEgBwldIwi/196f2f1e6caec88053f575f4c3e342c8/image7.png" />
            
            </figure>
    <div>
      <h3>The technical explanation</h3>
      <a href="#the-technical-explanation">
        
      </a>
    </div>
    <p>The longer version is that this verification involves public-key cryptography and digital certificates.</p><p>Public-key cryptography provides a way to produce unforgeable digital signatures. A user generates a signing key that can sign messages and a verification key that can be used by anyone to verify a message is authentic. This is akin to a <a href="https://en.wikipedia.org/wiki/Seal_(emblem)#Signet_rings">signet ring</a>, where the imprint of the ring is the signature and the ring itself the signing key.</p><p>Signature schemes are used widely to prove authenticity. Right now, your browser has verified that the server claiming to be “blog.cloudflare.com” is legitimate by verifying a signature made by someone who has a signing key associated with “blog.cloudflare.com”. To show the verification key is legitimate, the server provides a certificate that links the verification key to “blog.cloudflare.com”, itself signed by another verification key in another certificate. This chain goes all the way up to a root certificate from a <i>Certificate Authority</i> built into your browser.</p><p>Let's take another example. Alice owns a laptop with a secure module embedded. This module holds a signing key, sk_a. Alice says she sent a love letter to Bob yesterday. However, Bob is suspicious. Despite the letter stating "Hi Bob, it's Alice", Bob would like to be sure this letter comes from Alice. To do so, Bob asks Alice to provide her signature for the following message "musical-laboratory-ground". Since Bob chooses the message, if Alice can provide a signature associated with her verification key (pk_a), Bob would be convinced the love letter is from Alice. Alice does provide the signature, sk_a(“musical-laboratory-ground”). Bob confirms sk_a(“musical-laboratory-ground”) is associated with pk_a. He can now securely engage in their cryptographer relationship.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2az1pFbAuzJIcBMppOa1YC/19a6ebd82f20d88e7db696b42182025e/image1-4.png" />
            
            </figure><p>Thinking back to the Cryptographic Attestation of Personhood, you now know that your hardware key embeds a signing key. However, Cloudflare does not and cannot know the signing keys of all users of the Internet. To alleviate this problem, Cloudflare requests a different kind of proof. When asked if you are a human, we ask you to prove you are in control of a public key signed by a trusted manufacturer. When shipping devices with a secure module, <a href="https://fidoalliance.org/specs/fido-security-requirements/fido-authenticator-security-requirements-v1.4-fd-20201102.html">manufacturers sign</a> the associated attestation public key with a digital certificate.</p><p>Digital certificates usually contain a public key, information about the organization they are provisioned for, a validity period, the allowed usage, and a signature from a Certificate Authority making sure the certificate is legitimate. They allow metadata to be associated with a public key and therefore provide information about the issuer of a signature.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7zLUNHHDgaWpnCniSwkThu/3236b7b22b54c8319e30aa17c78937a3/image6-1.png" />
            
            </figure><p>So when Cloudflare asks you to provide a signature, it verifies your public key has been signed by the public key of a manufacturer. Since manufacturers have multiple levels of certificates, your device provides a chain of certificates that Cloudflare is able to verify. Each link in the chain is signed by its predecessor and signs its successor. Cloudflare trusts the root certificate of manufacturers. Because their numbers are limited, we have the capacity to verify them manually.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/O9TXLinQvwKA19xqCzcGb/332b024322a0ea832073e7e3ef98bfd7/image5-3.png" />
            
            </figure>
    <div>
      <h2>Privacy first</h2>
      <a href="#privacy-first">
        
      </a>
    </div>
    <p>Designing a challenge asking users to prove they are in control of a key from a certain manufacturer comes with a privacy and security challenge.</p><p>The privacy properties of the Cryptographic Attestation of Personhood are summarized in the following table.</p><table><tr><td><p><b>Property</b></p></td><td><p><b>Cloudflare Could</b></p></td><td><p><b>Cloudflare Does</b></p></td></tr><tr><td><p>Get your fingerprints or face</p></td><td><p>NO</p></td><td><p>N/A</p></td></tr><tr><td><p>Know the manufacturer of your key</p></td><td><p>YES - limited to the number of keys in your batch*</p></td><td><p>YES</p></td></tr><tr><td><p>Associate a unique ID to your key</p></td><td><p>YES**</p></td><td><p>NO</p></td></tr></table><p><i>* There must be 100,000 or more keys per batch (</i><a href="https://fidoalliance.org/specs/fido-uaf-v1.1-ps-20170202/fido-uaf-protocol-v1.1-ps-20170202.html#full-basic-attestation"><i>FIDO UAF Protocol Specification #4.1.2.1.1</i></a><i>). However, self-signed keys and keys from certain manufacturers have been found to</i> <a href="https://www.chromium.org/security-keys"><i>not meet this requirement</i></a><i>.</i></p><p><i>**This would require that we set a separate and distinct cookie to track your key. This is antithetical to privacy on the Internet, and to the goals of this project. You can learn more about how we are removing cookies like</i> <a href="/deprecating-cfduid-cookie/"><i>__cfduid here</i></a><i>.</i></p>
    <div>
      <h3>Attestation without collecting biometrics</h3>
      <a href="#attestation-without-collecting-biometrics">
        
      </a>
    </div>
    <p>The aim of this project: we want to know <i>that</i> you’re human. But we’re not interested in <i>which</i> human you are.</p><p>Happily, the WebAuthn API goes a long way to take care of this for us. Not that we want it, but the WebAuthn API prevents the collection of biometrics, such as a fingerprint. When your device asks for a biometric authentication — such as via a fingerprint sensor — it all happens locally. The verification is meant to unlock the secure module of your device, which provides a signature associated with your platform.</p><p>For our challenge, we leverage the <a href="https://w3c.github.io/webauthn/#sctn-sample-registration">WebAuthn registration</a> process. It has been designed to perform multiple authentications, which we do not have a use for. Therefore, we do assign the same constant value to the required username field. It protects users from deanonymization.</p>
    <div>
      <h3>No hidden work</h3>
      <a href="#no-hidden-work">
        
      </a>
    </div>
    <p>A common use of CAPTCHA is to label datasets that AI has difficulty identifying. This could be for books, street numbers, or fire hydrants. While this is useful for science, it has also been used as a way for companies to leverage human recognition ability for commercial gain without their users’ knowledge.</p><p>With the Cryptographic Attestation of Personhood, this does not happen. We have more flexibility designing the user flow, as we are not constrained by the CAPTCHA challenge model any more.</p>
    <div>
      <h3>What Cloudflare is doing to push privacy even further</h3>
      <a href="#what-cloudflare-is-doing-to-push-privacy-even-further">
        
      </a>
    </div>
    <p>While the Cryptographic Attestation of Personhood has a lot of upsides in terms of privacy, it is not perfect. Cloudflare still needs to know your manufacturer to let you in. As WebAuthn works with any certificate, we need to make sure Cloudflare receives certificates from untampered hardware keys. We would prefer to not have that information, further preserving your privacy.</p><p>We have worked on privacy standards in the past, leading the efforts with Privacy Pass for instance. <a href="http://privacypass.cloudflare.com/">Privacy Pass</a> allows you to solve a challenge once and provide a proof you passed it, meaning you don’t have to solve multiple CAPTCHAs. It greatly improved the user experience of VPN users, who face more challenges than other Internet users.</p><p>For the Cryptographic Attestation of Personhood, we dig into an emerging field in cryptography called <a href="https://en.wikipedia.org/wiki/Zero-knowledge_proof">Zero Knowledge proofs</a> (ZK proof). It allows our users to prove their manufacturer is part of a set of manufacturers trusted by Cloudflare. Using a ZK proof, the devices from a single manufacturer become indistinguishable from each other, as well as from devices from other manufacturers. This new system requires more technical details and deserves a dedicated blog post. Stay tuned.</p>
    <div>
      <h2>A never-ending quest</h2>
      <a href="#a-never-ending-quest">
        
      </a>
    </div>
    <p>Designing a challenge aimed at protecting millions of Internet properties is no easy task. In the current setup, we believe Cryptographic Attestation of Personhood offers strong security and usability guarantees compared to traditional CAPTCHA challenges. During a preliminary user study, users indicated a strong preference for touching their hardware key over clicking on pictures. Nevertheless, we know that this is a new system with room for improvements.</p><p>This experiment will be available on a limited basis in English-speaking regions. This allows us to have diversity in the pool of users and test this process in various locations. However, we recognize this is insufficient coverage, and we intend to test further. If you have specific needs, feel free to reach out.</p><p>Another issue that we keep a close eye on is security. The security of this challenge depends on the underlying hardware provided by trusted manufacturers. We have confidence they are secured. If any breach were to occur, we would be able to quickly deauthorize manufacturers’ public keys at various levels of granularity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3hbowSpXCTcXvLzs9vgpGV/8b46a33594c8b7f70f268dff8d05d44a/image3-3.png" />
            
            </figure><p>We also have to consider the possibility of facing automated button-pressing systems. A <a href="https://en.wikipedia.org/wiki/Drinking_bird">drinking bird</a> able to press the capacitive touch sensor could pass the Cryptographic Attestation of Personhood. At best, the bird solving rate matches the time it takes for the hardware to generate an attestation. With our current set of trusted manufacturers, this would be slower than the solving rate of professional CAPTCHA-solving services, while allowing legitimate users to pass through with certainty. In addition, existing Cloudflare mitigations would remain in place, efficiently protecting Internet properties.</p>
    <div>
      <h2>Final words</h2>
      <a href="#final-words">
        
      </a>
    </div>
    <p>For Cloudflare, it always comes back to: helping build a better Internet. The very idea that we’re all wasting 500 years per day on the Internet — that nobody had revisited the fundamental assumptions of CAPTCHAs since the turn of the century — seemed absurd to us.</p><p>We’re very proud of the work we’ve done here to release the Cryptographic Attestation of Personhood. This challenge has been built with a user-first approach while maintaining a high level of security for accessing Internet properties sitting behind Cloudflare’s global network. We’re now in the process of augmenting our existing humanity challenge with the Cryptographic Attestation of Personhood. You should expect to see it more frequently as time passes. You can try it out today at <a href="https://cloudflarechallenge.com">cloudflarechallenge.com</a>.</p><p>We want to acknowledge the work of other teams at Cloudflare. While this work is led by the Research team, we have been extremely privileged to get support from all across the company. If you want to help us build a better Internet, <a href="https://www.cloudflare.com/careers/jobs/?department=Technology%20Research&amp;location=default">we are hiring</a>.</p><p>Finally: we’re excited to bring about the demise of the fire hydrant on the Internet. It’s no longer needed.</p>
    <div>
      <h2>Feedback and Common errors</h2>
      <a href="#feedback-and-common-errors">
        
      </a>
    </div>
    <p>As this is currently an experimental project from the Cloudflare Research Team only USB or NFC security keys work today. We’re happy for the feedback and will look into adding other authenticators as soon as possible. If you use a non-supported device then you’re likely to get a somewhat difficult to understand error message from your browser. On Google Chrome you would see:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2DhXRbBd40SKy0GhKMfMXT/73a01215e4eaf839fce6e8bf73598d4a/Chrome-WebAuth-Fail-Screenshot.png" />
            
            </figure><p>If you would like to give us feedback on the Cryptographic Attestation of Personhood please fill out our <a href="https://forms.gle/HQxJtXgryg4oRL3e8">Google Form</a>.</p> ]]></content:encoded>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[CAPTCHA]]></category>
            <guid isPermaLink="false">XSbvOPEifCz8EVsPEDM4h</guid>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
        <item>
            <title><![CDATA[A Name Resolver for the Distributed Web]]></title>
            <link>https://blog.cloudflare.com/cloudflare-distributed-web-resolver/</link>
            <pubDate>Wed, 13 Jan 2021 12:00:00 GMT</pubDate>
            <description><![CDATA[ We are proud to announce a new resolver for the Distributed Web, where IPFS content indexed by the Ethereum Name Service (ENS) can be accessed. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>The Domain Name System (DNS) matches names to resources. Instead of typing 104.18.26.46 to access the Cloudflare Blog, you type blog.cloudflare.com and, using DNS, the <a href="https://www.cloudflare.com/learning/dns/glossary/what-is-a-domain-name/">domain name</a> resolves to 104.18.26.46, the Cloudflare Blog IP address.</p><p>Similarly, distributed systems such as Ethereum and IPFS rely on a naming system to be usable. DNS could be used, but its resolvers’ attributes run contrary to properties valued in distributed Web (dWeb) systems. Namely, dWeb resolvers ideally provide (i) locally verifiable data, (ii) built-in history, and (iii) have no single trust anchor.</p><p>At Cloudflare Research, we have been exploring alternative ways to resolve queries to responses that align with these attributes. We are proud to announce a new resolver for the Distributed Web, where IPFS content indexed by the <a href="http://ens.domains/">Ethereum Name Service</a> (ENS) can be accessed.</p><p>To discover how it has been built, and how you can use it today, read on.</p>
    <div>
      <h2>Welcome to the Distributed Web</h2>
      <a href="#welcome-to-the-distributed-web">
        
      </a>
    </div>
    
    <div>
      <h3>IPFS and its addressing system</h3>
      <a href="#ipfs-and-its-addressing-system">
        
      </a>
    </div>
    <p>The InterPlanetary FileSystem (IPFS) is a peer-to-peer network for storing content on a distributed file system. It is composed of a set of computers called nodes that store and relay content using a common addressing system.</p><p>This addressing system relies on the use of <a href="https://github.com/multiformats/cid">Content IDentifiers</a> (CID). CIDs are self-describing identifiers, because the identifier is derived from the content itself. For example, QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco is the CID version 0 (CIDv0) of the <a href="https://en.wikipedia-on-ipfs.org">wikipedia-on ipfs homepage</a>.</p><p>To understand why a CID is defined as self-describing, we can look at its binary representation. For QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco, the CID looks like the following:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2A7q58l0WReM66ndaxQmms/fc93187cd6f358d2291944cd57cbc419/image2-1.png" />
            
            </figure><p>The first is the algorithm used to generate the CID (sha2-256 in this case); then comes the length of the encoded content (32 for a sha2-256 hash), and finally the content itself. When referring to the <a href="https://github.com/multiformats/multicodec/blob/master/table.csv">multicodec table</a>, it is possible to understand how the content is encoded.</p><table><tr><td><p><b>Name</b></p></td><td><p><b>Code (in hexadecimal)</b></p></td></tr><tr><td><p>identity</p></td><td><p>0x00</p></td></tr><tr><td><p>sha1</p></td><td><p>0x11</p></td></tr><tr><td><p>sha2-256</p></td><td><p>0x12 = 00010010</p></td></tr><tr><td><p>keccak-256</p></td><td><p>0x1b</p></td></tr></table><p>This encoding mechanism is useful, because it creates a unique and upgradable content-addressing system across multiple protocols.</p><p>If you want to learn more, have a look at <a href="https://proto.school/#/anatomy-of-a-cid">ProtoSchool’s tutorial</a>.</p>
    <div>
      <h3>Ethereum and decentralised applications</h3>
      <a href="#ethereum-and-decentralised-applications">
        
      </a>
    </div>
    <p>Ethereum is an account-based blockchain with smart contract capabilities. Being account-based, each account is associated with addresses and these can be modified by operations grouped in blocks and sealed by Ethereum’s consensus algorithm, Proof-of-Work.</p><p>There are two categories of accounts: user accounts and contract accounts. User accounts are controlled by a private key, which is used to sign transactions from the account. Contract accounts hold bytecode, which is executed by the network when a transaction is sent to their account. A transaction can include both funds and data, allowing for rich interaction between accounts.</p><p>When a transaction is created, it gets verified by each node on the network. For a transaction between two user accounts, the verification consists of checking the origin account signature. When the transaction is between a user and a smart contract, every node runs the smart contract bytecode on the Ethereum Virtual Machine (EVM). Therefore, all nodes perform the same suite of operations and end up in the same state. If one actor is malicious, nodes will not add its contribution. Since nodes have diverse ownership, they have an incentive to not cheat.</p>
    <div>
      <h2>How to access IPFS content</h2>
      <a href="#how-to-access-ipfs-content">
        
      </a>
    </div>
    <p>As you may have noticed, while a CID describes a piece of content, it doesn't describe where to find it. In fact, the CID describes the content, but not its location on the network. The location of the file would be retrieved by a query made to an IPFS node.</p><p>An IPFS URL (Unified Resource Locator) looks like this: <code>ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco</code>. Accessing this URL means retrieving <code>QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco</code> using the IPFS protocol, denoted by ipfs://. However, typing such a URL is quite error-prone. Also, these URLs are not very human-friendly, because there is no good way to remember such long strings. To get around this issue, you can use DNSLink. DNSLink is a way of specifying IPFS CIDs within a DNS TXT record. For instance, <a href="http://wikipedia-on-ipfs.org">wikipedia on ipfs</a> has the following TXT record</p><p><code>$ dig +short TXT _dnslink.en.wikipedia-on-ipfs.org</code></p><p><code>_dnslink=/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco</code></p><p>In addition, it's A record points to an IPFS gateway. This means that, when you access en.wikipedia-on-ipfs.org, your request is directed to an IPFS HTTP Gateway, which then looks out for the CID using your domain TXT record, and returns the content associated to this CID using the IPFS network.</p><p>This is trading ease-of-access against security. The web browser of the user doesn't verify the integrity of the content served. This could be because the browser does not implement IPFS or because it has no way of validating domain signature — <a href="https://www.cloudflare.com/dns/dnssec/how-dnssec-works/">DNSSEC</a>. We wrote about this issue in our previous blog post on <a href="/e2e-integrity/">End-to-End Integrity</a>.</p>
    <div>
      <h2>Human-readable identifiers</h2>
      <a href="#human-readable-identifiers">
        
      </a>
    </div>
    <p>DNS simplifies referring to IP addresses, in the same way that postal addresses are a way of referring to geolocation data, and contacts in your mobile phone abstract phone numbers. All these systems provide a human-readable format and reduce the error rate of an operation.</p><p>To verify these data, the trusted anchors, or “sources of truth”, are:</p><ul><li><p><a href="https://www.cloudflare.com/en-gb/dns/dnssec/root-signing-ceremony/">Root DNS Keys</a> for DNS.</p></li><li><p>The government registry for postal addresses. In the UK, addresses <a href="https://www.nidirect.gov.uk/articles/how-streets-are-named-and-numbered">are handled</a> by cities, boroughs and local councils.</p></li><li><p>When it comes to your contacts, you are the trust anchor.</p></li></ul>
    <div>
      <h2>Ethereum Name Service, an index for the Distributed Web</h2>
      <a href="#ethereum-name-service-an-index-for-the-distributed-web">
        
      </a>
    </div>
    <p>An account is identified by its address. An address starts with "0x" and is followed by 20 bytes (<a href="https://ethereum.github.io/yellowpaper/paper.pdf">ref 4.1 Ethereum yellow paper</a>), for example: 0xf10326c1c6884b094e03d616cc8c7b920e3f73e0. This is not very readable, and can be pretty scary when transactions are not reversible and one can easily mistype a single character.</p><p>A first mitigation strategy was to introduce a new notation to capitalise some letters based on the hash of the address 0xF10326C1c6884b094E03d616Cc8c7b920E3F73E0. This can help detect mistype, but it is still not readable. If I have to send a transaction to a friend, I have no way of confirming she hasn't mistyped the address.</p><p>The <a href="https://ens.domains/">Ethereum Name Service</a> (ENS) was created to tackle this issue. It is a system capable of turning human-readable names, referred to as domains, to blockchain addresses. For instance, the domain <a href="https://app.ens.domains/name/privacy-pass.eth">privacy-pass.eth</a> points to the Ethereum address 0xF10326C1c6884b094E03d616Cc8c7b920E3F73E0.</p><p>To achieve this, the system is organised in <a href="https://docs.ens.domains/">two components</a>, registries and resolvers.</p><p>A registry is a smart contract that maintains a list of domains and some information about each domain: the domain owner and the domain resolver. The owner is the account allowed to manage the domain. They can create subdomains and change ownership of their domain, as well as modify the resolver associated with their domain.</p><p>Resolvers are responsible for keeping records. For instance, Public Resolver is a smart contract capable of associating not only a name to blockchain addresses, but also a name to an IPFS content identifier. The resolver address is stored in a registry. Users then contact the registry to retrieve the resolver associated with the name.</p><p>Consider a user, Alice, who has direct access to the Ethereum state. The flow goes as follows: Alice would like to get Privacy Pass’s Ethereum address, for which the domain is privacy-pass.eth. She looks for privacy-pass.eth in the ENS Registry and figures out the resolver for privacy-pass.eth is at 0x1234... . She now looks for the address of privacy-pass.eth at the resolver address, which turns out to be 0xf10326c....</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6yVOgswqi6HQ38qlhTaTdK/0956f47fa306bebb2233e9601d0b430c/image1-3.png" />
            
            </figure><p>Accessing the IPFS content identifier for privacy-pass.eth works similarly. The resolver is the same, only the accessed data is different — Alice calls a different method from the smart contract.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1CjIbo1euB3DG5EZgnL3Bm/9b59d7bd3c7fa63870238274ef5a0200/image5.png" />
            
            </figure>
    <div>
      <h2>Cloudflare Distributed Web Resolver</h2>
      <a href="#cloudflare-distributed-web-resolver">
        
      </a>
    </div>
    <p>The goal was to be able to use this new way of indexing IPFS content directly from your web browser. However, accessing the ENS registry requires access to the Ethereum state. To get access to IPFS, you would also need to access the IPFS network.</p><p>To tackle this, we are going to use Cloudflare’s Distributed Web Gateway. Cloudflare operates both an Ethereum Gateway and an IPFS Gateway, respectively available at cloudflare-eth.com and cloudflare-ipfs.com.</p>
    <div>
      <h3>EthLink</h3>
      <a href="#ethlink">
        
      </a>
    </div>
    <p>The <a href="https://github.com/wealdtech/coredns-ens">first version</a> of EthLink was built by Jim McDonald and is operated by True Name LTD at eth.link. Starting from next week, eth.link will transition to use the Cloudflare Distributed Web Resolver. To that end, we have built EthLink on top of Cloudflare Workers. This is a proxy to IPFS. It proxies all ENS registered domains when .link is appended. For instance, privacy-pass.eth should render the Privacy Pass homepage. From your web browser, <a href="https://privacy-pass.eth.link">https://privacy-pass.eth.link</a> does it.</p><p>The resolution is done at the Cloudflare edge using a Cloudflare Worker. Cloudflare Workers allows JavaScript code to be run on Cloudflare infrastructure, eliminating the need to maintain a server and increasing the reliability of the service. In addition, it follows Service Workers API, so results returned from the resolver can be checked by end users if needed.</p><p>To do this, we set up a wildcard DNS record for *.eth.link to be proxied through Cloudflare and handled by a Cloudflare Worker.  When a user Alice accesses <a href="https://privacy-pass.eth.link">privacy-pass.eth.link</a>, the worker first gets the CID of the CID to be retrieved from Ethereum. Then, it requests the content matching this CID to IPFS, and returns it to Alice.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/WivGoQhRDcSaDh99sVdNI/0e9bca31a378146d49d92c3af71180e8/image3.png" />
            
            </figure><p>All parts can be run locally. The worker can be run in a service Worker, and the Ethereum Gateway can point to both a local Ethereum node and the IPFS gateway provided by IPFS Companion. It means that while Cloudflare provides resolution-as-a-service, none of the components has to be trusted.</p>
    <div>
      <h2>Final notes</h2>
      <a href="#final-notes">
        
      </a>
    </div>
    <p>So <a href="https://arewedistributedyet.com/">are we distributed yet</a>? No, but we are getting closer, building bridges between emerging technologies and current web infrastructure. By providing a gateway dedicated to the distributed web, we hope to make these services more accessible to everyone.</p><p>We thank the ENS team for their support of a new resolver on expanding the distributed web. The ENS team has been running a similar service at <a href="https://eth.link">https://eth.link</a>. On January 18th, they will switch <a href="https://eth.link">https://eth.link</a> to using our new service.</p><p>These services benefit from the added speed and security of the Cloudflare Worker platform, while paving the way to run distributed protocols in browsers.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[IPFS]]></category>
            <category><![CDATA[Ethereum]]></category>
            <category><![CDATA[Distributed Web]]></category>
            <guid isPermaLink="false">5GZYZoddJJgvOcmn2ALKWL</guid>
            <dc:creator>Thibault Meunier</dc:creator>
        </item>
    </channel>
</rss>