
<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>Fri, 10 Apr 2026 01:27:57 GMT</lastBuildDate>
        <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[Privacy Pass v3: the new privacy bits]]></title>
            <link>https://blog.cloudflare.com/privacy-pass-v3/</link>
            <pubDate>Tue, 12 Oct 2021 12:59:19 GMT</pubDate>
            <description><![CDATA[ A new version of Privacy Pass for reducing the number of CAPTCHAs. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In November 2017, we <a href="/cloudflare-supports-privacy-pass/">released</a> our implementation of a privacy preserving protocol to let users prove that they are humans without enabling tracking. When you install <a href="https://privacypass.github.io/">Privacy Pass’s browser extension</a>, you get tokens when you solve a Cloudflare CAPTCHA which can be used to avoid needing to solve one again... The redeemed token is cryptographically unlinkable to the token originally provided by the server. That is why Privacy Pass is privacy preserving.</p><p>In October 2019, Privacy Pass reached another milestone. We released <a href="/supporting-the-latest-version-of-the-privacy-pass-protocol/">Privacy Pass Extension v2.0</a> that includes a <a href="https://www.hcaptcha.com/privacy-pass">new service provider</a> (hCaptcha) which provides a way to redeem a token not only with CAPTCHAs in the Cloudflare challenge pages but also hCaptcha CAPTCHAs in any website. When you encounter any hCaptcha CAPTCHA in any website, including the ones not behind Cloudflare, you can redeem a token to pass the CAPTCHA.</p><p>We believe Privacy Pass solves an important problem — balancing privacy and security for bot mitigation— but we think there’s more to be done in terms of both the <a href="https://github.com/privacypass/challenge-bypass-extension/tree/v3-rc">codebase</a> and the protocol. We improved the codebase by redesigning how the service providers interact with the core extension. At the same time, we made progress on the standardization at IETF and improved the protocol by adding metadata which allows us to do more fabulous things with Privacy Pass.</p>
    <div>
      <h2>Announcing Privacy Pass Extension v3.0</h2>
      <a href="#announcing-privacy-pass-extension-v3-0">
        
      </a>
    </div>
    <p>The current implementation of our extension is functional, but it is difficult to maintain two Privacy Pass service providers: Cloudflare and hCaptcha. So we decided to <a href="https://www.cloudflare.com/learning/cloud/how-to-refactor-applications/">refactor</a> the browser extension to improve its maintainability. We also used this opportunity to make following improvements:</p><ul><li><p>Implement the extension using TypeScript instead of plain JavaScript.</p></li><li><p>Build the project using a module bundler instead of custom build scripts.</p></li><li><p>Refactor the code and define the API for the cryptographic primitive.</p></li><li><p>Treat provider-specific code as an encapsulated software module rather than a list of configuration properties.</p></li></ul><p>As a result of the improvements listed above, the extension will be less error-prone and each service provider will have more flexibility and can be integrated seamlessly with other providers.</p><p>In the new extension we use TypeScript instead of plain JavaScript because its syntax is a kind of extension to JavaScript, and we already use TypeScript in <a href="/bootstrapping-a-typescript-worker/">Workers</a>. One of the things that makes TypeScript special is that it has features that are only available in modern programming languages, like <a href="https://en.wikipedia.org/wiki/Void_safety">null safety</a>.</p>
    <div>
      <h2>Support for Future Service Providers</h2>
      <a href="#support-for-future-service-providers">
        
      </a>
    </div>
    <p>Another big improvement in v3.0 is that it is designed for modularity, meaning that it will be very easy to add a new potential service provider in the future. A new provider can use an API provided by us to implement their own request flow to use the Privacy Pass protocol and to handle the HTTP requests. By separating the provider-specific code from the core extension code using the API, the extension will be easier to update when there is a need for more service providers.</p><p>On a technical level, we allow each service provider to have its own <a href="https://developer.chrome.com/extensions/webRequest">WebRequest API</a> event listeners instead of having central event listeners for all the providers. This allows providers to extend the browser extension's functionality and implement any request handling logic they want.</p><p>Another major change that enables us to do this is that we moved away from configuration to programmable modularization.</p>
    <div>
      <h2>Configuration vs Modularization</h2>
      <a href="#configuration-vs-modularization">
        
      </a>
    </div>
    <p><a href="/supporting-the-latest-version-of-the-privacy-pass-protocol/">As mentioned in 2019</a>, it would be impossible to expect different service providers to all abide by the same exact request flow, so we decided to use a JSON configuration file in v2.0 to define the request flow. The configuration allows the service providers to easily modify the extension characteristics without dealing too much with the core extension code. However, recently we figured out that we can improve it without using a configuration file, and using modules instead.</p><p>Using a configuration file limits the flexibility of the provider by the number of possible configurations. In addition, when the logic of each provider evolves and deviates from one another, the size of configuration will grow larger and larger which makes it hard to document and keep track of. So we decided to refactor how we determine the request flow from using a configuration file to using a module file written specifically for each service provider instead.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/34G52zSZ9ukkaa0h079EBV/287aaf7e3245f7fe1071ee0d4270a95f/image2-19.png" />
            
            </figure><p>By using a programmable module, the providers are not limited by the available fields in the configuration. In addition, the providers can use the available implementations of the necessary cryptographic primitives in any point of the request flow because we factored out the crypto bits into a separate module which can be used by any provider. In the future, if the cryptographic primitives ever change, the providers can update the code and use it any time.</p>
    <div>
      <h2>Towards Standard Interoperability</h2>
      <a href="#towards-standard-interoperability">
        
      </a>
    </div>
    <p>The Privacy Pass protocol was first published at the <a href="https://www.petsymposium.org/2018/files/papers/issue3/popets-2018-0026.pdf">PoPETS</a> symposium in 2018. As explained in this <a href="/privacy-pass-the-math/">previous post</a>, the core of the Privacy Pass protocol is a secure way to generate tokens between server and client. To that end, the protocol requires evaluating a pseudorandom function that is oblivious and verifiable. The first property prevents the server from learning information about the client’s tokens, while the client learns nothing about the server’s private key. This is useful to protect the privacy of users. The token generation must also be verifiable in the sense that the client can attest to the fact that its token was minted using the server’s private key.</p><p>The original implementation of Privacy Pass has seen real-world use in our browser extension, helping to reduce CAPTCHAs for hundreds of thousands of people without compromising privacy. But to guarantee interoperability between services implementing Privacy Pass, what's required is an accurate specification of the protocol and its operations. With this motivation, the Privacy Pass protocol was proposed as an Internet draft at the <a href="https://www.ietf.org/">Internet Engineering Task Force</a> (IETF) — to know more about our participation at IETF <a href="/cloudflare-and-the-ietf">look at the post</a>.</p><p>In March 2020, the protocol was presented at IETF-107 for the first time. The session was a <a href="https://www.ietf.org/how/bofs/">Birds-of-a-Feather</a>, a place where the IETF community discusses the creation of new working groups that will write the actual standards. In the session, the working group’s charter is presented and proposes to develop a secure protocol for redeeming unforgeable tokens that attest to the validity of some attribute being held by a client. The charter was later approved, and three documents were integrated covering the protocol, the architecture, and an HTTP API for supporting Privacy Pass. The working group at IETF can be found at <a href="https://datatracker.ietf.org/wg/privacypass/about/">https://datatracker.ietf.org/wg/privacypass/</a>.</p><p>Additionally, to its core functionality, the Privacy Pass protocol can be extended to improve its usability or to add new capabilities. For instance, adding a mechanism for public verifiability will allow a third party, someone who did not participate in the protocol, to verify the validity of tokens. Public verifiability can be implemented using a <i>blind-signature scheme</i> — this is a special type of digital signatures firstly proposed by <a href="https://link.springer.com/chapter/10.1007/978-1-4757-0602-4_18">David Chaum</a> in which signers can produce signatures on messages without learning the content of the message. A diversity of algorithms to implement blind-signatures exist; however, there is still work to be done to define a good candidate for public verifiability.</p><p>Another extension for Privacy Pass is the support for including metadata in the tokens. As this is a feature with high impact on the protocol, we devote a larger section to explain the benefits of supporting metadata in the face of hoarding attacks.</p>
    <div>
      <h2>Future work: metadata</h2>
      <a href="#future-work-metadata">
        
      </a>
    </div>
    <p>What is research without new challenges that arise? What does development look like if there are no other problems to solve? During the design and development of Privacy Pass (both as a service, as an idea, and as a protocol), a potential vector for abuse was noted, which will be referred to as a “hoarding” or “farming” attack. This attack consists of individual users or groups of users that can gather tokens over a long period of time and redeem them all at once with the aim of, for example, overwhelming a website and making the service unavailable for other users. In a more complex scenario, an attacker can build up a stock of tokens that they could then redistribute amongst other clients. This redistribution ability is possible as tokens are not linked to specific clients, which is a property of the Privacy Pass protocol.</p><p>There have been several proposed solutions to this attack. One can, for example, make the verification of tokens procedure very efficient, so attackers will need to hoard an even larger amount of tokens in order to overwhelm a service. But the problem is not only about making verification times faster, and, therefore, this does not completely solve the problem. Note that in Privacy Pass, a successful token redemption could be exchanged for a single-origin cookie. These cookies allow clients to avoid future challenges for a particular domain without using more tokens. In the case of a hoarding attack, an attacker could trade in their hoarded number of tokens for a number of cookies. An attacker can, then, mount a layer 7 DDoS attack with the “hoarded” cookies, which would render the service unavailable.</p><p>In the next sections, we will explore other different solutions to this attack.</p>
    <div>
      <h3>A simple solution and its limitations: key rotation</h3>
      <a href="#a-simple-solution-and-its-limitations-key-rotation">
        
      </a>
    </div>
    <p>What does “key rotation” mean in the context of Privacy Pass? In Privacy Pass, each token is attested by keys held by the service. These keys are further used to verify the honesty of a token presented by a client when trying to access a challenge-protected service. “Key rotation” means updating these keys with regard to a chosen epoch (meaning, for example, that every two weeks — the epoch —, the keys will be rotated). Regular key rotation, then, implies that tokens belong to these epochs and cannot be used outside them, which prevents stocks of tokens from being useful for longer than the epoch they belong to.</p><p>Keys, however, should not be rotated frequently as:</p><ul><li><p>Rotating a key can lead to security implications</p></li><li><p>Establishing trust in a frequently-rotating key service can be a challenging problem</p></li><li><p>The unlinkability of the client when using tokens can be diminished</p></li></ul><p>Let’s explore these problems one by one now:</p><p><b>Rotating a key can lead to security implications</b>, as past keys need to be deleted from secure storage locations and replaced with new ones. This process is prone to failure if done regularly, and can lead to potential key material leakage.</p><p><b>Establishing trust in a frequently-rotating key service</b> can be a challenging problem, as keys will have to be verified by the needed parties each time they are regenerated. Keys need to be verified as it has to be attested that they belong to the entity one is trying to communicate with. If keys rotate too frequently, this verification procedure will have to happen frequently as well, so that an attacker will not be able to impersonate the honest entity with a “fake” public key.</p><p><b>The unlinkability of the client when using tokens can be diminished</b> as a savvy attacker (a malicious server, for example) could link token generation and token future-use. In the case of a malicious server, it can, for example, rotate their keys too often to violate unlinkability or could pick a separate public key for each client issuance. In these cases, this attack can be solved by the usage of public mechanisms to record which server’s public keys are used; but this requires further infrastructure and coordination between actors. Other cases are not easily solvable by this “public verification”: if keys are rotated every minute, for example, and a client was the only one to visit a “privacy pass protected” site in that minute, then, it's not hard to infer (to “link”) that the token came only from this specific client.</p>
    <div>
      <h3>A novel solution: Metadata</h3>
      <a href="#a-novel-solution-metadata">
        
      </a>
    </div>
    <p>A novel solution to this “hoarding” problem that does not require key rotation or further optimization of verification times is the addition of metadata. This approach was introduced in the paper “<a href="https://eprint.iacr.org/2021/864.pdf">A Fast and Simple Partially Oblivious PRF, with Applications</a>”, and it is called the “POPRF with metadata” construction. The idea is to add a metadata field to the token generation procedure in such a way that tokens are cryptographically linked to this added metadata. The added metadata can be, for example, a number that signals which epoch this token belongs to. The service, when presented with this token on verification, promptly checks that it corresponds to its internal epoch number (this epoch number can correspond to a period of time, a threshold of number of tokens issued, etc.). If it does not correspond, this token is expired and cannot be further used. Metadata, then, can be used to expire tokens without performing key rotations, thereby avoiding some issues outlined above.</p><p>Other kinds of metadata can be added to the Partially Oblivious PRF (PO-PRF) construction as well. Geographic location can be added, which signals that tokens can only be used in a specific region.</p>
    <div>
      <h3>The limits of metadata</h3>
      <a href="#the-limits-of-metadata">
        
      </a>
    </div>
    <p>Note, nevertheless, that the addition of this “metadata” should be carefully considered as adding, in the case of “time-metadata”, an explicit time bound signal will diminish the unlikability set of the tokens. If an explicit time-bound signal is added (for example, the specific time — year, month, day, hour, minute and seconds — in which this token was generated and the amount of time it is valid for), it will allow a malicious server to link generation and usage. The recommendation is to use “opaque metadata”: metadata that is public to both client and service but that only the service knows its precise meaning. A server, for example, can set a counter that gets increased after a period of time (for example, every two weeks). The server will add this counter as metadata rather than the period of time. The client, in this case, publicly knows what this counter is but does not know to which period it refers to.</p><p>Geographic location metadata should be coarse as well: it should refer to a large geographical area, such as a continent, or political and economic union rather than an explicit location.</p>
    <div>
      <h2>Wrap up</h2>
      <a href="#wrap-up">
        
      </a>
    </div>
    <p>The Privacy Pass protocol provides users with a secure way for redeeming tokens. At Cloudflare, we use the protocol to reduce the number of CAPTCHAs improving the user experience while browsing websites. A natural evolution of the protocol is expected, ranging from its standardization to innovating with new capabilities that help to prevent abuse of the service.</p><p>On the service side, we refactored the Privacy Pass browser extension aiming to improve the quality of the code, so bugs can be detected in earlier phases of the development. The code is available at the <a href="https://github.com/privacypass/challenge-bypass-extension/tree/v3-rc">challenge-bypass-extension</a> repository, and we invite you to try the release candidate version.</p><p>An appealing extension for Privacy Pass is the inclusion of metadata as it provides a non-cumbersome way to solve hoarding attacks, while preserving the anonymity (in general, the privacy) of the protocol itself. <a href="https://eprint.iacr.org/2021/864.pdf">Our paper</a> provides you more information about the technical details behind this idea.</p><p>The application of the Privacy Pass protocol in other use cases or to create other service providers requires a certain degree of compatibility. People wanting to implement Privacy Pass must be able to have a standard specification, so implementations can interoperate. The efforts along these lines are centered on the <a href="https://datatracker.ietf.org/wg/privacypass/about/">Privacy Pass working group</a> at IETF, a space open for anyone to participate in delineating the future of the protocol. Feel free to be part of these efforts too.</p><p>We are continuously working on new ways of improving our services and helping the Internet be a better and a more secure place. You can join us on this effort and can reach us at <a href="https://research.cloudflare.com">research.cloudflare.com</a>. See you next time.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Privacy Pass]]></category>
            <category><![CDATA[CAPTCHA]]></category>
            <guid isPermaLink="false">nnk7WdvORjw4nOJUFyE1z</guid>
            <dc:creator>Pop Chunhapanya</dc:creator>
            <dc:creator>Armando Faz-Hernández</dc:creator>
            <dc:creator>Sofía Celi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Announcing cfnts: Cloudflare's implementation of NTS in Rust]]></title>
            <link>https://blog.cloudflare.com/announcing-cfnts/</link>
            <pubDate>Thu, 31 Oct 2019 13:00:00 GMT</pubDate>
            <description><![CDATA[ Several months ago we announced that we were providing a new public time service. Part of what we were providing was the first major deployment of the new Network Time Security protocol, with a newly written implementation of NTS in Rust.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Several months ago we announced that we were providing a <a href="/secure-time/">new public time service.</a> Part of what we were providing was the first major deployment of the new Network Time Security (NTS) protocol, with a newly written implementation of NTS in Rust. In the process, we received helpful advice from the NTP community, especially from the NTPSec and Chrony projects. We’ve also participated in several interoperability events. Now we are returning something to the community: Our implementation, cfnts, is now <a href="https://github.com/cloudflare/cfnts">open source</a> and we welcome your pull requests and issues.</p><p>The journey from a blank source file to a working, deployed service was a lengthy one, and it involved many people across multiple teams.</p><hr /><p><i>"Correct time is a necessity for most security protocols in use on the Internet. Despite this, secure time transfer over the Internet has previously required complicated configuration on a case by case basis. With the introduction of NTS, secure time synchronization will finally be available for everyone. It is a small, but important, step towards increasing security in all systems that depend on accurate time. I am happy that Cloudflare are sharing their NTS implementation. A diversity of software with NTS support is important for quick adoption of the new protocol."</i></p><p></p><p>— <b>Marcus Dansarie</b>, coauthor of the <a href="https://datatracker.ietf.org/doc/draft-ietf-ntp-using-nts-for-ntp/">NTS specification</a></p><hr />
    <div>
      <h2>How NTS works</h2>
      <a href="#how-nts-works">
        
      </a>
    </div>
    <p>NTS is structured as a suite of two sub-protocols as shown in the figure below. The first is the Network Time Security Key Exchange (NTS-KE), which is always conducted over Transport Layer Security (TLS) and handles the creation of key material and parameter negotiation for the second protocol. The second is <a href="https://tools.ietf.org/html/rfc5905">NTPv4</a>, the current version of the NTP protocol, which allows the client to synchronize their time from the remote server.</p><p>In order to maintain the scalability of NTPv4, it was important that the server not maintain per-client state. A very small server can serve millions of NTP clients. Maintaining this property while providing security is achieved with cookies that the server provides to the client that contain the server state.</p><p>In the first stage, the client sends a request to the NTS-KE server and gets a response via TLS. This exchange carries out a number of functions:</p><ul><li><p>Negotiates the <a href="https://en.wikipedia.org/wiki/Authenticated_encryption">AEAD</a> algorithm to be used in the second stage.</p></li><li><p>Negotiates the second protocol. Currently, the standard only defines how NTS works with NTPv4.</p></li><li><p>Negotiates the NTP server IP address and port.</p></li><li><p>Creates cookies for use in the second stage.</p></li><li><p>Creates two symmetric keys (C2S and S2C) from the TLS session via exporters.</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6ELZCQXF1AwQPqScsl7VRM/3a9b9848f80df1c72126b485ebbba15d/overview-of-NTP-_2x-1.png" />
            
            </figure><p>In the second stage, the client securely synchronizes the clock with the negotiated NTP server. To synchronize securely, the client sends NTPv4 packets with four special extensions:</p><ul><li><p><i>Unique Identifier Extension</i> contains a random nonce used to prevent replay attacks.</p></li><li><p><i>NTS Cookie Extension</i> contains one of the cookies that the client stores. Since currently only the client remembers the two AEAD keys (C2S and S2C), the server needs to use the cookie from this extension to extract the keys. Each cookie contains the keys encrypted under a secret key the server has.</p></li><li><p><i>NTS Cookie Placeholder Extension</i> is a signal from the client to request additional cookies from the server. This extension is needed to make sure that the response is not much longer than the request to prevent amplification attacks.</p></li><li><p><i>NTS Authenticator and Encrypted Extension Fields Extension</i> contains a ciphertext from the AEAD algorithm with C2S as a key and with the NTP header, timestamps, and all the previously mentioned extensions as associated data. Other possible extensions can be included as encrypted data within this field. Without this extension, the timestamp can be spoofed.</p></li></ul><p>After getting a request, the server sends a response back to the client echoing the <i>Unique Identifier Extension</i> to prevent replay attacks, the <i>NTS Cookie Extension</i> to provide the client with more cookies, and the <i>NTS Authenticator and Encrypted Extension Fields Extension</i> with an AEAD ciphertext with S2C as a key. But in the server response, instead of sending the <i>NTS Cookie Extension</i> in plaintext, it needs to be encrypted with the AEAD to provide unlinkability of the NTP requests.</p><p>The second handshake can be repeated many times without going back to the first stage since each request and response gives the client a new cookie. The expensive public key operations in TLS are thus amortized over a large number of requests. Furthermore, specialized timekeeping devices like FPGA implementations only need to implement a few symmetric cryptographic functions and can delegate the complex TLS stack to a different device.</p>
    <div>
      <h2>Why Rust?</h2>
      <a href="#why-rust">
        
      </a>
    </div>
    <p>While many of our services are written in <a href="/tag/go/">Go</a>, and we have considerable experience on the Crypto team with Go, a garbage collection pause in the middle of responding to an NTP packet would negatively impact accuracy. We picked <a href="/tag/rust/">Rust</a> because of its zero-overhead and useful features.</p><ul><li><p><b>Memory safety</b> After <a href="/answering-the-critical-question-can-you-get-private-ssl-keys-using-heartbleed/">Heartbleed</a>, <a href="/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/">Cloudbleed</a>, and the <a href="https://docs.microsoft.com/en-us/security-updates/securitybulletins/2009/ms09-044">steady</a> <a href="https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-1.html">drip</a> <a href="https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=%22heap+overflow%22">of</a> <a href="https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=%22buffer+overflow%22">vulnerabilities</a> caused by C’s lack of memory safety, it’s clear that C is not a good choice for new software dealing with untrusted inputs. The obvious solution for memory safety is to use garbage collection, but garbage collection has a substantial runtime overhead, while Rust has less runtime overhead.</p></li><li><p><b>Non-nullability</b> Null pointers are an edge case that is frequently not handled properly. Rust explicitly marks optionality, so all references in Rust can be safely dereferenced. The type system ensures that option types are properly handled.</p></li><li><p><b>Thread safety</b>  Data-race prevention is another key feature of Rust. Rust’s ownership model ensures that all cross-thread accesses are synchronized by default. While not a panacea, this eliminates a major class of bugs.</p></li><li><p><b>Immutability</b> Separating types into mutable and immutable is very important for reducing bugs. For example, in Java, when you pass an object into a function as a parameter, after the function is finished, you will never know whether the object has been mutated or not. Rust allows you to pass the object reference into the function and still be assured that the object is not mutated.</p></li><li><p><b>Error handling</b>  Rust result types help with ensuring that operations that can produce errors are identified and a choice made about the error, even if that choice is passing it on.</p></li></ul><p>While Rust provides safety with zero overhead, coding in Rust involves understanding linear types and for us a new language. In this case the importance of security and performance meant we chose Rust over a potentially easier task in Go.</p>
    <div>
      <h2>Dependencies we use</h2>
      <a href="#dependencies-we-use">
        
      </a>
    </div>
    <p>Because of our scale and for DDoS protection we needed a highly scalable server. For UDP protocols without the concept of a connection, the server can respond to one packet at a time easily, but for TCP this is more complex. Originally we thought about using <a href="https://github.com/tokio-rs/tokio">Tokio</a>. However, at the time Tokio suffered from scheduler <a href="https://github.com/tokio-rs/tokio/issues/449">problems that had caused other teams some issues</a>. As a result we decided to use <a href="https://github.com/tokio-rs/mio">Mio</a> directly, basing our work on the examples in <a href="https://github.com/ctz/rustls">Rustls</a>.</p><p>We decided to use Rustls over OpenSSL or BoringSSL because of the crate's consistent error codes and default support for authentication that is difficult to disable accidentally. While there are some features that are not yet supported, it got the job done for our service.</p>
    <div>
      <h2>Other engineering choices</h2>
      <a href="#other-engineering-choices">
        
      </a>
    </div>
    <p>More important than our choice of programming language was our implementation strategy. A working, fully featured NTP implementation is a complicated program involving a <a href="https://en.wikipedia.org/wiki/Phase-locked_loop">phase-locked loop.</a> These have a difficult reputation due to their nonlinear nature, beyond the usual complexities of closed loop control. The response of a phase lock loop to a disturbance can be estimated if the loop is locked and the disturbance small. However, lock acquisition, large disturbances, and the necessary filtering in NTP are all hard to analyze mathematically since they are not captured in the linear models applied for small scale analysis. While NTP works with the total phase, unlike the phase-locked loops of electrical engineering, there are still nonlinear elements. For NTP testing, changes to this loop requires weeks of operation to determine the performance as the loop responds very slowly.</p><p>Computer clocks are generally accurate over short periods, while networks are plagued with inconsistent delays. This <a href="https://tf.nist.gov/general/pdf/1551.pdf">demands a slow response</a>. Changes we make to our service have taken hours to have an effect, as the clients slowly adapt to the new conditions. While <a href="https://tools.ietf.org/html/rfc5905">RFC 5905</a> provides lots of details on an algorithm to adjust the clock, later implementations such as <a href="https://chrony.tuxfamily.org/">chrony</a> have improved upon the algorithm through much more sophisticated nonlinear filters.</p><p>Rather than implement these more sophisticated algorithms, we let chrony adjust the clock of our servers, and copy the state variables in the header from chrony and adjust the dispersion and root delay according to the formulas given in the RFC. This strategy let us focus on the new protocols.</p>
    <div>
      <h2>Prague</h2>
      <a href="#prague">
        
      </a>
    </div>
    <p>Part of what the Internet Engineering Task Force (IETF) does is organize events like hackathons where implementers of a new standard can get together and try to make their stuff work with one another. This exposes bugs and infelicities of language in the standard and the implementations. We attended the IETF 104 hackathon to develop our server and make it work with other implementations. The NTP working group members were extremely generous with their time, and during the process we uncovered a few issues relating to the exact way one has to handle ALPN with older OpenSSL versions.</p><p>At the IETF 104 in Prague we had a working client and server for NTS-KE by the end of the hackathon. This was a good amount of progress considering we started with nothing. However, without implementing NTP we didn’t actually know that our server and client were computing the right thing. That would have to wait for later rounds of testing.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1YlPzBw5H4kOUfQWJfgFXq/486254883416f6509d7abd54ec911ff1/Screen-Shot-2019-10-28-at-12.58.07-PM.png" />
            
            </figure><p>Wireshark during some NTS debugging</p>
    <div>
      <h2>Crypto Week</h2>
      <a href="#crypto-week">
        
      </a>
    </div>
    <p>As <a href="/secure-time/">Crypto Week 2019</a> approached we were busily writing code. All of the NTP protocol had to be implemented, together with the connection between the NTP and NTS-KE parts of the server. We also had to deploy processes to synchronize the ticket encrypting keys around the world and work on reconfiguring our own timing infrastructure to support this new service.</p><p>With a few weeks to go we had a working implementation, but we needed servers and clients out there to test with. But because we only support TLS 1.3 on the server, which had only just entered into OpenSSL, there were some compatibility problems.</p><p>We ended up compiling a chrony branch with NTS support and NTPsec ourselves and testing against time.cloudflare.com. We also tested our client against test servers set up by the chrony and NTPsec projects, in the hopes that this would expose bugs and have our implementations work nicely together. After a few lengthy days of debugging, we found out that our nonce length wasn’t exactly in accordance with the spec, which was quickly fixed. The NTPsec project was extremely helpful in this effort. Of course, this was the day that our <a href="https://sfist.com/2019/05/31/power-outage-hits-soma-china-basin/">office had a blackout</a>, so the testing happened outside in Yerba Buena Gardens.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3JaJ1t9QsDElwkgvBo5Uo/94b282d0f621c730e467495d03a486d2/pasted-image-0-3.png" />
            
            </figure><p>Yerba Buena commons. Taken by Wikipedia user Beyond My Ken. CC-BY-SA</p><p>During the deployment of time.cloudflare.com, we had to open up our firewall to incoming NTP packets. Since the start of Cloudflare’s network existence and because of NTP reflection attacks we had previously closed UDP port 123 on the router. Since source port 123 is also used by clients sometimes to send NTP packets, it’s impossible for NTP servers to filter reflection attacks without parsing the contents of NTP packet, which routers have difficulty doing.  In order to protect Cloudflare infrastructure we got an entire subnet just for the time service, so it could be aggressively throttled and rerouted in case of massive DDoS attacks. This is an exceptional case: most edge services at Cloudflare run on every available IP.</p>
    <div>
      <h2>Bug fixes</h2>
      <a href="#bug-fixes">
        
      </a>
    </div>
    <p>Shortly after the public launch, we discovered that older Windows versions shipped with NTP version 3, and our server only spoke version 4. This was easy to fix since the timestamps have not moved in NTP versions: we echo the version back and most still existing NTP version 3 clients will understand what we meant.</p><p>Also tricky was the failure of Network Time Foundation ntpd clients to expand the polling interval. It turns out that one has to echo back the client’s polling interval to have the polling interval expand. Chrony does not use the polling interval from the server, and so was not affected by this incompatibility.</p><p>Both of these issues were fixed in ways suggested by other NTP implementers who had run into these problems themselves. We thank Miroslav Lichter tremendously for telling us exactly what the problem was, and the members of the Cloudflare community who posted packet captures demonstrating these issues.</p>
    <div>
      <h2>Continued improvement</h2>
      <a href="#continued-improvement">
        
      </a>
    </div>
    <p>The original production version of cfnts was not particularly object oriented and several contributors were just learning Rust. As a result there was quite a bit of unwrap and unnecessary mutability flying around. Much of the code was in functions even when it could profitably be attached to structures. All of this had to be restructured. Keep in mind that some of the best code running in the real-world have been written, rewritten, and sometimes rewritten again! This is actually a good thing.</p><p>As an internal project we relied on Cloudflare’s internal tooling for building, testing, and deploying code. These were replaced with tools available to everyone like Docker to ensure anyone can contribute. Our repository is integrated with Circle CI, ensuring that all contributions are automatically tested. In addition to unit tests we test the entire end to end functionality of getting a measurement of the time from a server.</p>
    <div>
      <h2>The Future</h2>
      <a href="#the-future">
        
      </a>
    </div>
    <p>NTPsec has already released support for NTS but we see very little usage. Please try turning on NTS if you use NTPsec and see how it works with time.cloudflare.com.  As the draft advances through the standards process the protocol will undergo an incompatible change when the identifiers are updated and assigned out of the IANA registry instead of being experimental ones, so this is very much an experiment. Note that your daemon will need TLS 1.3 support and so could require manually compiling OpenSSL and then linking against it.</p><p>We’ve also added our time service to the public NTP pool. The NTP pool is a widely used volunteer-maintained service that provides NTP servers geographically spread across the world. Unfortunately, NTS doesn’t currently work well with the pool model, so for the best security, we recommend enabling NTS and using time.cloudflare.com and other NTS supporting servers.</p><p>In the future, we’re hoping that more clients support NTS, and have licensed our code liberally to enable this. We would love to hear if you incorporate it into a product and welcome contributions to make it more useful.</p><p>We’re also encouraged to see that Netnod has a <a href="https://www.netnod.se/time-and-frequency/netnod-launch-one-of-the-first-nts-enabled-time-services-in-the-world">production NTS service</a> at nts.ntp.se. The more time services and clients that adopt NTS, the more secure the Internet will be.</p>
    <div>
      <h2>Acknowledgements</h2>
      <a href="#acknowledgements">
        
      </a>
    </div>
    <p>Tanya Verma and <a href="/author/gabbi/">Gabbi Fisher</a> were major contributors to the code, especially the configuration system and the client code. We’d also like to thank Gary Miller, Miroslav Lichter, and all the people at Cloudflare who set up their laptops and home machines to point to time.cloudflare.com for early feedback.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/0pc2IWY3wfq8UQuTPPMAB/2d7651cc321580194ca41bbbb6b3e7e5/tales-from-the-crypto-team_2x--1--1.png" />
            
            </figure> ]]></content:encoded>
            <category><![CDATA[Crypto Week]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">1T4MGuuPm0kE0qsJuGUTw5</guid>
            <dc:creator>Watson Ladd</dc:creator>
            <dc:creator>Pop Chunhapanya</dc:creator>
        </item>
    </channel>
</rss>