<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ricardo Iván Vieitez Parra</title>
    <description>The latest articles on DEV Community by Ricardo Iván Vieitez Parra (@corrideat).</description>
    <link>https://dev.to/corrideat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F907614%2F7b97f0a7-01aa-46c9-88f6-7ab6ca42072a.jpeg</url>
      <title>DEV Community: Ricardo Iván Vieitez Parra</title>
      <link>https://dev.to/corrideat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/corrideat"/>
    <language>en</language>
    <item>
      <title>Privacy Pass: The Revolution in CAPTCHA Mitigation and User Privacy</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Fri, 09 Jun 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/privacy-pass-the-revolution-in-captcha-mitigation-and-user-privacy-lae</link>
      <guid>https://dev.to/apeleg/privacy-pass-the-revolution-in-captcha-mitigation-and-user-privacy-lae</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As we traverse the digital frontier, the importance of robust security measures, devised to shield against harmful elements, has become paramount. CAPTCHAs – an acronym for Completely Automated Public Turing test to tell Computers and Humans Apart – serve this purpose, playing a pivotal role in authenticating online interactions. Since their introduction in 2003 by L. von Ahn and colleagues &lt;sup id="fnref:1"&gt;1&lt;/sup&gt;, CAPTCHAs have become a commonplace presence, attempting to discern humans from automated bots, thereby safeguarding digital spaces from malicious activities.&lt;/p&gt;

&lt;p&gt;Since their inception, CAPTCHAs have long been the go-to solution for differentiating between human users and automated bots on online platforms. These tests typically involve tasks like deciphering distorted characters, selecting specific images, or solving puzzles. While CAPTCHAs may have been initially effective in combating bots, they have become increasingly inadequate and burdensome for users in recent years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fW1kIoV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://apeleg.com/blog/posts/2023/06/09/privacypass/06-000_hu968ec01a560b13ca61d1fd287b0aa93a_4836_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fW1kIoV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://apeleg.com/blog/posts/2023/06/09/privacypass/06-000_hu968ec01a560b13ca61d1fd287b0aa93a_4836_352x0_resize_box_3.png" alt="Visual representation of a CAPTCHA showing the word ‘pump’ with distortions" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Picture of an early CAPTCHA, as shown in the paper by von Ahn et al.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The rapid growth of the internet, combined with the increasing sophistication of malicious actors, has led to the widespread adoption of CAPTCHAs by countless websites and online platforms. These tests have become the gatekeepers of digital spaces, serving as the first line of defence against automated attacks, fraudulent activities and data breaches.&lt;/p&gt;

&lt;p&gt;By presenting users with challenges that are easy for humans to solve but difficult for machines, CAPTCHAs aim to accomplish two crucial objectives. First, they seek to authenticate human presence, ensuring that real users can access and utilise online resources while maintaining a secure environment. Second, they aim to hinder or altogether prevent malicious bots from infiltrating websites, safeguarding sensitive information, and maintaining the integrity of online interactions.&lt;/p&gt;

&lt;p&gt;In recent times, the prevalence of CAPTCHAs seems to have risen considerably, and it’s not hard to understand why. The growing reliance on digital platforms for various tasks, such as online shopping, social media engagement, and financial transactions, has made them attractive targets for actors seeking to exploit vulnerabilities and gain unauthorised access.&lt;/p&gt;

&lt;p&gt;To keep pace with these evolving threats, CAPTCHAs have been continuously evolving as well. From deciphering distorted text or numbers to identifying specific objects in images or solving logical puzzles, the variety of CAPTCHA types has expanded to offer different levels of difficulty and security. However, these conventional CAPTCHAs are not without their limitations and drawbacks, often leading to frustrating user experiences and accessibility challenges for certain individuals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zYxwh4R6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://apeleg.com/blog/posts/2023/06/09/privacypass/google_recaptcha_demo_hu95f9d259ec2f8324c960069b62ecf876_1018439_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zYxwh4R6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://apeleg.com/blog/posts/2023/06/09/privacypass/google_recaptcha_demo_hu95f9d259ec2f8324c960069b62ecf876_1018439_352x0_resize_box_3.png" alt="Screen capture of a page using reCAPTCHA v2. The challenge shows a grid of pictures and asks the user to select all those containing cars." width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Picture reCAPTCHA version 2, a typical modern CAPTCHA&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Issues with CAPTCHAs
&lt;/h3&gt;

&lt;p&gt;The rise of sophisticated bots armed with advanced algorithms and machine learning techniques has rendered traditional CAPTCHAs significantly less effective. Bots can now solve CAPTCHAs with surprising accuracy, compromising the security of online platforms and leaving them vulnerable to various malicious activities. As a result, the need for a more robust and reliable solution has become paramount.&lt;/p&gt;

&lt;p&gt;Furthermore, traditional CAPTCHAs often lead to a subpar user experience. Users frequently encounter distorted images, complex puzzles, or illegible text, causing frustration and hindering their ability to access the desired online content. Not only does this affect user satisfaction, but it also leads to potential abandonment of platforms, resulting in lost opportunities and revenue.&lt;/p&gt;

&lt;p&gt;There is yet-another concern with CAPTCHAs. Building any system at Internet scale that can with answer with certain certainity: ‘is this a real person?’ is inherently a &lt;em&gt;very&lt;/em&gt; hard problem. Following up with the continuous arms race that occurs between CAPTCHA designers and CAPTCHA solvers is simply beyond the reach of most individuals and organisations.&lt;/p&gt;

&lt;p&gt;In turn, this has lead to the consolidation of CAPTCHA-as-a-Service providers, &lt;em&gt;i.e.&lt;/em&gt;, third party services that offer integrations for embedding CAPTCHAs in our sites and applications. The largest such provider is Google’s reCAPTCHA, advertised the following way: ‘reCAPTCHA is a free service that protects your site from spam and abuse. It uses advanced risk analysis techniques to tell humans and bots apart’.&lt;/p&gt;

&lt;p&gt;The centralized nature of mainstream CAPTCHA systems concentrates vast amounts of user data in the hands of a few entities. This concentration of data power undermines the principles of decentralization and user autonomy, reinforcing the existing power dynamics in the digital landscape. The potential for data misuse or abuse looms large, especially when considering the far-reaching influence these providers possess over individuals’ online experiences.&lt;/p&gt;

&lt;p&gt;These privacy concerns are inherently difficult to address, because the reason that these services are able to work is likely in large part &lt;em&gt;because&lt;/em&gt; of the large amounts of data they collect, which they can analyise and use to make inferences into what looks like typical human interaction and what looks like typical bot behaviour. This point is further reinforced by services like reCAPTCHA v3, that have largely done away with puzzle-solving and instead assign each visitor a score, with minimal or no interaction. Hence, it is probably safe to say that a privacy-friendly CAPTCHA is unlikely to be effective against sophisticated attackers, and that, even if it were, it may very well be difficult for humans to solve.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing Privacy Pass
&lt;/h2&gt;

&lt;p&gt;Cloudflare are a prominent Internet infrastructure company that offer a range of services, including protection against automated attacks. Among their services is a protection feature called ‘Challenge’, that enables website owners to verify human visitors, protecting their sites against automated attacks. The specific factors taken into account when issuing a challenge are unknown and dependent on configuration, but in many cases, it used a CAPTCHA as one of its signals.&lt;/p&gt;

&lt;p&gt;Because a vast swath of the Internet is behind Cloudflare with such challenges enabled, many sites started in practice requiring solving a CAPTCHA on first visit. This was particularly inconvenient for private users, such as those utilising the Tor Browser, who would often need to complete one or several CAPTCHAS for every site visited. ‘Regular’ private users are in many ways indistinguishable from malicious users, which led to the unfortunate result of forcing them to solve a vast number of CAPTCHAS or worse, blocking access entirely.&lt;/p&gt;

&lt;p&gt;Circa 2017, CloudFlare in collaboration with other actors in the industry and academia, developed what came to be known as ‘Privacy Pass’ &lt;sup id="fnref:2"&gt;2&lt;/sup&gt;. In its original form, it would be a browser extension that would allow users to prove their humanity by solving a CAPTCHA, which would result in a special signed token that can later be sent to servers proving that a challenge had been successfully solved.&lt;/p&gt;

&lt;p&gt;The main innovation of Privacy Pass was its ‘blind’ nature. This means that servers cannot link the tokens they sign with the ones redeemed in the future. As a result, users can maintain their privacy without compromising their communication with the server.&lt;/p&gt;
&lt;h2&gt;
  
  
  Moving on and into the browser
&lt;/h2&gt;

&lt;p&gt;As innovative as Privacy Pass may have been, its lack of native browser support in practice limited its ability to take off. Installing a browser extension requires users to take additional steps to download it and configuring it, and that’s not taking into account that they must be aware of it in the first place. Adding an extension is also not always possible due to policy or platform limitations, and, as with all extensions, comes with an increased attack surface.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://datatracker.ietf.org/wg/privacypass/about/" rel="noopener noreferrer"&gt;IETF PrivacyPass working group&lt;/a&gt; are now in the process of standardising the protocols used in PrivacyPass so that it can be natively supported in all devices as a CAPTCHA alternative.&lt;/p&gt;

&lt;p&gt;At a high level, it leverages the existing mechanisms in the HTTP protocol for authentication. When a server requires proof that the user is not automated, is transmits a challenge in the &lt;code&gt;WWW-Authenticate&lt;/code&gt; header, just like it would for any other authentication scheme. It looks something like this: &lt;code&gt;WWW-Authenticate: PrivateToken challenge="&amp;lt;base64url encoded data&amp;gt;", token-key="&amp;lt;base64url encoded data&amp;gt;"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The challenge part is a serialised and base64url encoded representation of the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; struct {
 uint16_t token_type;
 uint16_t issuer_name_length;
 char issuer_name[1..2^16-1];
 uint8_t redemption_context_length;
 char redemption_context[0..32];
 uint16_t origin_info_length;
 char origin_info[0..2^16-1];
 } TokenChallenge;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The TokenChallenge structure as shown in the latest draft of the Privacy Pass HTTP authentication scheme, with some changes to the types used to more closely resemble C syntax.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;issuer_name&lt;/code&gt; field meant to include the hostname of the token issuer, the and the optional &lt;code&gt;origin_info&lt;/code&gt; meant to include the hostname of the party issuing the request, note that there is little space left for including personally identifiable information about the user. The place where a unique identifier could fit is in the optional 32-bit &lt;code&gt;redemption_context&lt;/code&gt; field, which is not visible to the token issuer.&lt;/p&gt;

&lt;p&gt;Once a supporting client receives a challenge, it initiates &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-privacypass-protocol/" rel="noopener noreferrer"&gt;a protocol&lt;/a&gt; with the issuer (as specified in the &lt;code&gt;issuer_name&lt;/code&gt; field), first by requesting the resource at &lt;code&gt;/.well-known/token-issuer-directory&lt;/code&gt; and then requesting a token be issued. The issuer is not provided with the raw value of the &lt;code&gt;TokenChallenge&lt;/code&gt; issued to the client, but rather with a digest of it, meaning that it does not have access to read what little information can be encoded in the request.&lt;/p&gt;

&lt;p&gt;After receiving a token from the issuer, the client relays this value to the origin that requested it using the standard HTTP &lt;code&gt;Authorization&lt;/code&gt; header, for example, like this: &lt;code&gt;Authorization: PrivateToken token="&amp;lt;base64url encoded data&amp;gt;"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The structure of the token is the following, where &lt;code&gt;Nid&lt;/code&gt; and &lt;code&gt;Nk&lt;/code&gt; are fixed integers depending on the &lt;code&gt;token_type&lt;/code&gt; value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; struct {
 uint16_t token_type;
 char nonce[32];
 char challenge_digest[32];
 char token_key_id[Nid];
 char authenticator[Nk];
 } Token;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The Token structure as shown in the latest draft of the Privacy Pass HTTP authentication scheme, with some changes to the types used to more closely resemble C syntax.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The origin requesting the token must verify that the &lt;code&gt;authenticator&lt;/code&gt; field includes a valid signature over the entire value of the token, not including the &lt;code&gt;authenticator&lt;/code&gt; itself (&lt;em&gt;i.e.&lt;/em&gt;, the first 66 + &lt;code&gt;Nid&lt;/code&gt; bytes) and that the key ID identified by the &lt;code&gt;token_key_id&lt;/code&gt; is valid.&lt;/p&gt;

&lt;p&gt;This approach is deceivingly simple and yet tremendously powerful, because it enables providing an often required facility (closing off certain resources to automated requests) in a privacy-friendly manner that does not leak information about the user, and in a way that is also resistant to correlation attacks by the issuer. What is more, by implementing it as a standard using existing authentication mechanisms as building blocks, it is possible to support this feature while providing graceful degradation for clients that do not support the standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  When and where can I use this?
&lt;/h2&gt;

&lt;p&gt;Although the standard has not been finalised, it is already used in the wild and it can be used right now. &lt;a href="https://developer.apple.com/news/?id=huqjyh7k" rel="noopener noreferrer"&gt;Apple announced support for PATs&lt;/a&gt; in June last year in iOS 16 and macOS Ventura. It requires, however, being logged in at the device level to iCloud. As the specification is finalised, it is likely that other vendors will include support for the standard.&lt;/p&gt;

&lt;p&gt;PATs are already being used by CloudFlare, for example for clients using &lt;a href="https://blog.cloudflare.com/eliminating-captchas-on-iphones-and-macs-using-new-standard/" rel="noopener noreferrer"&gt;‘managed challenges’&lt;/a&gt; or using the &lt;a href="https://blog.cloudflare.com/turnstile-private-captcha-alternative/" rel="noopener noreferrer"&gt;Turnstile&lt;/a&gt; service. Likewise, the feature is available to &lt;a href="https://www.fastly.com/blog/private-access-tokens-stepping-into-the-privacy-respecting-captcha-less" rel="noopener noreferrer"&gt;Fastly&lt;/a&gt; customers.&lt;/p&gt;

&lt;p&gt;However, you do not need to entirely rely on a third-party service to use PATs, and we have developed an open source JavaScript library, &lt;a href="https://github.com/ApelegHQ/ts-privacypass" rel="noopener noreferrer"&gt;PrivacyPass&lt;/a&gt;, also &lt;a href="https://www.npmjs.com/package/@apeleghq/privacypass" rel="noopener noreferrer"&gt;available on NPM&lt;/a&gt; to support issuing PAT challenges and redeeming tokens. The only, but crucial, part missing is the issuer. For this, you’ll need to use an existing open one, like the ones operated by Cloudflare and Fastly, or you can develop your own after gaining access to Apple’s attester service.&lt;/p&gt;

&lt;h2&gt;
  
  
  How will this not lead more centralisation?
&lt;/h2&gt;

&lt;p&gt;The problem at heart, thwarting automation and automated attacks, is a difficult one to solve anonymously and at scale, and it is not surprising that existing solutions prior to PATs, like CAPTCHA services, require data collection to tell ‘good’ and ‘bad’ users apart. What is perplexing is that a solution that purportedly addresses the issue privately requires a specific brand of devices and being signed in to the vendor’s account.&lt;/p&gt;

&lt;p&gt;This is unfortunate but not unsalvageable. For one, the PrivacyPass protocols do not mandate any particular vendor and is intended and easy for several and parties to perform the attestation part.&lt;/p&gt;

&lt;p&gt;Then, there is the issue of why there needs to be an attestation at all, which introduces a bottleneck and closes off the protocol. The reason for requiring attestations is that without a trusted third party vouching for a particular user, it is impossible to enforce any system against automation. In particular, with self-attestation, an attacker can simply mint as many tokens as they desire, and then a few more.&lt;/p&gt;

&lt;p&gt;We have explored some alternatives, such as Proof of Work, that would obviate the need for ’trusted’ parties. The main downside of these alternative approaches, even after ignoring the potential environmental concerns of ‘wasting power’, is simply that compute power is &lt;em&gt;too cheap&lt;/em&gt;. Let’s do some simple calculations to drive this point home. Let’s say that we want to build a system to prevent spam, and that a cost of just 1 cent would be enough to deter spammers. Hence, we need to implement a proof of work system where producing a proof costs at least 1 cent. Let’s say that a spammer can get a server for $100 per month (likely an inflated number, and the server could in fact cost far less), which comes down to shy of 0.004 &lt;em&gt;cents&lt;/em&gt; per second of server time. Therefore, to have a proof of work system that expends the equivalent of 1 cent, we’d need some algorithm that uses up around 250 seconds to construct a proof, or over 4 minutes. Such long-running proof of work would likely be unacceptable in any real-world scenario.&lt;/p&gt;

&lt;p&gt;Going back to attestations, we believe that they can be done in an environment that fosters competition, remains privacy friendly and avoids vendor lock-in. For better or for worse, most consumer hardware these days comes equipped with some form of trusted hardware, such as a TPM, that could be leveaged to produce the rate limited tokens required for this protocol, without any changes that compromise privacy from the way those devices work today. As an alternative, external modules (such as a cheap USB dongle) could be made specifically for this purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing remarks
&lt;/h2&gt;

&lt;p&gt;We have explored the innovative solution known as PrivacyPass and its potential to revolutionise the way we approach CAPTCHA-related challenges. We began by examining the limitations and drawbacks of traditional CAPTCHAs, acknowledging their impact on user experience and their vulnerability to automated attacks. This led us to the introduction of PrivacyPass, a cutting-edge approach that combines cryptographic techniques with user-centric design principles.&lt;/p&gt;

&lt;p&gt;PrivacyPass offers several advantages over traditional CAPTCHAs, most notably in terms of user experience. By generating tokens that vouch for a user’s human identity, PrivacyPass eliminates the need for repetitive CAPTCHA-solving tasks, allowing users to access online content swiftly and effortlessly. Moreover, the cryptographic proof systems employed by PrivacyPass provide enhanced security against automated attacks, ensuring a higher level of protection.&lt;/p&gt;

&lt;p&gt;While PrivacyPass presents an innovative and promising solution, it is important to address potential concerns or criticisms that may arise. Most notably, PrivacyPass is reliant on remote attestation, which shuts off users that do not have or do not desire hardware with such capabilities.&lt;/p&gt;

&lt;p&gt;Looking ahead, the field of CAPTCHA mitigation is ripe with possibilities for future developments and improvements. As technology advances, we can expect further refinements in the design and implementation of PrivacyPass and other similar solutions. Continued collaboration between researchers, industry leaders, and privacy advocates will undoubtedly lead to advancements that strike a balance between security, user experience and privacy.&lt;/p&gt;

&lt;p&gt;In conclusion, PrivacyPass represents a significant step forward in the world of mitigation of automated threats. By prioritising user experience, security, and privacy, PrivacyPass offers an elegant solution to the challenges faced by traditional CAPTCHAs. With real-world applications already implemented by leading organizations, it is clear that PrivacyPass is shaping the landscape of online security. As we move forward, we eagerly anticipate the continued progress and evolution of CAPTCHA mitigation techniques, paving the way for a safer, more user-friendly online experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In an era where online security and user privacy are paramount, it is crucial to find innovative solutions that strike a balance between protecting sensitive information and ensuring a seamless user experience. Throughout this blog post, we have delved into the world of CAPTCHA-related challenges and explored the remarkable solution known as PrivacyPass.&lt;/p&gt;

&lt;p&gt;PrivacyPass offers a unique approach to combating the limitations and drawbacks of traditional CAPTCHAs. By leveraging cryptographic techniques and user-centric design principles, it revolutionises the way we authenticate human users online. By generating Private Access Tokens that vouch for a user’s human identity, PrivacyPass not only improves user experience by eliminating repetitive CAPTCHA-solving tasks but also enhances security by mitigating automated attacks.&lt;/p&gt;

&lt;p&gt;As we conclude, it is essential to recognize the significance of PrivacyPass in the broader context of online security. By adopting PrivacyPass, organisations can create a safer and more user-friendly online environment. Users can enjoy a streamlined browsing experience while knowing that their privacy is protected. PrivacyPass has already garnered attention and adoption from prominent organisations, demonstrating its effectiveness and potential impact.&lt;/p&gt;

&lt;p&gt;We encourage readers to explore PrivacyPass further and consider its adoption as a viable solution to CAPTCHA-related challenges. By implementing PrivacyPass, organizations can enhance their security measures while improving the user experience. Stay updated on the latest developments in this field, as ongoing research and advancements will continue to shape the landscape of CAPTCHA mitigation.&lt;/p&gt;

&lt;p&gt;In conclusion, PrivacyPass represents a significant advancement in the pursuit of robust online security and user privacy. By recapitulating the importance of online security, emphasizing the role of PrivacyPass in improving user experience, and encouraging its adoption, we can collectively strive for a safer, more user-centric online world.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;L. von Ahn, M. Blum, N. J. Hopper, and J. Langford, “CAPTCHA: Using hard ai problems for security”, &lt;em&gt;Lecture Notes in Computer Science&lt;/em&gt;, pp. 294–311, 2003. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A. Davidson, I. Goldberg, N. Sullivan, G. Tankersley, and F. Valsorda, “Privacy pass: Bypassing internet challenges anonymously” &lt;em&gt;Proceedings on Privacy Enhancing Technologies&lt;/em&gt;, vol. 2018, no. 3, pp. 164–180, 2018. ↩︎&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Understanding Identity and Access Management (IAM)</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Wed, 05 Apr 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/understanding-identity-and-access-management-iam-15hk</link>
      <guid>https://dev.to/apeleg/understanding-identity-and-access-management-iam-15hk</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Identity and Access Management (often shortened as IAM or IdM) consists of the set of frameworks, policies and practices that ensure the correct users have access to the right resources in a given system or collection of systems. Almost any system with multiple users will benefit from or require IAM, even more so systems that need limited access to certain parts, actions or resources.&lt;/p&gt;

&lt;p&gt;IAM typically comprises two parts, the &lt;em&gt;identity&lt;/em&gt; (or authentication, sometimes shortened &lt;em&gt;authn&lt;/em&gt;) and &lt;em&gt;access control&lt;/em&gt; (or authorisation, sometimes shortened &lt;em&gt;authz&lt;/em&gt;). Authentication responds to the question of &lt;em&gt;‘who?’&lt;/em&gt; and refers to the process used to identify a specific user (for example, using a username and password combination), and authorisation answers the question of &lt;em&gt;‘is this allowed?’&lt;/em&gt; and represents the policies that determine whether someone may perform a specific action or access a particular resource.&lt;/p&gt;

&lt;p&gt;Consider a simple message board system used for internal announcements within an organisation. The &lt;em&gt;identity&lt;/em&gt; part of IAM may be fulfilled by prompting users (likely employees) for a username and password. Once users log in, they may have different &lt;em&gt;roles&lt;/em&gt;, which define how to interact with the system and determine the &lt;em&gt;access control&lt;/em&gt; part. For example, users may be divided into viewers (who can only read posted announcements), editors (who can read announcements as well as publish new announcements and edit and delete existing ones) and administrators (who can do all that editors can do as well as change the role assigned to other users).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why IAM is important
&lt;/h2&gt;

&lt;p&gt;Imagine a scenario where a company has a database of its clients’ details, including personal and financial information. If that database falls into the wrong hands, it could spell disaster for the company and its clients. For instance, the attackers could use the information to commit fraud, tarnish the company’s reputation, or cause financial loss. This is where IAM comes in; it helps prevent such scenarios by ensuring that only the right individuals can access the system and its resources.&lt;/p&gt;

&lt;p&gt;IAM achieves this by identifying users and their roles, authenticating their identity, and authorising them to access resources and services that are relevant to their roles. It is important to note that IAM is not only about security but also helps maintain compliance, reduce risk, and increase productivity.&lt;/p&gt;

&lt;p&gt;Because IAM plays such a central role in systems and organisations, implementing them correctly and efficaciously can be incredibly challenging, commanding specialist skillsets, a deep understanding of the business domain, best security practices and intimate knowledge of the systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;Authentication is the process of verifying the identity of a user before granting access to a system. The identity could be validated using various methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication methods
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Username and password
&lt;/h4&gt;

&lt;p&gt;Passwords are by far the most common method of authentication, where the user provides a unique username and a password, and these credentials are then validated against the system’s records.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EF2NQSQF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/username-and-password-authn_hud37c61987d93166463147cb7d33d8284_42595_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EF2NQSQF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/username-and-password-authn_hud37c61987d93166463147cb7d33d8284_42595_352x0_resize_box_3.png" alt="Screen capture of a username and password slog-on prompt" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Username and password is a common authentication method for many applications. For example, it is the default method for establishing a session in many operating systems, as shown in this Windows Server 2003 log-on prompt.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This method is the most widely used authentication method due to its low entry barrier, ease of implementation, and convenience for users, as passwords are straightforward to use, do not require any additional hardware or software and can be easily changed if needed.&lt;/p&gt;

&lt;p&gt;However, the use of password authentication has several disadvantages. Passwords can be easily compromised through brute force attacks, where attackers use automated software to try numerous password combinations until they find the correct one. Users also tend to choose weak passwords, such as common words or easily-guessable patterns, which attackers can easily crack. Furthermore, users often reuse the same password across multiple accounts, which increases the risk of a security breach.&lt;/p&gt;

&lt;p&gt;Moreover, several steps must be taken to prevent passwords from being compromised when implementing password authentication. These steps include using encrypted connections and other general good network and operation practices to prevent interception during transmission, rate-limiting to prevent guessing by attackers, and proper password storage methods like hashing and salting.&lt;/p&gt;

&lt;h4&gt;
  
  
  Magic links
&lt;/h4&gt;

&lt;p&gt;This authentication method involves sending a one-time link to the user’s email address or phone number, which they then open to gain access. Magic links can be a more convenient authentication method, especially for users who may forget their passwords, and avoids the issue of password management. However, the link could be intercepted or forwarded to an unauthorised user. Thus an attacker could gain access to the system, making it a relatively weak authentication method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1V6ON6zN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/magiclink-authn_hu430261b0120c9a7170a107b29d44e8e3_73042_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1V6ON6zN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/magiclink-authn_hu430261b0120c9a7170a107b29d44e8e3_73042_352x0_resize_box_3.png" alt="Screen capture of an email containing a magic link" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Magic links are a relatively low-friction authentication method. A link is sent, typically by email or SMS, that when opened automatically signs the user on.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Cryptographic authentication
&lt;/h4&gt;

&lt;p&gt;Cryptographic authentication is a passwordless authentication method that uses cryptography to establish trust between the user and the server. Traditionally, this is done with digital certificates, also known as client certificates, issued to users and stored on their devices. When the user attempts to access a resource, a cryptographic protocol is run between the server and the user, ensuring that the user is whom they claim to be and possesses the private key associated with the certificate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uWc-mqWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/client-certificate-authn_hu73bc519bf0e8d2091c63cddf7414547f_63572_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uWc-mqWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/client-certificate-authn_hu73bc519bf0e8d2091c63cddf7414547f_63572_352x0_resize_box_3.png" alt="Screen capture of a client certificate sign-on prompt" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Client certificates are a high-security authentication method that has seen relatively low adoption.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While cryptographic authentication has been used for a long time, it has been challenging to implement on a large scale because of the complexity of managing the necessary infrastructure. The administration of certificates, certificate revocation and key management can be difficult and time-consuming, leading to higher development and operation costs than other methods, such as passwords, and potential security risks.&lt;/p&gt;

&lt;p&gt;Newer approaches, such as FIDO and WebAuthn, have addressed these challenges of cryptographic authentication by using methods that do not require that the verifying party operate or maintain their own key infrastructure. The private key is typically stored on a hardware device, such as a USB key or a TPM on the user’s device, and a cryptographic protocol is defined to allow servers to validate identities depending on these keys.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7Tandvih--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/webauthn-authn_hu4c42eb82991d1a7499b7299f4238614c_142433_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Tandvih--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/webauthn-authn_hu4c42eb82991d1a7499b7299f4238614c_142433_352x0_resize_box_3.png" alt="Screen capture of a WebAuthn sign-on prompt" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;WebAuthn is a newer approach to cryptographic authentication that commonly uses operating system features and hardware keys to verify identity.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Multi-Factor Authentication (MFA)
&lt;/h4&gt;

&lt;p&gt;Multi-Factor Authentication (MFA) requires users to provide more than one form of identification to access a system. Each form of identification is referred to as a &lt;em&gt;factor&lt;/em&gt; and can fall under three categories: &lt;em&gt;knowledge&lt;/em&gt; or something you know (e.g., a password), &lt;em&gt;possession&lt;/em&gt; or something you have (e.g., a physical token or a mobile device) and &lt;em&gt;inherence&lt;/em&gt; or something you are (e.g., biometric data like fingerprints).&lt;/p&gt;

&lt;p&gt;MFA combines two or more of these factors to increase security. For example, a user may be required to enter a password (something they know) and use a physical token (something they have) to gain access to a system. Alternatively, users may be asked to use their fingerprint (something they are) and enter a one-time password (something they have) sent to their mobile phone.&lt;/p&gt;

&lt;p&gt;Some common examples of MFA include biometric authentication (such as fingerprints or facial recognition), one-time passwords (OTP) sent via SMS or a mobile app, smart cards, physical tokens, and push notifications to a mobile device. Overall, MFA provides an extra layer of security that can significantly reduce the risk of unauthorised access to a system.&lt;/p&gt;

&lt;p&gt;Using multiple factors makes it more difficult for attackers to gain unauthorised access to a system, even if they obtain one of the factors (such as a password). Some factors (e.g., cryptographic keys) additionally support phishing-resistant methods like scoped credentials. These are designed to work only on the intended system and cannot be used elsewhere, preventing phishing attacks where attackers attempt to trick users into providing their log-in credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation options
&lt;/h3&gt;

&lt;p&gt;The implementation of authentication is application-dependent and varies based on business considerations. Three main methods to implement authentication are per-system authentication, dedicated authentication services, and Single Sign-On (SSO) and federated identity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Per-system authentication
&lt;/h4&gt;

&lt;p&gt;Per-system authentication is where applications manage their own authentication, authentication methods, and user database. This approach can be simpler for developers because it does not require knowledge of the application’s environment and is more straightforward for small organisations because no additional infrastructure is needed. However, it can be challenging to scale as it requires managing user databases across many systems and enforcing policies. Furthermore, users needing access to multiple systems may need help navigating this authentication method.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dedicated authentication services
&lt;/h4&gt;

&lt;p&gt;Dedicated authentication services are a popular method in which a centralised service is responsible for authenticating users, and various applications can delegate authentication to this service. This approach avoids the challenges of managing users centrally and ensuring consistent security practices across multiple applications, leading to a better experience both for system administrators and users. Additionally, using dedicated authentication services reduces the attack surface area that comes with individual applications needing to implement authentication.&lt;/p&gt;

&lt;p&gt;Various dedicated authentication services are available, ranging from commercial options like &lt;a href="https://www.okta.com" rel="noopener noreferrer"&gt;Okta&lt;/a&gt; and &lt;a href="https://azure.microsoft.com/en-us/products/active-directory" rel="noopener noreferrer"&gt;Azure Active Directory&lt;/a&gt; to open-source solutions like &lt;a href="https://www.keycloack.org" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt; and &lt;a href="https://www.freeipa.org/page/Main_Page" rel="noopener noreferrer"&gt;FreeIPA&lt;/a&gt;. These services typically provide features such as multi-factor authentication, user management, and access controls and can integrate with various applications using standards like &lt;a href="https://openid.net/connect/" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; and &lt;a href="https://www.oasis-open.org/standard/saml/" rel="noopener noreferrer"&gt;SAML 2.0&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Single Sign-On (SSO) and federated identity
&lt;/h4&gt;

&lt;p&gt;Single Sign-On (SSO) and federated identity are similar and sometimes synonymous with dedicated authentication services. The difference is that SSO typically refers to the widespread use of a central authentication service within an organisation. On the other hand, a federated identity allows users to access systems across different organisations using a single set of credentials.&lt;/p&gt;

&lt;p&gt;SSO and federated identity may be combined. For example, user management may be entirely outsourced (using an external provider with their own user database), and likewise, organisations may make their authentication service available to other external systems. An example is social media log-in, which allows independent services to delegate validation of users’ identities to a social media network.&lt;/p&gt;

&lt;p&gt;These methods are more convenient for users since they only need to remember one set of credentials but they might require more infrastructure. However, the benefits of SSO and federated identity will typically greatly outweigh the additional infrastructure required, as they provide a better user experience and improve security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorisation
&lt;/h2&gt;

&lt;p&gt;Authorisation is the process of granting or denying access to a resource. It determines what a user can do or what resources they can access once they have been authenticated and plays a critical role in securing resources and ensuring that only authorised parties have access to sensitive information or functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorisation strategies
&lt;/h3&gt;

&lt;p&gt;As for authentication, there are several ways to implement authorisation, and the best strategy is highly contextual, depending on the environment, business needs and nature of the systems in question. Some of the more common strategies are discussed below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Role-Based Access Control (RBAC)
&lt;/h4&gt;

&lt;p&gt;Role-Based Access Control (RBAC) is a widely used authorisation strategy that involves assigning roles to users based on their responsibilities or job functions. Each role is associated with a set of permissions that define what resources a user can access or what actions they can perform. This approach is particularly useful in organisations with many users because it simplifies management and scalability.&lt;/p&gt;

&lt;p&gt;For example, consider a curling club management application that has different roles, such as players, coaches, and administrators. Players can view their team’s schedules and update their availability for upcoming games, while coaches can also view player statistics and performance metrics. Administrators can manage user accounts but cannot access player-specific data or modify game results. Using RBAC, the application can ensure that each user can access only the information and functions relevant to their role within the club.&lt;/p&gt;

&lt;h4&gt;
  
  
  Policy-Based Access Control (PBAC)
&lt;/h4&gt;

&lt;p&gt;Policy-Based Access Control (PBAC) is an authorisation strategy that uses policies to govern access. Policies are rules that define what actions a user can perform based on their attributes, such as job title, department, or location. This approach provides greater granularity than RBAC and offers more flexibility. However, it can be more complex to manage.&lt;/p&gt;

&lt;p&gt;A travel agency could use PBAC to control access to their booking system. For instance, they could have policies such as ‘Only travel agents with a certain level of certification can book international flights’ or ‘Only users in the sales department can offer discounts to customers’.&lt;/p&gt;

&lt;h4&gt;
  
  
  Attribute-Based Access Control (ABAC)
&lt;/h4&gt;

&lt;p&gt;Attribute-Based Access Control (ABAC) is an authorisation strategy that uses attributes to determine access. Attributes can be any characteristic that can be used to identify users, such as user role, job title, department, location, time of day, and more. ABAC is highly flexible and can accommodate complex environments and scenarios, making it a popular choice for many organisations.&lt;/p&gt;

&lt;p&gt;For instance, consider a tattoo parlour that uses ABAC to grant access to its online booking system. The system may allow customers with a minimum age of 18 years and those with valid identification to book an appointment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Context-Aware Access Control (CAAC)
&lt;/h4&gt;

&lt;p&gt;Context-Aware Access Control is an authorisation strategy that uses various contextual factors to grant or deny access to resources. The factors may include the user’s location, device, network, time of day, and activity history. By considering these contextual factors, the system can detect anomalous user behaviour and prevent potential cyber-attacks or data breaches. This strategy is often used with machine learning to help identify unlikely behaviours or represent high-risk scenarios.&lt;/p&gt;

&lt;p&gt;For example, a grocery store might use context-aware access control to prevent unauthorised access to sensitive information and protect the store’s business operations by ensuring that only authorised personnel can access the inventory management system. The system may allow employees to access the system only during business hours, from the store’s Wi-Fi network, using a company-issued device. If an employee tries to access the system from outside the store or at an unusual time, the system can deny access or trigger an additional authentication step, such as a one-time password or biometric verification.&lt;/p&gt;

&lt;h4&gt;
  
  
  Access Control Lists (ACLs)
&lt;/h4&gt;

&lt;p&gt;Access Control Lists (ACLs) are a commonly used authorisation strategy in which a list of users and the resources they are allowed to access is created. ACLs are typically applied to individual files or directories in a system, making them effective in managing access to specific resources rather than entire systems. This approach is well-suited for small-scale organisations where access to resources is limited to a few users or groups of users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QJ73ypuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/acl-authz_hua7929366f93c1a22178cc599a01dd27e_49285_352x0_resize_box_3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QJ73ypuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://exact.realty/blog/posts/2023/04/05/introduction-to-iam-and-its-ramifications/acl-authz_hua7929366f93c1a22178cc599a01dd27e_49285_352x0_resize_box_3.png" alt="Screen capture of security settings for a file showcasing advanced permissions, a form of ACLs" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;ACLs are often used for individual files or directories in a system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For instance, ACLs can be applied to patient records to control access in a doctor’s practice to ensure that only authorised personnel have access to patient information, which is critical in maintaining patient confidentiality and complying with legal regulations. The doctor, nurses and receptionist may have different access levels, with the attending doctor having full access, other doctors having read-only access, the nurses having access to certain information, and the receptionist having no access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing authorisation
&lt;/h3&gt;

&lt;p&gt;After choosing an authorisation strategy, the next step is implementing it in the relevant systems.&lt;/p&gt;

&lt;p&gt;Similar to authentication, authorisation can be handled internally by each application through internal rules, or it can be delegated to an external service, which may be internally managed or outsourced.&lt;/p&gt;

&lt;p&gt;Implementing authorisation can be complex, particularly in large and distributed systems. It requires careful consideration of the system’s security requirements, as well as the needs of the users and applications that will be accessing the system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Internal rules
&lt;/h4&gt;

&lt;p&gt;One approach to implementing authorisation in an application is by using internal rules. This method involves creating rules directly within the application and determining which users are granted access to specific resources. This approach suits small organisations with limited resources or simple systems requiring less infrastructure. However, as the size and complexity of an organisation’s IT environment grow, the management of internal rules becomes increasingly complex, time-consuming, and error-prone.&lt;/p&gt;

&lt;p&gt;While the benefits of implementing internal rules include simplified management and implementation without needing external services, there are drawbacks. The risk of inconsistent or poorly enforced internal rules is a significant concern that can lead to security vulnerabilities. As such, organisations need to periodically review and update their internal practices to ensure that they align with the organisation’s security needs.&lt;/p&gt;

&lt;p&gt;Examples of internal rules include row-based security, which restricts access to specific rows within a database, and ‘Gates’ in frameworks like Laravel, which enable developers to define custom authorisation logic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Delegated authorisation
&lt;/h4&gt;

&lt;p&gt;Delegated authorisation is the practice of delegating authorisation decisions to a purpose-built authorisation server rather than having each application manage its own rules. This server administers and enforces authorisation policies across multiple applications, services, and resources.&lt;/p&gt;

&lt;p&gt;When applications require access to protected resources or data, they must request authorisation from the server. The server evaluates the request based on the authorisation policies in place, and either approves or denies it. This approach simplifies the management of authorisation policies across multiple applications and provides a centralised point of control and visibility over access to resources.&lt;/p&gt;

&lt;p&gt;Delegated authorisation also helps enforce a zero-trust security model, where all access requests must be authenticated and authorised, regardless of the user, application or request origin. Zero-trust models can, in turn, reduce the risk of data breaches and other security incidents.&lt;/p&gt;

&lt;p&gt;Examples of delegated authorisation protocols include &lt;a href="https://oauth.net/2/" rel="noopener noreferrer"&gt;OAuth 2.0&lt;/a&gt; and &lt;a href="https://www.oasis-open.org/standard/saml/" rel="noopener noreferrer"&gt;SAML 2.0&lt;/a&gt;. These widely adopted protocols provide a framework for delegating authorisation decisions to an external server.&lt;/p&gt;

&lt;h5&gt;
  
  
  Delegation authorisation patterns
&lt;/h5&gt;

&lt;p&gt;API gateways are an example of a pattern that can manage authorisation. Acting as a layer between the user and the application, an API gateway handles both authentication and authorisation. API gateways can control access to specific resources within an application or multiple applications. Examples of such services include &lt;a href="https://konghq.com/products/kong-gateway" rel="noopener noreferrer"&gt;Kong Gateway&lt;/a&gt; and &lt;a href="https://apisix.apache.org/" rel="noopener noreferrer"&gt;Apache APISIX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Query-based services are another example of a pattern for managing authorisation. These offer a service that applications can query to determine whether to allow or block access to a resource or operation. An example of this approach is using &lt;a href="https://www.ory.sh/keto/" rel="noopener noreferrer"&gt;ORY Keto&lt;/a&gt;, an implementation of &lt;a href="https://www.usenix.org/system/files/atc19-pang.pdf" rel="noopener noreferrer"&gt;Google Zanzibar&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, Identity and Access Management (IAM) is a crucial aspect of modern business operations. IAM ensures that the correct users have access to the right resources, which is essential for security, compliance, and productivity. There are many different authentication and authorisation strategies, each with its benefits and drawbacks. Organisations must carefully choose the strategy that best fits their needs and implement them correctly to maximise effectiveness. Implementing IAM can improve an organisation’s security posture, reduce the risk of data breaches, and increase operational efficiency by supporting business needs.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Opaque IDs: the ultimate protection against enumeration attacks</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Thu, 30 Mar 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/opaque-ids-the-ultimate-protection-against-enumeration-attacks-197g</link>
      <guid>https://dev.to/apeleg/opaque-ids-the-ultimate-protection-against-enumeration-attacks-197g</guid>
      <description>&lt;p&gt;In this post, we’ll discuss two types of attacks, timing attacks and enumeration attacks, which can result in disclosing confidential information to attackers when accessing resources. We’ll then introduce a method to neutralise these attacks using AEAD encryption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why IDs are used
&lt;/h2&gt;

&lt;p&gt;A great many applications involve some sort of information retrieval for interactivity. The information is stored in some type of database and each item or resource that is typically assigned a unique identifier, or ID. This identifier can then be used to refer to that item later on.&lt;/p&gt;

&lt;p&gt;For example, if you have a web application where users can upload photos, you might store each photo’s metadata in a database and assign each row a unique ID. The ID will then be sent in some form to the user, so that when she wants to see the photo the application can retrieve that file by looking up the ID in the database.&lt;/p&gt;

&lt;p&gt;This applies not just to web applications, but rather is a feature of APIs in general. For example, a REST API might provide a user a path like &lt;code&gt;http://api.example/foo/123&lt;/code&gt; to identify a resource of type &lt;code&gt;foo&lt;/code&gt; named &lt;code&gt;123&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How IDs might be exploited to gain access
&lt;/h2&gt;

&lt;p&gt;Disclosing internal information (such as an ID) to users can result in providing them with access to &lt;em&gt;other&lt;/em&gt; information that they are not intended to have access to.&lt;/p&gt;

&lt;p&gt;While the ID in itself might seem like a harmless piece of information (and it usually is, in isolation), it could allow users to make inferences about the system and potentially gain access to private data.&lt;/p&gt;

&lt;h2&gt;
  
  
  German tank problem
&lt;/h2&gt;

&lt;p&gt;The German tank problem gets it name from a statistical problem the Allies faced during World War Ⅱ. The Germans built a lot of tanks, and the Allies wanted to know how many as well as the monthly rate of production. Since the Germans used a sequential numbering system to label the components for each tank they built, when Allies captured one, they could see its serial numbers. By looking at the highest serial number they saw, and applying some statistical analysis, they could effectively estimate how many tanks the Germans had built.&lt;/p&gt;

&lt;p&gt;This problem can be very relevant to information security. Suppose you are using sequential IDs for the photo upload application mentioned earlier and that each photo is given a sequential ID (e.g., &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, etc.). Then, by just observing the IDs being used, an attacker could gain information about the number of photos stored in the system as well as the rate at which photos are uploaded. Whether this is a concern or not depends, of course, on the specifics of the situation. Most likely, the information in this particular example is of little value, but it might be helpful to, say, a potential competitor considering building a similar application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enumeration attacks
&lt;/h2&gt;

&lt;p&gt;While the German tank problem shows how our choice of identifiers might non-public reveal information to an adversary, many or even most applications are interactively accessible to adversaries. This interactivity allows attackers to carry out another attack that can give them the same information directly, without the need to guess: an enumeration attack.&lt;/p&gt;

&lt;p&gt;An enumeration attack is a type of attack where an attacker attempts to gather information about a system by systematically trying different values for a particular parameter. In the context of IDs, an enumeration attack might involve an attacker trying a large number of possible IDs to determine which IDs exist and which do not. Once the attacker has determined which IDs exist, they can potentially use that information to carry out further attacks.&lt;/p&gt;

&lt;p&gt;Enumeration attacks can be particularly effective when the IDs being used follow some kind of sequence or are represented in a relatively small set and are part of a publicly available URL, as it is trivial to automate the process of trying a large number of possible IDs.&lt;/p&gt;

&lt;p&gt;For example, consider the previous API with an endpoint like &lt;code&gt;http://api.example/foo/:id&lt;/code&gt;, where &lt;code&gt;:id&lt;/code&gt; is a numeric and sequential ID. It is trivial for an actor to try many requests, such as &lt;code&gt;http://api.example/foo/1&lt;/code&gt;, &lt;code&gt;http://api.example/foo/2&lt;/code&gt;, &lt;code&gt;http://api.example/foo/99&lt;/code&gt;, etc., and evaluate the response.&lt;/p&gt;

&lt;p&gt;The impact of enumeration attacks depends on the application in question. In many situations, successfully exploiting an enumeration vulnerability will only provide information about which resources are valid, making it similar to the German tank problem. However, in combination with additional vulnerabilities in the application, especially &lt;a href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/" rel="noopener noreferrer"&gt;broken access control&lt;/a&gt;, it could have farther reaching implications, such as leaking confidential information, including customer data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;Enumeration attacks can be avoided or mitigated by addressing the factors that make them possible: small sets and predictable values. A common solution is to use &lt;a href="https://www.ietf.org/rfc/rfc4122.html#section-4.4" rel="noopener noreferrer"&gt;UUIDs version 4&lt;/a&gt;, which consist of 122 random bits and are therefore impossibly impractical to guess or enumerate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timing attacks
&lt;/h2&gt;

&lt;p&gt;A timing attack is a type of side-channel attack where an attacker attempts to gain information about a system by measuring the amount of time it takes to perform certain operations. In the context of IDs, a timing attack might involve an attacker trying to guess a resource’s ID by trying a large number of possible IDs and measuring the time it takes for the system to respond. By measuring the time it takes to receive a response, the attacker can potentially learn information about the system, such as which IDs exist and which do not.&lt;/p&gt;

&lt;p&gt;Timing attacks can be a way to extract information even from systems that implement proper access control. Consider the endpoint from earlier: &lt;code&gt;http://api.example/foo/:id&lt;/code&gt;. Let’s say that IDs follow a simple numeric sequence (i.e., &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, etc.) and that the no path IDs is publicly accessible. Our adversary is a user to the system with legitimate access to the resources with an ID of &lt;code&gt;11&lt;/code&gt; and &lt;code&gt;17&lt;/code&gt;, and no access to any other resources. How could this adversary carry out an enumeration attack?&lt;/p&gt;

&lt;p&gt;Because of difficult or impossible to avoid circumstances when developing such an application, the endpoint will likely take different time to respond depending on the result. This information, if consistent, can be revealing of the internal state. Our attacker could proceed to make queries against the endpoint to all resources, for example, from 1 to 100 000. The measured response times could look like something like what is shown in the table below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID range&lt;/th&gt;
&lt;th&gt;Mean response time (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1–10&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12–16&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18–7 363&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 364–100 000&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Table with mean measured response times for different IDs. Note the difference between various IDs. The IDs the attacker has legitimate access to have a mean response time of about 56ms, whereas the remaining resources have response times of about 50ms for IDs under 7 364 and of about 50ms for higher values.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note that from ID &lt;code&gt;7364&lt;/code&gt; onwards the response time is lower. This information can reveal to the attacker that the system likely contains 7 363 entries.&lt;/p&gt;

&lt;p&gt;Depending on how lookups are carried out, timing information can also be used to identify valid IDs even when they don’t follow a sequence and there is a much larger set of valid IDs (such as UUIDs). This means that the specifics of how data are looked up are important, not just the format of IDs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mitigation
&lt;/h3&gt;

&lt;p&gt;There are several ways to mitigate timing and enumeration attacks. As mentioned earlier, one common solution against enumeration attacks is using random UUIDs instead of sequential IDs. These have a very low probability of being guessed by an attacker. However, UUIDs can be relatively long, which can be a disadvantage in certain contexts, such as when they need to be used in URLs.&lt;/p&gt;

&lt;p&gt;Timing attacks, being a side-channel attack, are impossible to eliminate entirely because so doing would require eliminating all possible side-channels. However, there are ways to practically mitigate them. Ideally, we would write our application so that response times are independent from user-provided data. Since this is impractical, we can practice defence-in-depth and make timing information less useful and more difficult to obtain.&lt;/p&gt;

&lt;p&gt;For example, if we are concerned about enumeration attacks, we might add a MAC or digital signature to IDs, which (1) users cannot readily forge and (2) we can verify before proceeding further with the request.&lt;/p&gt;

&lt;p&gt;The new IDs could look like the original IDs, but with the MAC or signature prepended to it, like this &lt;code&gt;&amp;lt;MAC&amp;gt;.&amp;lt;ID&amp;gt;&lt;/code&gt;. So, the internal resource &lt;code&gt;1&lt;/code&gt; could result in a user-visible ID like &lt;code&gt;53CUR3C0D3.1&lt;/code&gt;, with &lt;code&gt;53CUR3C0D3&lt;/code&gt; being a value that we can verify as corresponding to resource &lt;code&gt;1&lt;/code&gt;, but which is difficult to forge or guess. If we verify this value before handling the request further, an attempt at the timing attack described earlier could instead have resulted in measurements like the following.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID range&lt;/th&gt;
&lt;th&gt;Mean response time (ms)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1–10&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12–16&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18–7 363&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7 364–100 000&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Table with mean measured response times for different IDs after only processing requests with a valid MAC. Note that mean response times are divided into two categories this time. For IDs the attacker has legitimate access to, we see similar, slightly higher, response times of around 60ms. For all other IDs (where an invalid MAC was provided), the response time is of around 32ms.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note that in this case, an attacker does not gain much information besides what they already know (i.e., the representation of resources &lt;code&gt;11&lt;/code&gt; and &lt;code&gt;17&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Encrypted IDs
&lt;/h4&gt;

&lt;p&gt;While a MAC or signature can go to great lengths towards preventing enumeration and timing attacks to learn about valid IDs, the issue arising from the German tank problem, namely, making inferences from observable IDs, remains. In order to mitigate this, we can use encryption to make internal representation of the ID itself opaque to external parties.&lt;/p&gt;

&lt;p&gt;Indeed, we can use various authenticated encryption schemes (e.g., AES-GCM) to hand out users IDs which are both &lt;em&gt;opaque&lt;/em&gt; (they do not allow to infer information about their internal value, structure or representation) and &lt;em&gt;unforgeable&lt;/em&gt; (IDs not generated by us can be detected and rejected).&lt;/p&gt;

&lt;p&gt;However, there are some potential downsides to using this method. One issue is that the encrypted IDs are not human-readable, so it may be difficult for developers to work with these IDs directly. This can make debugging and troubleshooting more challenging.&lt;/p&gt;

&lt;p&gt;Another potential issue is that the overhead involved in encrypting and decrypting IDs can be significant both in terms of computing time and space. This can be a concern particularly in applications where a large number of IDs need to be generated and transmitted or in certain resource-constrained applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example solution in TypeScript
&lt;/h2&gt;

&lt;p&gt;We have developed a small library, &lt;a href="https://www.npmjs.com/package/%40exact-realty/safeid" rel="noopener noreferrer"&gt;@exact-realty/safeid&lt;/a&gt;, that implements the techiques discussed here applied to UUIDs, with the possibility of extending it to other arbitrary ID formats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach taken
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@exact-realty/safeid&lt;/code&gt; uses AES-GCM to produce IDs that are opaque, unforgeable and stable (i.e., the same internal ID will always result in the same encrypted ID).&lt;/p&gt;

&lt;p&gt;To do this, first we provide the library with a secret key that will be used to derive other cryptographic IDs.&lt;/p&gt;

&lt;p&gt;Then, before providing an ID to a user, we encrypt the internal representation. This is a multiple-step process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We derive an &lt;a href="https://www.ietf.org/rfc/rfc2104.html" rel="noopener noreferrer"&gt;HMAC&lt;/a&gt; key from the supplied secret key (this step is carried out before any encryption or decryption operation).&lt;/li&gt;
&lt;li&gt;We use the HMAC key to produce the an IV to be used for the following encryption step, taking the plaintext internal ID as input to the HMAC function. This is the step that ensures that the resulting output is stable.&lt;/li&gt;
&lt;li&gt;We derive an AES256-GCM encryption key from the supplied secret key. In this implementation, we additionally use the IV derived in the previous step an an input to this process, which results in a different encryption key for each ID.&lt;/li&gt;
&lt;li&gt;We proceed to encrypt the supplied internal ID, using the derived IVs and encryption keys.&lt;/li&gt;
&lt;li&gt;We prepend the IV to the resulting encrypted data and encode it using the &lt;a href="https://www.ietf.org/rfc/rfc4648.html#section-5" rel="noopener noreferrer"&gt;base64url&lt;/a&gt; encoding and return this as a result (which for UUIDs results in a 48-byte string).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For decryption, the steps are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We derive an &lt;a href="https://www.ietf.org/rfc/rfc2104.html" rel="noopener noreferrer"&gt;HMAC&lt;/a&gt; key from the supplied secret key (this step is carried out before any encryption or decryption operation).&lt;/li&gt;
&lt;li&gt;We decode the encrypted ID and split it into two parts: the IV and the encrypted data.&lt;/li&gt;
&lt;li&gt;We derive an AES256-GCM decryption key from the supplied secret key. In this implementation, we additionally use the IV, which results in a different decryption key for each ID.&lt;/li&gt;
&lt;li&gt;We decrypt the encrypted ID to obtain the plaintext internal ID.&lt;/li&gt;
&lt;li&gt;With this information, we derive the IV from the plaintext and verify that the IV in the input that we obtained earlier matches what we expect it to be (i.e., the IV that the encryption function would have derived). This step is a sanity check to ensure that the ID has not been tampered with.&lt;/li&gt;
&lt;li&gt;We return the plaintext internal ID, which our application can now use for accessing resources.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>infosec</category>
      <category>encryption</category>
      <category>webdev</category>
      <category>uuids</category>
    </item>
    <item>
      <title>Progressively loading CSR pages</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Tue, 17 Jan 2023 01:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/progressively-loading-csr-pages-5bmi</link>
      <guid>https://dev.to/apeleg/progressively-loading-csr-pages-5bmi</guid>
      <description>&lt;h2&gt;
  
  
  Progressive enhancement
&lt;/h2&gt;

&lt;p&gt;Progressive enhancement is a design philosophy that consists in delivering as much functionality to users as possible, regardless of the manner they may access our system. This ensures that a baseline of content and functionality is available to all users, while a richer experience may be offered under the right conditions. For instance, the website for a newspaper may make the text content of its articles available to all users through HTML markup, while providing interactive media content for users with a capable browser.&lt;/p&gt;

&lt;p&gt;Nowadays, client-side scripting is used in most websites to provide various levels of functionality. Frameworks like React, Angular and Vue.js allow developers to deliver highly interactive experiences, which in turn has made modern rich web applications feasible, such as spreadsheet applications that run completely in the browser. Because of many of the conveniences that they provide, these frameworks are also used for all sorts of websites and not just for those with complex interactivity.&lt;/p&gt;

&lt;p&gt;The principles of progressive enhancement can be applied to all websites, no matter how they are built or what they do. For websites that are open to the public, progressive enhancement is essential to ensure the best possible experience for our users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progressively loading web applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Server-side rendering vs. client-side rendering
&lt;/h3&gt;

&lt;p&gt;A website can be server-side rendered, client-side rendered or use a combination of both approaches.&lt;/p&gt;

&lt;p&gt;When an application is server-side rendered, the server delivers HTML markup with content that is ready for a user to consume. In contrast, an application that is client-side rendered constructs the document presented to users with the help of client-side scripts.&lt;/p&gt;

&lt;p&gt;By default, applications built with modern frameworks will be rendered on the client side, whether the content is static or generated dynamically from external parameters (such as data returned from an API).&lt;/p&gt;

&lt;p&gt;For example, a typical React application may have some HTML like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Example Page&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script
        &lt;/span&gt;&lt;span class="na"&gt;crossorigin&lt;/span&gt;
        &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react%4018/umd/react.production.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script
        &lt;/span&gt;&lt;span class="na"&gt;crossorigin&lt;/span&gt;
        &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react-dom%4018/umd/react-dom.production.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"basic.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the corresponding rendering logic in &lt;code&gt;basic.js&lt;/code&gt;, which could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createrrorElementement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple example will show a page with the text &lt;code&gt;Hello, World!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/Edge-basic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/Edge-basic.png" title="A modern browser will execute the script to render the application, which in this case displays the text  raw `Hello, World!` endraw ." alt="Screen capture showing a simple client-side rendered page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since in this example all of the rendering code depends on client-side scripting, users with an older browser, one that doesn't support scripts or one with scripts disabled will see a blank page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62p564lei1szzsjxrrzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62p564lei1szzsjxrrzv.png" title="The Links2 text-based browser doesn't support scripts and will show a blank page." alt="Screen capture showing a blank page in a text-based browser" width="558" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje5bk1gyktd9krk6myg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje5bk1gyktd9krk6myg5.png" title="The now-depreacted Internet Explorer 11 browser doesn't support modern scripts and will display a blank page." alt="Screen capture showing a blank page in an older browser" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The situation of having a blank page in certain browsers can be avoided by using server-side rendering. Depending on the framework in question, the approach can be different. For React, this can be accomplished with &lt;a href="https://reactjs.org/docs/react-dom-server.html" rel="noopener noreferrer"&gt;&lt;code&gt;ReactDOMServer&lt;/code&gt;&lt;/a&gt;. Following the principles of progressive enhancement, server-side rendering should be used whenever possible or feasible to give users the possibility to use and interact with our page. The advantage of this approach is that client-side scripting can still be used to enhance interactivity and functionaliy if the client supports it. However, server-side rendering might not always be a viable option, depending on what our page is meant to do. For instance, a highly-interactive rich application, like an online image editor or game, may require scripting to provide an adequate experience beyond the capabilities of a statically-generated document.&lt;/p&gt;

&lt;p&gt;Regardless of whether server-side rendering is a viable option for our page, we can follow some principles of progressive enhancement to improve the experience of all users.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Firstly, there is the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; element, which presents content for browsers that do not support or process client-side scripts. We could use this tag to tell our users either that scripts are required and that they should use a different browser or to let them know that some functionality might not be available without scripting.&lt;/p&gt;

&lt;p&gt;We could use the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; to display a message like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
    Scripting must be enabled to use this application.
&lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handling errors
&lt;/h3&gt;

&lt;p&gt;A second consideration is that a client might support scripts but they could result in an error. For example, an older browser might not understand the syntax used in our scripts, like using &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;let&lt;/code&gt; for variables, or it might be that we use some functionality that isn't implemented, such as promises.&lt;/p&gt;

&lt;p&gt;While we could avoid some of these potential errors by other means (like feature detection), for robustness we should implement an error handler that lets users know that an unexpected error occurred so that they can take appropriate action, such as using a different browser or contacting support.&lt;/p&gt;

&lt;p&gt;We can implement this with a separate script that implements an &lt;code&gt;error&lt;/code&gt; event handler. The reason for using a separate script is that we can implement this handler with syntax and features that all browsers are likely to support.&lt;/p&gt;

&lt;p&gt;For example, our error handler could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;errorElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;loadingElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Show some information about the error&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Make the error element visible&lt;/span&gt;
    &lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Hide 'loading' message if an error occurred&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loadingElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;loadingElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a corresponding HTML body with &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;loading&lt;/code&gt; elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
        Scripting must be enabled to use this application.
    &lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Loading...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;An error occurred&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, browsers without client-side scripting will display the message in the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; element, while browsers with scripting will show a 'loading' message indicating that the application is not yet ready (alternatively, this can be the page contents when using server-side rendering) or an error message should some error occur.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mz2z0180bovynuge508.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mz2z0180bovynuge508.png" title="A browser without scripting enabled displays a message indicating that scripting is required." alt="Screen capture showing a browser with scripting disabled" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ty61eh9dd03octwipkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ty61eh9dd03octwipkz.png" title="If an error occurs during script execution, an error message is presented." alt="Screen capture showing an error message" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bgh6jbr4rmi91g6lx1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bgh6jbr4rmi91g6lx1h.png" title="If an error occurs during script execution, an error message is presented, even on a legacy browser." alt="Screen capture showing an error message on a legacy browser" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; attributes
&lt;/h3&gt;

&lt;p&gt;Generally, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; elements block rendering. This means that the page won't be interactive or display content until scripts have loaded. Depending on factors like network speed, this can result in poor user experience because the page will appear slow without indication of what is happening.&lt;/p&gt;

&lt;p&gt;HTML5 introduced the &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; attributes to the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to address this issue. The &lt;code&gt;async&lt;/code&gt; attribute specifies that the script should be fetched in parallel and executed as soon as its contents are available. The &lt;code&gt;defer&lt;/code&gt; attribute is similar, except that it specifies that the script should be executed right after the document has been parsed, but before the &lt;code&gt;DOMContentLoaded&lt;/code&gt; event is fired.&lt;/p&gt;

&lt;p&gt;For scripts that should render the initial contents of the page, as we are discussing, the &lt;code&gt;defer&lt;/code&gt; attribute is the most appropriate, since it'll allow us to progressively enhance the page when possible while still being able to provide some fallback content while scripts are being downloaded and executed.&lt;/p&gt;

&lt;p&gt;We could use a helper function like this in a &lt;code&gt;&amp;lt;script defer&amp;gt;&lt;/code&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Exceptions to throw&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;InvalidOrUnsupportedStateError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// Entry point&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;browserOnLoad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;interactive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The page has already loaded and the 'DOMContentLoaded'&lt;/span&gt;
    &lt;span class="c1"&gt;// event has already fired&lt;/span&gt;
    &lt;span class="c1"&gt;// Call handler directly&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 'DOMContentLoaded' has not yet fired&lt;/span&gt;
    &lt;span class="c1"&gt;// This is what we expect with &amp;lt;script defer&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Remove the event listener to avoid double firing&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Call handler on 'DOMContentLoaded'&lt;/span&gt;
      &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Set an event listener on 'DOMContentLoaded'&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The page has not fully loaded but addEventListener isn't&lt;/span&gt;
    &lt;span class="c1"&gt;// available. This shouldn't happen.&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrUnsupportedStateError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;browserOnLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// code that does client side rendering&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;We can combine all of the techniques presented to load scripts in a way that progressively enhances our page load on each step: first, by presenting users with a message that scripting is necessary, then by displaying a loading message while the application gets ready (and an error message if something goes wrong), followed by a fully loaded application once all scripts have been executed.&lt;/p&gt;

&lt;p&gt;First, we set up the HTML document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Example Page&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;errorElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;loadingElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Show some information about the error&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// Make the error element visible&lt;/span&gt;
            &lt;span class="nx"&gt;errorElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Hide 'loading' message if an error occurred&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loadingElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;loadingElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;display&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"font-size:24pt;background-color:white;color:black"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
            Scripting must be enabled to use this
            application.
        &lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color:blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Loading...
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:none;color:teal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            An error occurred&lt;span class="c"&gt;&amp;lt;!--
        --&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Followed by the &lt;code&gt;app.js&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Exceptions to throw&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;InvalidOrUnsupportedStateError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="c1"&gt;// Entry point&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;browserOnLoad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;interactive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// The page has already loaded and the 'DOMContentLoaded'&lt;/span&gt;
      &lt;span class="c1"&gt;// event has already fired&lt;/span&gt;
      &lt;span class="c1"&gt;// Call handler directly&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 'DOMContentLoaded' has not yet fired&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeEventListener&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Remove the event listener to avoid double firing&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Call handler on 'DOMContentLoaded'&lt;/span&gt;
        &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// Set an event listener on 'DOMContentLoaded'&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// The page has not fully loaded but addEventListener isn't&lt;/span&gt;
      &lt;span class="c1"&gt;// available. This shouldn't happen.&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidOrUnsupportedStateError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to load dependency scripts&lt;/span&gt;
  &lt;span class="c1"&gt;// For simplicity, this assumes all scripts are independent&lt;/span&gt;
  &lt;span class="c1"&gt;// from each other&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;loadScripts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;
          &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crossOrigin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;browserOnLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;loadScripts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://unpkg.com/react%4018/umd/react.production.min.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://unpkg.com/react-dom%4018/umd/react-dom.production.min.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;onerror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>a11y</category>
      <category>web</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Effectively mitigating CSRF</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Mon, 02 Jan 2023 10:40:58 +0000</pubDate>
      <link>https://dev.to/apeleg/effectively-mitigating-csrf-4apk</link>
      <guid>https://dev.to/apeleg/effectively-mitigating-csrf-4apk</guid>
      <description>&lt;h2&gt;
  
  
  What CSRF is
&lt;/h2&gt;

&lt;p&gt;Cross-Site Request Forgery (often shortened to CSRF or XSRF) is a type of attack in which an external site makes a request to another site on behalf of a user without consent. This attack often relies on there being an existing session on the target site, which the attacker hijacks for their own purposes. Traditionally, this attack also relies on cookies (classic CSRF), although a new variant of the attack, called Client-Side CSRF (CSCSRF), is possible on sites that use client-side scripting without appropriate input validation.&lt;/p&gt;

&lt;p&gt;Although any site could potentially become a target for CSRF attacks and should therefore implement appropriate mitigations, some factors that can increase the likelihood of becoming a target are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having a large audience, where it is likely that users are logged in (for example, major social media sites)&lt;/li&gt;
&lt;li&gt;Being a high-value sites where a successful attack is lucrative (for example, sites of financial institutions)&lt;/li&gt;
&lt;li&gt;Offering subdomains to third parties (for example, some blogging platforms and shared hosting services). This is a high-risk scenario because some of the protections implemented in browsers to isolate origins may not work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Classic CSRF: a concrete example
&lt;/h4&gt;

&lt;p&gt;Cookies are used to store user sessions (or session identifiers) in a vast number of sites, and historically cookies are sent with all requests to a site, even those triggered from external sites.&lt;/p&gt;

&lt;p&gt;Imagine the site &lt;code&gt;bank.example&lt;/code&gt;, which works with user sessions. When a client logs in, the site sets a cookie like c with some session identifier. Although the session identifier alone is enough to make requests on behalf of a (logged in) client, it is sufficiently difficult to guess for an attacker, so that directly exploiting this mechanism is impractical. The site at &lt;code&gt;bank.example&lt;/code&gt; offers transfer functionality, which works by submitting a form to the address &lt;code&gt;bank.example/secure/transfer.do&lt;/code&gt; with the transfer amount and a destination account.&lt;/p&gt;

&lt;p&gt;How could an attacker exploit this system to transfer funds to themselves? Imagine further that an attacker has compromised an unrelated site, &lt;code&gt;vulnerablenewssite.example&lt;/code&gt;, which ideally (for the attacker) is a site that the bank's customers are likely to visit. Then the attacker can make a request from &lt;code&gt;vulnerablenewssite.example&lt;/code&gt; to &lt;code&gt;bank.example/secure/transfer.do&lt;/code&gt; with their account details by submitting a form. This request will include the users' &lt;code&gt;SESSIONID&lt;/code&gt; cookie (which the attacker doesn't know) and result in the attacker stealing funds from the unsuspecting user.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus classic CSRF example: logging out
&lt;/h4&gt;

&lt;p&gt;Another example of a CSRF attack is terminating users' sessions. Many sites implement logging out by directing the user to a location like &lt;code&gt;example.com/logout&lt;/code&gt;, which implements the logic necessary to invalidate a user session. An attacker could exploit this fact to terminate a session from an external site by loading this path (if the path also works with a simple GET request, this can be done trivially by embedding the logout path as an external resource in a multitude of ways, such as by using the &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt; and &lt;code&gt;iframe&lt;/code&gt; tags, to name a few).&lt;/p&gt;

&lt;p&gt;Although in many cases this may not have many consequences besides annoyance (still, depending on the target site even a short-lived denial of service could be advantageous to an attacker, especially in combination with other attacks) at having to log in again, this illustrates two points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That the request doesn't need to fully 'succeed' (i.e., probably loading an image from &lt;code&gt;example.com/logout&lt;/code&gt; will not actually display an image). As long as the request is made, whether or not a valid resource is presented, an attack has potential to succeed.&lt;/li&gt;
&lt;li&gt;Although this attack also works with &lt;code&gt;POST&lt;/code&gt; requests by submitting a form, alloing &lt;code&gt;GET&lt;/code&gt; requests for things that change the server state in some manner leaves the target site in a precarious position because it opens up more avenues for attack while reducing the number of possible mitigations discussed later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Client-Side CSRF: a concrete example
&lt;/h4&gt;

&lt;p&gt;Client-Side CSRF has similar consequences to classic CSRF but is carried out in a different way (through insecure input validation) that renders most defences against classic CSRF ineffective.&lt;/p&gt;

&lt;p&gt;Consider the bank site from earlier. To mitigate classic CSRF attacks, they've stopped using cookies in favour of local storage and user actions are implemented with requests using client-side scripting. Because local storage can only be read by &lt;code&gt;bank.example&lt;/code&gt; and because, unlike cookies, values in local storage are not sent along HTTP requests, a classic CSRF attack will fail.&lt;/p&gt;

&lt;p&gt;However, imagine that now, in order to make a transfer, the URL is something like &lt;code&gt;https://bank.example/secure/action.do#?destination=transfer.do&amp;amp;data=amount_100-payee_1234&lt;/code&gt;, for making a transfer of $100 to the account number 1234. Then, the page at &lt;code&gt;https://bank.example/secure/action.do&lt;/code&gt; has a script that extracts the relevant data from the URI fragment (i.e., the part after &lt;code&gt;#&lt;/code&gt;) and makes a request to &lt;code&gt;https://bank.example/secure/transfer.do&lt;/code&gt;, which is deduced from these data.&lt;/p&gt;

&lt;p&gt;Since all of these parameters are controlled by an attacker, several ways of exploiting this system exist. For example, an attacker could open a new browser window (e.g., through &lt;code&gt;window.open&lt;/code&gt;) to the target URL or could trick the user into clicking an attacker-crafted link. Because the exploitation happens through client-side code on the target site, server-side or browser-side CSRF mitigations are ineffective.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSRF mitigations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;SameSite&lt;/code&gt; cookies
&lt;/h3&gt;

&lt;p&gt;Historically, cookies set on a site are sent along all requests to that site, even for requests that originate from a different site. This is the mechanism that classic CSRF exploits, and, to mitigate this, &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis/#section-5.5.7" rel="noopener noreferrer"&gt;RFC6265bis&lt;/a&gt; introduced the &lt;code&gt;SameSite&lt;/code&gt; attribute, which is implemented in all major modern browsers.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SameSite&lt;/code&gt; attribute may take three possible values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;None&lt;/code&gt;, which results in the historical behaviour of the cookie being sent with all requests;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Lax&lt;/code&gt;, which results in the cookie being sent only for requests either originating from the &lt;em&gt;same site&lt;/em&gt; or navigation to the site (for example, as a result of following a link); and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Strict&lt;/code&gt;, which omits sending the cookie unless for requests originating from the &lt;em&gt;same site&lt;/em&gt; (i.e., all external requests, including navigation will omit the cookie).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most sites, &lt;code&gt;SameSite=Lax&lt;/code&gt; offers a good balance between convenience and protection. This is the default behaviour in many major modern browsers (i.e., all cookies implicitly are &lt;code&gt;SameSite=Lax&lt;/code&gt; unless the attribute is specified to be something else), with the notable exceptions at the time of writing being Firefox and Safari. In all other browsers, including legacy browsers that do not support the &lt;code&gt;SameSite&lt;/code&gt; attribute, the default (or only) behaviour is that of &lt;code&gt;SameSite=None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As a first line of defence, all sensitive cookies should explicitly set the &lt;code&gt;SameSite=Lax&lt;/code&gt; (or &lt;code&gt;SameSite=Strict&lt;/code&gt;) attribute to guard off against classic CSRF and &lt;code&gt;Secure&lt;/code&gt; attributes to guard against classic CSRF attacks&lt;/strong&gt;. In addition, sensitive pages should use HTTPS and set the &lt;code&gt;Secure&lt;/code&gt; attribute to protect against other attacks, as well as the &lt;code&gt;HttpOnly&lt;/code&gt; attribute if the cookie does not need to be visible to client side scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  TLS 1.3 + &lt;code&gt;SameSite&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Because there is a nearly complete overlap between browsers that support TLS 1.3 and browsers that support &lt;code&gt;SameSite&lt;/code&gt;, making the site available only through TLS 1.3 (or higher) can help ensure that &lt;code&gt;SameSite&lt;/code&gt; is effective by preventing older browsers from making requests at all. Do note that this isn't an absolute guarantee, since older browsers may still access the site with some non-standard configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSRF tokens
&lt;/h2&gt;

&lt;p&gt;The most common technique for CSRF protection, which works in older and newer browsers alike, consists of including some kind of &lt;em&gt;token&lt;/em&gt; along with the request. This token needs to be difficult to guess for third parties, so that attempts at CSRF fail validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Double-submit cookies
&lt;/h3&gt;

&lt;p&gt;This technique has the advantage of being stateless (i.e., the server does not need to maintain any state related to CSRF protection). It works by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting a cookie on the client that has sufficient entropy (i.e., a long random value), and having all requests to resources that need to be protected include this value (or a value derived therefrom).&lt;/li&gt;
&lt;li&gt;Upon receiving a request, requiring that the two values match&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, upon visiting a site, it could set a the cookie &lt;code&gt;_CSRF&lt;/code&gt; to the value &lt;code&gt;01234567-89ab-4000-8000-0123456789ab&lt;/code&gt;. Then, upon receiving requests that result in some sensitive action, the value &lt;code&gt;01234567-89ab-4000-8000-0123456789ab&lt;/code&gt; (or some derived form) is included as an additional field, which is checked to verify it matches the value included in the cookie. This additional field could, for example, take the form of a hidden form input field or a custom header.&lt;/p&gt;

&lt;p&gt;Sites that may have untrusted subdomains or subpaths (for example, because they are under the control of third parties) should consider restricting access to cookies with appropriate use of the &lt;code&gt;Domain&lt;/code&gt; and &lt;code&gt;Path&lt;/code&gt; attributes. However, when this is not practical, an appropriate defence is setting the double-sent value to be a value &lt;em&gt;derived&lt;/em&gt; from the CSRF cookie, in a way that only the target server can validate it. For example, the hidden field can be set to &lt;code&gt;HMAC(_CSRF cookie, secret)&lt;/code&gt; or even &lt;code&gt;HMAC(_CSRF cookie + path, secret)&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Additional restrictions
&lt;/h4&gt;

&lt;p&gt;To reduce the timeframe available to an attacker, the CSRF token cookie could be digitally-signed or integrity-protected and validity window set, with the token being rotated before it expires. This has the disadvantage of making validation slightly more demanding on the server as well as potential inconvenience to users when the token expires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronised tokens
&lt;/h3&gt;

&lt;p&gt;As an alternative to double-submit cookies, the value used to derive the token can be stored server-side on the server as part of the session information. This allows for finer-grained control of the token and its validation, because it remains opaque to the client and any potential attackers. However, it can require more server resource and result in inconvenience to users when the token expires or is rotated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoiding cookies
&lt;/h2&gt;

&lt;p&gt;Since classic CSRF attacks rely on how cookies are sent in the HTTP protocol, a viable protection against attacks can be simply not using cookies, opting for local or session storage instead. This may be especially appropriate for sites which require client-side scripts to function and require or can have session identifiers or information available to client-side scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  CORS
&lt;/h2&gt;

&lt;p&gt;Generally, classic CSRF attacks are not prevented by Cross-Origin Resource Sharing (CORS) because for compatibility reasons many cross-origin requests are allowed to go through without CORS checks, such as embedding external resources or submitting forms.&lt;/p&gt;

&lt;p&gt;For applications that require client-side scripts, one way simple way of triggering CORS checks is by including a custom header or submitting payloads with a &lt;code&gt;content-type&lt;/code&gt; header that is not allowed in HTML forms, such as &lt;code&gt;application/json&lt;/code&gt;. The backend must in this case check that incoming requests have the expected headers as well as block cross-origin requests as appropriate.&lt;/p&gt;

&lt;p&gt;When using CSFR tokens, it is imperative that CORS be set up correctly, or else a malicious actor could take advantage of an ineffective policy to retrieve the token value directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Origin&lt;/code&gt; and &lt;code&gt;Referer&lt;/code&gt; headers validation
&lt;/h2&gt;

&lt;p&gt;Browsers prevent spoofing the values of the &lt;code&gt;Origin&lt;/code&gt; and &lt;code&gt;Referer&lt;/code&gt; headers (although they do allow to omit the &lt;code&gt;Referer&lt;/code&gt; header in some circumstances). The &lt;code&gt;Referer&lt;/code&gt; header is by default included in all cross-origin requests while generally the &lt;code&gt;Origin&lt;/code&gt; header is included in all CORS requests as well as &lt;code&gt;POST&lt;/code&gt; requests.&lt;/p&gt;

&lt;p&gt;One could protect against CSRF attacks by verifying that the value of the &lt;code&gt;Origin&lt;/code&gt; header (when present) or else the origin in the &lt;code&gt;Referer&lt;/code&gt; header (when present) matches an expected value, which usually should be the host same as that of the &lt;code&gt;Host&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;In some situations, it could happen that neither the &lt;code&gt;Origin&lt;/code&gt; nor the &lt;code&gt;Referer&lt;/code&gt; headers be set, one such situation being a GET request caused by direct user navigation. When this happens, one might decide to either block (erring on the side of caution) or allow (erring on the side of availability) the incoming request. A good guideline might be blocking all non-&lt;code&gt;GET&lt;/code&gt; / non-&lt;code&gt;HEAD&lt;/code&gt; requests with neither header, while deciding on &lt;code&gt;GET&lt;/code&gt; (and &lt;code&gt;HEAD&lt;/code&gt;) on a case-by-case basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Sec-*&lt;/code&gt; headers validation
&lt;/h2&gt;

&lt;p&gt;Many, but not all, modern web browsers implement various &lt;code&gt;Sec-&lt;/code&gt;-prefixed request headers, which can provide additional information that is helpful in preventing CSRF. In particular, the &lt;code&gt;Sec-Fetch-Site&lt;/code&gt; having the value &lt;code&gt;cross-site&lt;/code&gt; (different site altogether) or &lt;code&gt;same-site&lt;/code&gt; (different subdomain) may be indicative of a CSRF attempt, and these requests may be blocked as appropriate.&lt;/p&gt;

&lt;p&gt;Since not all browsers (notably, Safari) send this header along, requests lacking this header should be allowed through to prevent service disruption to legitimate users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-in CSRF protection
&lt;/h2&gt;

&lt;p&gt;If you're using some sort of web framework, chances are that it comes with CSRF protection out-of-the-box or that third-party modules exist that provide the functionality. Before implementing your own, you may want to familiarise yourself with the built-in protection to see if it covers your needs, since chances are that it will be a robust and well-tested solution that will save you time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protection against Client-Side CSRF
&lt;/h2&gt;

&lt;p&gt;Unlike classic CSRF, client-side CSRF can be more challenging to protect against because rather than checking for the correctness of certain predetermined values, one needs to check for the well-formedness and correctness of application-dependent data.&lt;/p&gt;

&lt;p&gt;Some useful guidelines against client-side CSRF can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When possible, avoid client-side actions that affect the application state or are potentially sensitive upon without prior user interaction. In other words:

&lt;ul&gt;
&lt;li&gt;If possible, do not automatically make sensitive requests if the user has not interacted with the page (e.g., moving the mouse, clicking on something, typed something, scrolled, etc.)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When dynamic endpoints are used in a way that could be manipulated by a malicious actor (for example, as part of the URL), implement validation rules that are as strict as feasible for the application (for example, a whitelist or pattern checking).&lt;/li&gt;

&lt;li&gt;When the data are sent as dynamic client-side requests that could be manipulated by a malicious actor (for example, as part of the URL), implement validation rules that are as strict as feasible for the application (for example, schema validation or data signing).&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other defence-in-depth measures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Content Security Policy (CSP)
&lt;/h4&gt;

&lt;p&gt;While not effective against all forms of client-side CSRF (specifically, direct linking or somehow making a user open a link), a well-crafted content security policy can close some attack venues. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;frame-ancestors&lt;/code&gt; (and the header &lt;code&gt;X-Frame-Options&lt;/code&gt;) can be used to prevent embedding of our site into a different site, thus forcing an attacker to make the user open a link, which may be more obvious than, e.g., a hidden &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connect-src&lt;/code&gt; to restrict the origins our site is allowed to connect to, thus preventing leaking data to an attacker-controlled site&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;img-src&lt;/code&gt;, &lt;code&gt;script-src&lt;/code&gt;, &lt;code&gt;default-src&lt;/code&gt;, etc.: similar to &lt;code&gt;connect-src&lt;/code&gt;, if we might leak information through dynamically inserted resources.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cors</category>
      <category>csrf</category>
      <category>security</category>
      <category>web</category>
    </item>
    <item>
      <title>Apeleg join the W3C</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Wed, 19 Oct 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/exact-realty-join-the-w3c-1gj7</link>
      <guid>https://dev.to/apeleg/exact-realty-join-the-w3c-1gj7</guid>
      <description>&lt;p&gt;In July, &lt;a href="https://apeleg.com/blog/posts/2022/07/15/vectorexpress/" rel="noopener noreferrer"&gt;we announced&lt;/a&gt; our partnership with Smidyo to provide Vector Express. We view this as a strategic move to support our mission of facilitating interoperability and producing value through automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today, as part of our long-standing commitment to open standards and furthering innovation in the web, we are pleased to announce our becoming a W3C member.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org" rel="noopener noreferrer"&gt;World Wide Web Consortium&lt;/a&gt; (W3C) was founded in 1994 and is one of the chief international standard organisations for the web, including the ubiquitous HTML, CSS and SVG standards. The organisation is composed of over 470 members and is the arena for discussion and development to the latest innovations in the web space, such as &lt;a href="https://www.w3.org/TR/2021/WD-webauthn-3-20210427/" rel="noopener noreferrer"&gt;WebAuthn&lt;/a&gt;, a standard for superseding password authentication, the &lt;a href="https://www.w3.org/TR/2017/REC-WebCryptoAPI-20170126/" rel="noopener noreferrer"&gt;Web Cryptography API&lt;/a&gt;, an API for accessing cryptographic operations on web browsers and the &lt;a href="https://www.w3.org/TR/2022/WD-WGSL-20221014/" rel="noopener noreferrer"&gt;WebGPU Shading Language&lt;/a&gt;, a standard shader language that allows for bringing rich user experiences such as games and advanced animations to the web.&lt;/p&gt;

&lt;p&gt;We strongly believe in interoperability, open standards, collaboration and transparency and as a W3C member, Apeleg will be able to stay informed of new standards and advancements and participate in the various &lt;a href="https://www.w3.org/groups/wg/" rel="noopener noreferrer"&gt;working groups&lt;/a&gt; to shape the future of the web.&lt;/p&gt;

&lt;p&gt;The areas that are of special interest to us are &lt;em&gt;accessibility&lt;/em&gt;, &lt;em&gt;HTML&lt;/em&gt;, &lt;em&gt;service workers&lt;/em&gt; and &lt;em&gt;web authentication&lt;/em&gt;, as these closely relate to our areas of expertise and the solutions that we commonly work on. We plan on bringing our experience to the table to aid in producing high-quality standards as well as gain insights that can help us deliver even better services and solutions to our customers and the Internet community in general.&lt;/p&gt;

&lt;p&gt;As one of the few Norwegian-registered W3C members (not including members' subsidiaries), we feel a strong responsibility to ensure that we can represent the voices of our Norwegian customers and foster innovation and accessible standards worldwide as well as in Norway.&lt;/p&gt;

</description>
      <category>web</category>
      <category>standards</category>
      <category>standarddevelopment</category>
      <category>openstandards</category>
    </item>
    <item>
      <title>Modern and robust hotlink protection in 2022</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Mon, 10 Oct 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/apeleg/modern-and-robust-hotlink-protection-in-2022-l61</link>
      <guid>https://dev.to/apeleg/modern-and-robust-hotlink-protection-in-2022-l61</guid>
      <description>&lt;h2&gt;
  
  
  What a hotlink is
&lt;/h2&gt;

&lt;p&gt;Hotlinking refers to the practice of third-party web properties loading resources (most commonly images) directly from your own server.&lt;/p&gt;

&lt;p&gt;For example, if you operate the website &lt;code&gt;yourbusiness.example&lt;/code&gt;, you may have an image at &lt;code&gt;https://yourbusiness.example/infographic.png&lt;/code&gt; that you use within your website. A hotlink is when an unrelated property (for example, the site &lt;code&gt;anotherbusiness.test&lt;/code&gt;) embeds that image directly on their website by reference to your server, for example using the following HTML code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;https://yourbusiness.example/infographic.png&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Widget purchases per capita"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unauthorised hotlinks are generally undesirable, not only because they can facilitate reproducing your content without permission but also because, since the resources are being loaded directly from your server, they can burden you with additional server costs in computing and bandwidth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; If your website all your resources are in the same domain, add the &lt;code&gt;Cross-Origin-Resource-Policy: same-site&lt;/code&gt; response header to your resources. If you use a CDN or serve some resources from an external domain, add the &lt;code&gt;Cross-Origin-Resource-Policy: same-origin&lt;/code&gt; and &lt;code&gt;Access-Control-Allow-Origin: https://yourbusiness.example&lt;/code&gt; response headers to your (external) resources and force a CORS request by using the &lt;code&gt;crossorigin&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Older approach to hotlink protection
&lt;/h2&gt;

&lt;p&gt;Hotlink protection has historically relied on the HTTP &lt;code&gt;Referer&lt;/code&gt; header, which indicates the source of the document loading the resource.&lt;/p&gt;

&lt;p&gt;When a request is made to &lt;code&gt;https://yourbusiness.example/infographic.png&lt;/code&gt; from your website, this referrer header would look something like &lt;code&gt;Referer: https://yourbusiness.example/statistics.html&lt;/code&gt;, whereas when it's embedded in a third-party website, it might look like &lt;code&gt;Referer: https://anotherbusiness.test/widgets-consumption/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This approach is usually implemented in various webservers as follows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example configuration for &lt;code&gt;Referer&lt;/code&gt;-based protection
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Apache: &lt;code&gt;.htaccess&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?yourbusiness\.example [NC]
RewriteRule \.(jpe?g|png|gif)$ - [NC,F,L]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  nginx
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location ~ \.(jpe?g|png|gif)$ {
    valid_referers
        none blocked
        server_names
            *.yourbusiness.example
            yourbusiness.example;

    if ($invalid_referer) {
        return 403;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Microsoft IIS
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rule&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Hotlinking Prevention"&lt;/span&gt;
    &lt;span class="na"&gt;stopProcessing=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt;
        &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;".*\.(jpe?g|png|gif)"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;conditions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt;
            &lt;span class="na"&gt;input=&lt;/span&gt;&lt;span class="s"&gt;"{HTTP_REFERER}"&lt;/span&gt;
            &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"^$"&lt;/span&gt;
            &lt;span class="na"&gt;negate=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt;
            &lt;span class="na"&gt;input=&lt;/span&gt;&lt;span class="s"&gt;"{HTTP_REFERER}"&lt;/span&gt;
            &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"^https?://(.+\.)?yourbusiness\.example/.*$"&lt;/span&gt;
            &lt;span class="na"&gt;negate=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/conditions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"CustomResponse"&lt;/span&gt;
        &lt;span class="na"&gt;statusCode=&lt;/span&gt;&lt;span class="s"&gt;"403"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issues with &lt;code&gt;Referer&lt;/code&gt;-based protection
&lt;/h3&gt;

&lt;p&gt;Hotlink protection using the &lt;code&gt;Referer&lt;/code&gt; has a number of issues that make it inappropriate in many scenarios.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hotlinking vs direct linking
&lt;/h4&gt;

&lt;p&gt;Perhaps the most compelling argument against relying on the &lt;code&gt;Referer&lt;/code&gt; server is that doing so also breaks regular direct links, which may not always be desirable. This is because the &lt;code&gt;Referer&lt;/code&gt; header is not only sent when loading resources but also when a navigation action happens. Hence, a citation like &lt;code&gt;From YourBusiness' &amp;lt;a href=https://yourbusiness.example/infographic.png&amp;gt;widget purchases per capita&amp;lt;/a&amp;gt; have increased steadily over the last century&lt;/code&gt; would result in a &lt;code&gt;Referer&lt;/code&gt; header being sent from an external domain, which will trigger hotlink protection and result in blocked content. This is in most cases a bad user experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Referer&lt;/code&gt; omission
&lt;/h4&gt;

&lt;p&gt;Another reason why this way of protection is ineffective is that the &lt;code&gt;Referer&lt;/code&gt; header is not sent along requests in all cases.&lt;/p&gt;

&lt;p&gt;One common case is that generally resources loaded from a plain HTTP location (i.e., with the URL starting with &lt;code&gt;http://&lt;/code&gt;) will not include a &lt;code&gt;Referer&lt;/code&gt; when they are being loaded from an HTTPS site. Therefore, an image loaded from &lt;code&gt;http://yourbusiness.example/infographic.png&lt;/code&gt; at &lt;code&gt;https://example.com&lt;/code&gt; will typically not have a &lt;code&gt;Referer&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;Although the above scenario is not as relevant nowadays as most sites use HTTPS, that is just one example of how the &lt;code&gt;Referer&lt;/code&gt; header can be omitted. A much more relevant argument is that the embedding site is in full control of whether a &lt;code&gt;Referer&lt;/code&gt; header is sent along, which is as simple as including the &lt;code&gt;referrerpolicy="no-referrer"&lt;/code&gt; attribute to the &lt;code&gt;img&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;It may be tempting to address this issue by requiring that a &lt;code&gt;Referer&lt;/code&gt; header be present. However, there are other reasons why a &lt;code&gt;Referer&lt;/code&gt; header may not be sent, such as direct navigation by a user, browser configuration and extensions that block this header or proxies that remove it. Thus, simply blocking incoming requests missing this header could result in poor user experience for some users, as your page will look 'broken' since resources won't load.&lt;/p&gt;

&lt;h4&gt;
  
  
  Additional processing
&lt;/h4&gt;

&lt;p&gt;A third disadvantage of &lt;code&gt;Referer&lt;/code&gt;-based protection is that it's dynamic by nature, meaning that every incoming request needs to be evaluated by your server to check whether the &lt;code&gt;Referer&lt;/code&gt; contains an allowed value. This is a relatively small concern, but it introduces a tiny amount of latency to the response and results in more complex cache management.&lt;/p&gt;

&lt;p&gt;As the web is moving more and more towards static or pre-rendered content and serverless platforms, effective protection that involves as little server logic as possible is ideal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A more robust approach
&lt;/h2&gt;

&lt;p&gt;Web standards and browsers have come a long way in the last few decades, and all of the tools for effective and robust protection against hotlinking in the most common scenarios. Specifically, developments in the &lt;a href="https://fetch.spec.whatwg.org/" rel="noopener noreferrer"&gt;&lt;code&gt;fetch&lt;/code&gt; standard&lt;/a&gt; regarding cross-origin requests arm us with request and response headers that we can use to implement browser-enforced hotlink protection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some relevant headers
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Origin&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://datatracker.ietf.org/doc/html/rfc6454#section-7" rel="noopener noreferrer"&gt;&lt;code&gt;Origin&lt;/code&gt; HTTP &lt;em&gt;request&lt;/em&gt; header&lt;/a&gt; is in many respects similar to the &lt;code&gt;Referer&lt;/code&gt; header with some enhancements that make it more suitable for requests across different web properties.&lt;/p&gt;

&lt;p&gt;One key difference between &lt;code&gt;Referer&lt;/code&gt; and &lt;code&gt;Origin&lt;/code&gt; is that the former &lt;em&gt;typically&lt;/em&gt; is a full URL (for example, &lt;code&gt;https://www.example.com/page/&lt;/code&gt;) whilst the latter is always just an &lt;em&gt;origin&lt;/em&gt;, or the first part of the URL, like &lt;code&gt;https://www.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Origin&lt;/code&gt; request header is sent for requests with methods other than &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;HEAD&lt;/code&gt;, or for requests that are explicitly marked as cross-origin (i.e., from one site to another).&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://fetch.spec.whatwg.org/commit-snapshots/283c2ae9285858e099c84a0841924fa7c4ef33e4/#cross-origin-resource-policy-header" rel="noopener noreferrer"&gt;&lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; HTTP &lt;em&gt;response&lt;/em&gt; header&lt;/a&gt; is used to define a policy for cross-origin requests made in &lt;code&gt;no-cors&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;In practical terms, &lt;strong&gt;this header alone is sufficient in most cases for effective hotlink protection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; can take one of three values: &lt;code&gt;same-origin&lt;/code&gt;, &lt;code&gt;same-site&lt;/code&gt; or &lt;code&gt;cross-origin&lt;/code&gt;. All we need to do is include the header &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; with either of &lt;code&gt;same-origin&lt;/code&gt; or &lt;code&gt;same-site&lt;/code&gt;, and embedding of your resources by external websites will be blocked.&lt;/p&gt;

&lt;h5&gt;
  
  
  Difference between &lt;code&gt;same-origin&lt;/code&gt; and &lt;code&gt;same-site&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;The value &lt;code&gt;same-origin&lt;/code&gt; specifies stricter policy than &lt;code&gt;same-site&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Consider the site at &lt;code&gt;https://example.com&lt;/code&gt; and the resources &lt;code&gt;https://example.com/a.png&lt;/code&gt; and &lt;code&gt;https://images.example.com/b.png&lt;/code&gt;. While both resources are part of the same &lt;em&gt;site&lt;/em&gt; (i.e., &lt;code&gt;example.com&lt;/code&gt;), each resource has a different origin: &lt;code&gt;https://example.com&lt;/code&gt; and &lt;code&gt;https://images.example.com&lt;/code&gt;, respectively. While both &lt;code&gt;same-origin&lt;/code&gt; and &lt;code&gt;same-site&lt;/code&gt; will allow for the site to use the first resource, only &lt;code&gt;same-site&lt;/code&gt; will allow it to embed the second resource, as the origins are different.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://fetch.spec.whatwg.org/commit-snapshots/283c2ae9285858e099c84a0841924fa7c4ef33e4/#http-access-control-allow-origin" rel="noopener noreferrer"&gt;&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; HTTP &lt;em&gt;response&lt;/em&gt; header&lt;/a&gt; is relevant for so-called CORS requests, which are requests that include an &lt;code&gt;Origin&lt;/code&gt; header. Furthermore, the CORS protocol defines some versatile mechanisms that allow sites to define policies for cross-origin resource sharing.&lt;/p&gt;

&lt;p&gt;Normally, most resources that we would like to protect against hotlinking (for example, images) are &lt;em&gt;not&lt;/em&gt; loaded using CORS requests. However, CORS requests can be made explicitly by including the &lt;code&gt;crossorigin&lt;/code&gt; or &lt;code&gt;crossorigin="anonymous"&lt;/code&gt; attribute to the resource tag, for example like this: &lt;code&gt;&amp;lt;img crossorigin alt=Example src=sample.jpg&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; instructs the browser that a certain origin actually allowed to make a cross-origin request, and it should take either of two values: &lt;code&gt;*&lt;/code&gt;, indicating that the resource can be requested by all origins, or the value of the &lt;code&gt;Origin&lt;/code&gt; header included with the request. &lt;strong&gt;Other values or absence of this header tell the browser that the request is not allowed in the context of the CORS protocol&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hotlink protection for sites using a single origin
&lt;/h3&gt;

&lt;p&gt;Many smaller sites serve all of their content from a single origin. For example, if you use WordPress, you may have the site &lt;code&gt;https://yourbusiness.example&lt;/code&gt; and have most of your images under the &lt;code&gt;https://yourbusiness.example/wp-content/uploads&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;For this simple case, an effective way to implement hotlink protection is to include the header &lt;code&gt;Cross-Origin-Resource-Policy: same-origin&lt;/code&gt; along with your responses, and this will prevent hotlinking by any other sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is important that the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header not be sent&lt;/strong&gt;, or if it is, that it be set to the origin of your site (e.g., &lt;code&gt;https://yourbusiness.example&lt;/code&gt;). Sending &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; with any other value, especially &lt;code&gt;*&lt;/code&gt; or replying back with the &lt;code&gt;Origin&lt;/code&gt; header included in the request will allow hotlinking if a CORS request is made.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configuration
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Apache &lt;code&gt;.htaccess&lt;/code&gt;
&lt;/h5&gt;

&lt;p&gt;This policy can be implemented in Apache by using the &lt;code&gt;.htaccess&lt;/code&gt; file (or alternatively the main configuration file) with something along these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;FilesMatch "\.(jpe?g|png|gif)$"&amp;gt;
    &amp;lt;IfModule mod_headers.c&amp;gt;
        Header set Cross-Origin-Resource-Policy "same-origin"
    &amp;lt;/IfModule&amp;gt;
&amp;lt;/FilesMatch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FilesMatch&lt;/code&gt; directive can be adjusted as needed depending on the files that require hotlink protection. Because this technique does not have many of the limitations of the &lt;code&gt;Referer&lt;/code&gt;-based one, it is even possible to skip this check and include the header with all responses.&lt;/p&gt;

&lt;h5&gt;
  
  
  nginx
&lt;/h5&gt;

&lt;p&gt;In the relevant &lt;code&gt;server&lt;/code&gt; block, this policy can be implemented as follows, adjusting the &lt;code&gt;location&lt;/code&gt; part as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location ~ \.(jpe?g|png|gif)$ {
    add_header cross-origin-resource-policy same-origin;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hotlink protection for sites using subdomains
&lt;/h3&gt;

&lt;p&gt;Oftentimes sites serve resources from a subdomain. For instance, the main site could be available at &lt;code&gt;https://yourbusiness.example&lt;/code&gt; while images and other static resources are hosted at &lt;code&gt;https://static.yourbusiness.example&lt;/code&gt;. It may also be the case that certain parts of the site reside in a subdomain (for example, &lt;code&gt;https://store.yourbusiness.example&lt;/code&gt;) and subdomains share resources.&lt;/p&gt;

&lt;p&gt;For these scenarios, hotlink protection can still use the &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; header, except that the &lt;code&gt;same-site&lt;/code&gt; value (instead of &lt;code&gt;same-origin&lt;/code&gt;) is likely the most appropriate choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hotlink protection for sites using external resources
&lt;/h3&gt;

&lt;p&gt;It is increasingly common for sites to use CDNs to serve static resources, which often are accessed through a separate domain. For example, &lt;code&gt;https://yourbusiness.example&lt;/code&gt; might load images from the origin &lt;code&gt;https://yourbusiness.cdnprovider.example&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hotlink protection in this scenario is slightly more involved than when all resources are part of the same site because then requests are by definition cross-origin and cross-site and CORS policies are only enforced for requests that use the CORS protocol.&lt;/p&gt;

&lt;p&gt;While &lt;em&gt;want&lt;/em&gt; to load resources from a different origin, we can't rely on the &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; alone. This is because the only value that would seem appropriate is &lt;code&gt;cross-origin&lt;/code&gt;, which does not provide any hotlink protection whatsoever: adding the header &lt;code&gt;Cross-Origin-Resource-Policy: cross-origin&lt;/code&gt; to CDN responses would result in &lt;em&gt;anyone&lt;/em&gt; being able to load the resource in question from any origin, which is exactly the situation that we are trying to avoid.&lt;/p&gt;

&lt;p&gt;Fortunately, we can force requests to use the CORS protocol and this way have more granular control over whom has access.&lt;/p&gt;

&lt;p&gt;Counter-intuitively, an appropriate value for the &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; header in CDN responses is &lt;code&gt;same-origin&lt;/code&gt;. By using this value, non-CORS requests to the CDN will fail, which leaves only CORS requests as a way to load resources, which equips us with more granular ways of defining an access policy through the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;For the CDN or external domain case, hence we need &lt;em&gt;three&lt;/em&gt; elements for hotlink protection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Cross-Origin-Resource-Policy: same-origin&lt;/code&gt; in the external resource response. This blocks non-CORS requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Allow-Origin: https://yourbusiness.example&lt;/code&gt; in the external resource response (where &lt;code&gt;https://yourbusiness.example&lt;/code&gt; is the origin the resource will be loaded from). This tells the browser that the response is intended for use by this origin and this origin only.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;crossorigin&lt;/code&gt; (or &lt;code&gt;crossorigin="anonymous"&lt;/code&gt;) attribute in the document referencing the resource. This means that &lt;code&gt;&amp;lt;img src=https://yourbusiness.cdnprovider.example/image.webp&amp;gt;&lt;/code&gt; becomes &lt;code&gt;&amp;lt;img crossorigin src=https://yourbusiness.cdnprovider.example/image.webp&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach will effectively block hotlinking from origins other than &lt;code&gt;https://yourbusiness.example&lt;/code&gt;, which is exactly what we are looking after. As an added bonus, this same configuration also works for the single-origin case discussed earlier and, with the caveats that follow, for the single-site case.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advantages, caveats and limitations
&lt;/h4&gt;

&lt;p&gt;The solution presented is simple (requires adding a few HTTP headers to the response and a small change to the HTML markup), robust, has good browser support&lt;sup id="fnref1"&gt;1&lt;/sup&gt; and because the policy is enforced by the browser itself, it &lt;a href="https://en.wikipedia.org/wiki/Progressive_enhancement" rel="noopener noreferrer"&gt;degrades gracefully&lt;/a&gt;, meaning that the resources will still load normally in the few browsers still in use that don't support these headers.&lt;/p&gt;

&lt;p&gt;Moreover, this solution for hotlink protection is in many cases &lt;em&gt;stateless&lt;/em&gt; meaning that no conditional logic is required in the server, as the values for the headers are predetermined in advance. &lt;/p&gt;

&lt;p&gt;The main caveat that applies, which is most relevant to this sites that make use of multiple domains or subdomains, &lt;strong&gt;and&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;load content served from an external domain (such as a CDN), &lt;strong&gt;or&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;use the &lt;code&gt;crossorigin&lt;/code&gt; attribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; can only contain a single origin (and there is no syntax for allowing subdomains), these sites will require some server-side logic give an appropriate value to the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header. The &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; must contain the value of the &lt;code&gt;Origin&lt;/code&gt; sent in the original request, and this value must be validated first to ensure that it's an allowed value. Moreover, it's likely that these sites will need to add &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; to their &lt;code&gt;Vary&lt;/code&gt; response header to allow for proper caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct linking protection
&lt;/h2&gt;

&lt;p&gt;In certain scenarios, it may be desirable to prevent direct access or direct linking to certain resources. The new &lt;code&gt;Sec-&lt;/code&gt; headers allow for controlling these actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images and other embeddable content
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org/TR/2021/WD-fetch-metadata-20210720/" rel="noopener noreferrer"&gt;&lt;code&gt;Sec-Fetch-Dest&lt;/code&gt; &lt;em&gt;request&lt;/em&gt; header&lt;/a&gt; is useful in these cases to have fine-grained control over when a browser is allowed to download a certain resource.&lt;/p&gt;

&lt;p&gt;For example, to prevent direct access to an image, you can check if this header is set to &lt;code&gt;image&lt;/code&gt;. To allow direct access and embedding as an image, but not other uses (for example, a &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;XHR&lt;/code&gt; request), only the &lt;code&gt;document&lt;/code&gt; and &lt;code&gt;image&lt;/code&gt; values could be allowed. To block direct access, just &lt;code&gt;image&lt;/code&gt; would be allowed.&lt;/p&gt;

&lt;p&gt;Note that this header is not yet supported by all browsers (most notably Safari), so it's advised that, if you decide to make decisions based on this header, you allow requests that do not have it set.&lt;/p&gt;

&lt;h3&gt;
  
  
  External direct links
&lt;/h3&gt;

&lt;p&gt;You may want to prevent or discourage external websites directly linking to certain files on your site (for instance, a large PDF file) while still allowing your users to access this content by directly linking files internally.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.w3.org/TR/2021/WD-fetch-metadata-20210720/#sec-fetch-site-header" rel="noopener noreferrer"&gt;&lt;code&gt;Sec-Fetch-Site&lt;/code&gt; &lt;em&gt;request&lt;/em&gt; header&lt;/a&gt; can be helpful for taking different actions based on where a user came from. For example, if this header is set to &lt;code&gt;cross-site&lt;/code&gt;, then you might decide to issue a &lt;code&gt;303 See Other&lt;/code&gt; redirect to a page discussing the resource in question.&lt;/p&gt;

&lt;p&gt;Like &lt;code&gt;Sec-Fetch-Dest&lt;/code&gt;, &lt;code&gt;Sec-Fetch-Site&lt;/code&gt; as of yet does not have wide enough support and may not be present in all requests. It's recommended to allow through normally requests without this header.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;As of the time of writing, &lt;code&gt;Cross-Origin-Resource-Policy&lt;/code&gt; is supported by &lt;a href="https://caniuse.com/mdn-http_headers_cross-origin-resource-policy" rel="noopener noreferrer"&gt;over 93% of global users&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>cors</category>
      <category>hotlinking</category>
      <category>security</category>
      <category>web</category>
    </item>
    <item>
      <title>Types of Execution Environments, Attestation and SGX</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Tue, 06 Sep 2022 00:45:55 +0000</pubDate>
      <link>https://dev.to/apeleg/types-of-execution-environments-attestation-and-sgx-4124</link>
      <guid>https://dev.to/apeleg/types-of-execution-environments-attestation-and-sgx-4124</guid>
      <description>&lt;h2&gt;
  
  
  Execution Environments
&lt;/h2&gt;

&lt;p&gt;OMTP &lt;a href="http://www.omtp.org/OMTP_Advanced_Trusted_Environment_OMTP_TR1_v1_1.pdf" rel="noopener noreferrer"&gt;refer&lt;/a&gt; to an &lt;strong&gt;execution environment&lt;/strong&gt; as the &lt;em&gt;combination of hardware and software components that can be used to execute and support applications&lt;/em&gt;. A typical execution environment consists of a processing unit, memory, input and output (I/O) ports and an operating system. Because application execution requires an execution environment, applications are ultimately limited by any constraints placed onto them by their execution environment. This means, for example, that applications can use only as much memory as their execution environment allows, and that they can only perform tasks supported and allowed by their execution environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rich Execution Environments (REEs)
&lt;/h3&gt;

&lt;p&gt;Traditionally, computing is effected in execution environments that not only permit the loading and execution of arbitrary programs but may also themselves be manipulated in arbitrary ways, such as by attaching a hardware debugger to observe and change the internal state. As it is impossible for such environments to make any verifiable assertions as to their state, they are inherently untrustworthy. Alternatively, the term Rich Execution Environments (REEs) is &lt;a href="https://globalplatform.org/specs-library/tee-system-architecture/" rel="noopener noreferrer"&gt;sometimes&lt;/a&gt; also used to refer to this type of execution environments, such as by GlobalPlatform.&lt;/p&gt;

&lt;p&gt;To understand the difficulty of establishing trust in REEs, consider the example of a messaging application that requires uploading a person's contacts to its developers' systems for the purpose of allowing that person to discover contacts already using said application. While this can be a valuable feature, the main disadvantage of such a system is that the users do not have a means of auditing or controlling how the information about their contacts will be used. While honest developers might use this information only for the stated purpose of contact discovery, unscrupulous developers might instead collect this information, aggregate it and then surreptitiously sell social graphs in the open market. Because at this point a sceptical user has only the word of the application developers that contact information is used for the stated purpose and only for the stated purpose, convincing prospective sceptical customers to upload their contacts requires demonstrating that their execution environment is such that the contacts uploaded cannot possibly be misused. However, providing such proof is impossible with an REE because a malicious developer could alter the execution environment in any number of ways such that contact information is exfiltrated.&lt;/p&gt;

&lt;p&gt;For example, suppose that the application developers hire an independent, objective and trusted auditor to inspect their systems for compliance to their stated policy and that not only does the auditor find the systems compliant, but also inspects the systems on a regular basis to ensure ongoing compliance. If the developers had malicious intent, they could attempt to fool the auditor (and their users) in various ways. A crude approach could be changing their server configuration files after each audit, but more sophisticated techniques are possible, such as modifying the hardware in their servers to exfiltrate the desired information.&lt;/p&gt;

&lt;p&gt;Furthermore, even if the developers &lt;em&gt;were&lt;/em&gt; honest and trustworthy, the nature of REEs results in the contact-use policy still being difficult to enforce by technical means because other actors involved might still interfere in ways that result in the misuse of contact information, such as the developers' employees and suppliers. Some of these breaches could include an employee reading the server's memory directly, a malicious operating system transmitting data on user activity, or even an unauthorised third-party accessing the server and modifying the software being executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trusted Execution Environments (TEEs)
&lt;/h3&gt;

&lt;p&gt;TEEs address the inherent untrustworthiness of REEs by providing an isolated environment for user applications, the properties of which are well-known. Continuing the previous example of contact discovery, consider messaging application developers willing to go to great lengths to substantiate their contact use policy. They may accomplish this by limiting the execution environment to prevent arbitrary state manipulation and by providing a means of establishing a verifiable chain of trust. One of the ways they can accomplish this is to configure the contact discovery service and then hand it over to a trusted third party (trusted third party in this context means an entity that is trusted to be honest by the application users). The trusted third party then proceeds to thoroughly audit the entire execution environment (including both hardware and software components) and publish the relevant findings. Then, the entire machine is secured&lt;sup id="fnref1"&gt;1&lt;/sup&gt; so that the execution environment cannot be modified further. When a user uploads their contact information to the contact discovery service, they also consult the trusted third party as to whether the service they are connecting to corresponds to the audited system.&lt;/p&gt;

&lt;p&gt;Intuitively, this scheme provides a high degree of confidence that the system a user is connecting to corresponds to one that behaves as per the published audit findings providing the user trusts the auditor. However, the example described is not practical for several reasons. Firstly, the increasing complexity of computer software and hardware and the interactions between them make it extremely difficult for an auditor to be decisively confident that a system behaves in a certain way, as doing so would require evaluating each of the components that comprise the system. Secondly, the example relies on an idealised notion of securing a machine that is not practical; physical access to the machine may be needed to effect repairs and other maintenance tasks, logical access may be needed to perform software updates. Thirdly, because of the restrictions placed on the entire system, any modifications would require going over the impractical processes of a full audit and securing once again.&lt;/p&gt;

&lt;p&gt;A more practical approach would be to isolate certain critical system components (such as software for contact discovery) from the rest of the system, and then audit these critical components. Hardware manufacturers are in a &lt;a href="https://doi.org/10.1109/Trustcom.2015.400" rel="noopener noreferrer"&gt;unique position&lt;/a&gt; to provide such isolated execution environments that allow users to restrict the interactions between sensitive components from the rest of the system, and that facilitate auditing by providing just enough functionality for implementing these critical operations. In GlobalPlaform terminology, these environments are known as Trusted Execution Environments (TEEs) and are defined as follows by &lt;a href="https://doi.org/10.1109/Trustcom.2015.357" rel="noopener noreferrer"&gt;M. Sabt &lt;em&gt;et al.&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[A] Trusted Execution Environment (TEE) is a tamper-resistant processing environment that runs on a separation kernel. It guarantees the authenticity of the executed code, the integrity of the runtime states (e.g. CPU registers, memory and sensitive I/O), and the confidentiality of its code, data and runtime states stored on a persistent memory. In addition, it shall be able to provide a remote attestation that proves its trustworthiness for third-parties. The content of TEE is not static; it can be securely updated. The TEE resists against all software attacks as well as the physical attacks performed on the main memory of the system. Attacks performed by exploiting backdoor security flaws are not possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TEEs have numerous privacy-enhancing applications that may benefit users. One of them is, as discussed earlier, private contact discovery; the &lt;strong&gt;Signal&lt;/strong&gt; application uses a contact discovery service enhanced using Intel SGX, a TEE technology, &lt;a href="https://signal.org/blog/private-contact-discovery/" rel="noopener noreferrer"&gt;to protect its users' privacy&lt;/a&gt;. A similar application of TEEs is &lt;a href="https://doi.org/10.1145/3052973.3053006" rel="noopener noreferrer"&gt;performing malware analysis in a remote cloud service&lt;/a&gt;, so that the service may not identify users by the contents of their devices, such as the applications they have installed, especially important as &lt;a href="https://doi.org/10.1145/2808138.2808146" rel="noopener noreferrer"&gt;98.93% of users may be uniquely identified by the list of applications they have installed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rhj4i633e47amvor47o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rhj4i633e47amvor47o.png" title="An overview of some of the components of a trusted platform. On the left, REE applications are executing on top of an untrusted operating system and sharing untrusted memory. Any privileged process in a TEE is able to manipulate the state and memory of REE applications. On the right, trusted applications are being executed in a trusted memory region. The platform and the isolation kernel protect access to the trusted memory and state of the trusted applications, which is protected from unauthorised access, even by privileged processes such as the untrusted operating system; any communication between the trusted and the untrusted parts is executed through a designated communication policy enforced by the platform. Lastly, trusted applications may produce attestations to prove their identity and trustworthiness." alt="Components of a trusted platform" width="782" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Sealing and Unsealing
&lt;/h4&gt;

&lt;p&gt;In the context of TEEs, sealing and unsealing refer to cryptographic primitives providing authenticated encryption and decryption, respectively, with a secret that exists &lt;em&gt;only&lt;/em&gt; within the TEE to securely store some of the TEE state in untrusted storage. Some TEE platforms, such as Intel SGX, provide a mechanism for deriving sealing secrets deterministically based on the TEE identity, which allow for unsealing information in different instances of the same TEE. Sealing can be useful to reduce the state information that is needed within a TEE, such as when the TEE is memory-constrained or for persistence when the TEE state may be lost (such as due to a power failure). A high-level overview of the sealing primitive is shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9k7gdw51sra3v8rk3kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9k7gdw51sra3v8rk3kp.png" title="High-level overview of the concept of _sealing_. A plaintext 𝖯 is authenticatedly encrypted using a secret 𝐾 that exists only within the TEE. This produces a sealed datum 𝖢, which can be safely stored in untrusted memory." alt="Sealing primitive" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Attestation
&lt;/h4&gt;

&lt;p&gt;A crucial component of TEEs is their providing a protocol to provide &lt;em&gt;attestations&lt;/em&gt;, verifiable assertions about the state or properties of the TEE; in particular, they can prove the presence of a particular TEE. Note that attestations are indispensable for TEEs, as without them it is impossible for an observer, including local observers with full access to a system, to differentiate between a TEE and another execution environment, whether it be another TEE or an REE. Hence, although it is indeed possible to use TEEs without using attestations (for example, for their isolation properties), they provide weaker security guarantees.&lt;/p&gt;

&lt;p&gt;The trusted part of a TEE stems from the concept of a &lt;em&gt;root of trust&lt;/em&gt;, that is, the notion that TEEs are trusted because some entity makes assertions about the properties of the TEE, and that these assertions are believed because the entities verifying the assertion trust the one making them. Trust in attestations entails both trusting the processing environment used in the TEE to meet certain specifications (a static component) and the &lt;a href="https://doi.org/10.1109/Trustcom.2015.357" rel="noopener noreferrer"&gt;specific state or application&lt;/a&gt; in the TEE (a semi-dynamic component).&lt;/p&gt;

&lt;h5&gt;
  
  
  Attestation Example
&lt;/h5&gt;

&lt;p&gt;Although various attestation schemes are possible, it may be helpful to consider a simple attestation model to understand the different parts that make an attestation. A TEE manufacturer produces TEE hardware in which each device δ is assigned a unique per-device asymmetric key pair (δₚ, δₛ) stored in the device. The public part of this key, δₚ, is signed with the device manufacturer's key pair (𝙼ₚ, 𝙼ₛ) to produce a signature σ. When a TEE is initialised, the secret key (δₛ) is used to sign the TEE state 𝑺&lt;sup id="fnref2"&gt;2&lt;/sup&gt; to produce a signature Σ. An attestation could consist of the tuple (𝙼ₚ, Σ, δₚ, Σ, 𝑺). This would allow anyone to verify that the state 𝑺 was present in the TEE δ. In particular, Σ establishes trust on the device δ because the manufacturer is trusted; then, the trust on the presence of state 𝑺 is possible because the device δ is trusted; lastly, if the state 𝑺 corresponds to a well-known and application, the entire TEE can be trusted to execute this application according to the device specifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intel Software Guard Extensions
&lt;/h2&gt;

&lt;p&gt;Intel Software Guard Extensions (SGX) is an extension to the Intel architecture, available since the Skylake microarchitecture, that provides a TEE for user software in the form of isolated software containers known as &lt;em&gt;enclaves&lt;/em&gt;. SGX has the stated goal of &lt;a href="https://software.intel.com/sites/default/files/332680-001.pdf" rel="noopener noreferrer"&gt;reducing application attack surface&lt;/a&gt; and &lt;a href="https://eprint.iacr.org/2016/086" rel="noopener noreferrer"&gt;protecting applications from potentially malicious privileged code&lt;/a&gt;, such as the operating system and a hypervisor. An SGX enclave is a protected region within the memory space of an application, which after initialisation can only be accessed by software resident in the enclave. Except where noted, the background information on the operation of SGX enclaves in this section is based on the &lt;a href="https://software.intel.com/sites/default/files/managed/7c/f1/332831-sdm-vol-3d.pdf" rel="noopener noreferrer"&gt;Intel® 64 and IA-32 Architectures Software Developer's Manual&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enclave Properties
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Enclave Signing
&lt;/h4&gt;

&lt;p&gt;Each SGX enclave is required to be signed with a 3072-bit RSA key, along with including identifiers of the enclaveprogram and its version. The public RSA key is used to identify the enclave developer, and a 256-bit identifier is derived from &lt;em&gt;measuring&lt;/em&gt; this public key, which is called &lt;code&gt;MRSIGNER&lt;/code&gt;. By signing several enclaves with the same key, some convenience features are available, such as the ability to derive common sealing keys for exchanging information between enclaves made by the same developer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Debug and Production Modes
&lt;/h4&gt;

&lt;p&gt;SGX enclaves exist in two flavours, which are determined at build time: debug and production enclaves. These two behave identically, except that external processes may use the &lt;code&gt;EDBGRD&lt;/code&gt; and &lt;code&gt;EDBGWR&lt;/code&gt; instructions for reading from and writing to debug enclave memory, and may similarly set breakpoints and traps within debug enclaves. As a result, the state of debug enclaves can be arbitrarily compromised and they are &lt;em&gt;not&lt;/em&gt; TEEs. While any SGX-capable processor may instantiate debug enclaves, only enclaves signed with a key &lt;a href="https://software.intel.com/en-us/articles/intel-software-guard-extensions-product-licensing-faq" rel="noopener noreferrer"&gt;whitelisted by Intel&lt;/a&gt; may be executed in production mode.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enclave Identity
&lt;/h4&gt;

&lt;p&gt;The initial enclave state is &lt;em&gt;measured&lt;/em&gt; upon initialisation by applying a hash function on every memory assigned to the enclave, which includes its code and data. This providing an enclave identity called &lt;code&gt;MRENCLAVE&lt;/code&gt;, which is represented as a 256-bit value. This identity, along with &lt;code&gt;MRSIGNER&lt;/code&gt;, represents the enclave identity. Both measurements may be used to derive enclave- or signer-specific keys (for example, using the &lt;code&gt;EGETKEY&lt;/code&gt; instruction) that depend on a processor-unique secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution Model
&lt;/h3&gt;

&lt;p&gt;An enclave may be accessed by using the &lt;code&gt;EENTER&lt;/code&gt; instruction, which must point to a well-known entry point in the enclave, each of which is called an &lt;a href="https://download.01.org/intel-sgx/sgx-linux/2.17.1/docs/Intel_SGX_Developer_Reference_Linux_2.17.1_Open_Source.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;ecall&lt;/strong&gt;&lt;/a&gt;. Once inside an enclave, the enclave may transfer control back to the calling process by using the &lt;code&gt;EEXIT&lt;/code&gt; instruction or its execution may be interrupted by an Asynchronous Exit Event (AEX), caused by external events (such as interrupts) that occur while an enclave is being executed. If an enclave execution is executed as a result of an AEX, the enclave execution may be resumed using the &lt;code&gt;ERESUME&lt;/code&gt; instruction. An enclave may call &lt;code&gt;EEXIT&lt;/code&gt; to return once it has finished its current task, or to perform an &lt;a href="https://download.01.org/intel-sgx/sgx-linux/2.17.1/docs/Intel_SGX_Developer_Reference_Linux_2.17.1_Open_Source.pdf" rel="noopener noreferrer"&gt;&lt;strong&gt;ocall&lt;/strong&gt;&lt;/a&gt;, that is, to execute code outside the enclave, such as a system call. In the latter case, the function performing the &lt;strong&gt;ocall&lt;/strong&gt; may not have finished executing and may expect the called code to return by following some convention to call back into the enclave.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Model
&lt;/h3&gt;

&lt;p&gt;The processor manages access to any memory pages assigned to SGX enclaves (referred to as &lt;em&gt;trusted memory&lt;/em&gt;) and triggers page faults for unauthorised accesses, and any memory pages swapped to disk are sealed to provide confidentiality and integrity, even from privileged processes. By contrast, memory pages not assigned to enclaves (referred to as &lt;em&gt;untrusted memory&lt;/em&gt;), do not offer these protections any may be arbitrarily manipulated by the operating system or other processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attestation Model
&lt;/h3&gt;

&lt;p&gt;SGX provides &lt;em&gt;local&lt;/em&gt; attestations, which depend upon a processor-unique secret and can only be verified by enclaves executing on the same processor, and &lt;em&gt;remote&lt;/em&gt; attestations, which can be verified by anyone, and do not require an enclave for verification.&lt;/p&gt;

&lt;h4&gt;
  
  
  Local Attestations
&lt;/h4&gt;

&lt;p&gt;Any SGX enclave may produce a report that can be verified by other enclaves executed on the same processor, referred to as &lt;em&gt;local attestations&lt;/em&gt;. These attestations enable secure information exchange between enclaves, and may be used both for synchronous communication (e.g., for establishing a secure channel between enclaves) and asynchronous communication (e.g., for storing information that may be later used by another enclave). The local attestation process is illustrated in the figure below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxy1vh1xx1il347esvk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxy1vh1xx1il347esvk1.png" title="Overview of the SGX local attestation generation and verification processes. An attesting enclave generates a report for a verifying enclave that contains some  raw `REPORTDATA` endraw  using the  raw `EREPORT` endraw  instruction. The verifying enclave generates a report verification key using the  raw `EGETKEY` endraw  instruction and proceeds to verify the report. The report includes  raw `REPORTDATA` endraw  and information about the attesting enclave." alt="Local attestation" width="800" height="785"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Generation
&lt;/h5&gt;

&lt;p&gt;Local attestations are generated using the &lt;code&gt;EREPORT&lt;/code&gt; instruction, which takes two inputs, &lt;code&gt;TARGETINFO&lt;/code&gt; and &lt;code&gt;REPORTDATA&lt;/code&gt;, and produces a &lt;em&gt;report&lt;/em&gt; as an output. &lt;code&gt;TARGETINFO&lt;/code&gt; identifies the enclave intended to verify the generated report and includes the target enclave &lt;code&gt;MRENCLAVE&lt;/code&gt; as well as other attributes, such as whether it is a debug enclave. &lt;code&gt;REPORTDATA&lt;/code&gt; is a 512-bit data structure that may contain arbitrary information intended to be verified by the target enclave. The generated report is authenticated with a symmetric key derived from the provided target &lt;code&gt;MRENCLAVE&lt;/code&gt; and contains  &lt;code&gt;REPORTDATA&lt;/code&gt; and information about the attesting enclave, including &lt;code&gt;MRENCLAVE&lt;/code&gt;, &lt;code&gt;MRSIGNER&lt;/code&gt; and other attributes, such as whether it was a debug enclave. &lt;/p&gt;

&lt;h5&gt;
  
  
  Verification
&lt;/h5&gt;

&lt;p&gt;Local attestations can only be verified by the target enclave, which must be executed in the same processor that was used for generating the report. The verification process consists of deriving a report key using the &lt;code&gt;EGETKEY&lt;/code&gt; instruction and verifying that the MAC attached to the report is valid.&lt;/p&gt;

&lt;h4&gt;
  
  
  Remote Attestations
&lt;/h4&gt;

&lt;p&gt;In addition to local attestations, &lt;a href="https://www.intel.com/content/www/us/en/developer/articles/technical/innovative-technology-for-cpu-based-attestation-and-sealing.html" rel="noopener noreferrer"&gt;SGX supports the generation of &lt;em&gt;remote attestations&lt;/em&gt;&lt;/a&gt;. Unlike local attestations, verifying remote attestations does not require the use of an enclave nor is it limited to the same processor.&lt;/p&gt;

&lt;h5&gt;
  
  
  Generation
&lt;/h5&gt;

&lt;p&gt;The process for generating a remote attestation is similar to that for local attestations but involves some additional steps. A remote attestation &lt;a href="https://eprint.iacr.org/2016/086" rel="noopener noreferrer"&gt;begins with a report&lt;/a&gt; made for an Intel-provisioned quoting enclave (QE). The quoting enclave then receives and verifies the report, and converts the report into a &lt;em&gt;quote&lt;/em&gt;, which is signed with the QE private key.&lt;/p&gt;

&lt;p&gt;The quoting enclave (QE) is provisioned by Intel as part of the &lt;a href="https://downloadmirror.intel.com/729371/Intel%20SGX%20PSW%20Release%20Notes%20for%20Windows%20OS.pdf" rel="noopener noreferrer"&gt;Intel SGX Platform Software (PSW)&lt;/a&gt;. The QE is tasked with verifying a local attestation report (described earlier) and using its public key to sign the report, which can be verified later. The signature uses a group signature scheme called Intel Enhanced Privacy ID (EPID) to ensure that a signature cannot be linked to a particular signer, but just to a member of the group.&lt;/p&gt;

&lt;h5&gt;
  
  
  Verification
&lt;/h5&gt;

&lt;p&gt;Remote attestation quotes may be verified by validating whether the signature they contain is valid, which can be done by using either an EPID public key certificate or an attestation verification service, such as the &lt;a href="https://software.intel.com/en-us/articles/intel-software-guard-extensions-remote-attestation-end-to-end-example" rel="noopener noreferrer"&gt;Intel Attestation Service (IAS)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plausible Deniability
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.iso.org/standard/23615.html" rel="noopener noreferrer"&gt;ISO non-repudiation framework&lt;/a&gt; states that the goal of non-repudiation is ‛to collect, maintain, make available and validate irrefutable evidence concerning a claimed event or action in order to resolve disputes about the occurrence or non-occurrence of the event or action’.&lt;/p&gt;

&lt;p&gt;Plausible deniability is a concept closely related to &lt;em&gt;non-repudiation&lt;/em&gt; in that it has the opposite stated goal: it is desired that any evidence regarding a disputed event be plausibly refutable. In particular, a protocol executed between two entities, Alice and Bob, and observed by an external observer Eve is &lt;a href="https://www.isg.rhul.ac.uk/~kp/IKE.ps" rel="noopener noreferrer"&gt;plausibly deniable&lt;/a&gt; if its execution does not generate any evidence that can be used to irrefutably demonstrate Alice's or Bob's involvement. Note that this definition permits mutual authentication of Alice and Bob insofar as this mutual authentication is non-transferrable (i.e., it has no meaning for a third party).&lt;/p&gt;

&lt;p&gt;Following &lt;a href="https://doi.org/10.1007/978-3-642-00457-5_10" rel="noopener noreferrer"&gt;Y. Dodis &lt;em&gt;et al.&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://doi.org/10.1145/1180405.1180454" rel="noopener noreferrer"&gt;M. di Raimondo &lt;em&gt;et al.&lt;/em&gt;&lt;/a&gt;, we can model deniability in the paradigm of simulation. For this, we assume an arbitrary protocol π in which there is a sender 𝐴, a receiver 𝐵, an informant 𝐸 who observes the protocol execution, a misinformer 𝑀 who does not observe the protocol run but executes a simulated protocol π* and a judge 𝐽 who will rule at the end of the protocol whether communication took place between 𝐴 and 𝐵. The protocol π is deniable if 𝐽 is not able to distinguish between 𝐸 and 𝑀.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;Authentication was presented earlier in the context of authenticated encryption as a cryptographic process conferring &lt;em&gt;integrity&lt;/em&gt;. In the context of communications, authentication has a broader meaning that encompasses the entire communication, including &lt;em&gt;provenance&lt;/em&gt;. Generally speaking, for a message ℳ, the authenticator 𝓐 allows a verifier 𝑉 to assess not only whether the message ℳ was tampered with but also whether it originated from the expected party, that is that ℳ was sent by some party 𝐴 and not from an unauthorised party 𝖢. Although authentication is useful to verify that messages are genuine, the way that ℳ and 𝓐 are tied together, possibly to a sender 𝐴, may reveal information to parties external to the protocol as to 𝐴's involvement.&lt;/p&gt;

&lt;p&gt;Working in the deniability framework set forth above, authentication is deniable if it does not give the informant 𝐸 any advantage over the misinformant 𝑀 in convincing the judge. We will examine three different authentication schemes and see how deniability is affected.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 1: No authentication
&lt;/h4&gt;

&lt;p&gt;In this case, the protocol π provides no authentication. Note that it is impossible for the judge to tell which messages are genuine (meaning that the misinformant is able to forge messages that are indistinguishable from any real messages sent by the sender). This protocol is therefore deniable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 2: Digital signatures
&lt;/h4&gt;

&lt;p&gt;In this case, the protocol π uses digital signatures for authentication. The sender has a key pair (𝐈ₐ, 𝐢ₐ), where 𝐢ₐ is used for verification and is public and 𝐈ₐ is used for generating an authenticator and is a secret known only by the sender. Assuming that generating a valid authenticator without knowledge of 𝐈ₐ is infeasible, the judge can now distinguish the informant from the misinformant because the latter is unable to furnish messages that validate correctly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 3: Symmetric authentication
&lt;/h4&gt;

&lt;p&gt;In this case, the protocol π uses symmetric authentication, such as that provided by AES-GCM. The sender and the receiver agree on a key 𝐾 and the sender transmits messages encrypted and authenticated under this key, which are verified and decrypted by the receiver using the same key. Note that because 𝐾 is a shared secret, the receiver (or anyone who knows 𝐾) can forge messages that are indistinguishable from genuine messages from the sender. Because forgeries are possible, the judge cannot distinguish the informant from the misinformant.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Securing the machine refers in this case to applying a combination of physical and technical tamper-evident seals such that any modifications to the execution environment be noticed if not completely prevented. As an example, administrator-level software access could be disabled, the entire software stack could be placed in read-only memory and the entire machine could be encased in concrete and then shipped to a secure location. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;For the purposes of this example, the state 𝑺 may be assumed to contain a nonce, a timestamp or some other similar measure that assures freshness. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>tee</category>
      <category>attestation</category>
      <category>security</category>
      <category>sgx</category>
    </item>
    <item>
      <title>Benchmarking in C (for x86 and x64)</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Mon, 05 Sep 2022 19:43:51 +0000</pubDate>
      <link>https://dev.to/apeleg/benchmarking-in-c-for-x86-and-x64-2lc2</link>
      <guid>https://dev.to/apeleg/benchmarking-in-c-for-x86-and-x64-2lc2</guid>
      <description>&lt;p&gt;Benchmarks are extremely useful to see how performant some code or operation is and a requirement for any empirical decision making. After all, how can we know with any certainty if some library is faster than another one without testing?&lt;/p&gt;

&lt;h2&gt;
  
  
  The basics of benchmarking
&lt;/h2&gt;

&lt;p&gt;At its core, benchmarking is quite a simple idea: we want to know how long a certain operation takes. Some simple (and naïve) pseudocode representing this can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start &amp;lt;- getCurrentTime()
runOperation()
end &amp;lt;- getCurrentTime()

print("Operation took: ", end - start)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Astute readers will notice a few issues with the above snippet. Let's go over some of these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operation time
&lt;/h3&gt;

&lt;p&gt;As with any real-world operation, how long &lt;code&gt;runOperation()&lt;/code&gt; takes is variable, and by having a single measurement we risk that it may not be representative. We can mitigate this by having several measurements and computing statistics, such as the &lt;em&gt;average&lt;/em&gt; time.&lt;/p&gt;

&lt;p&gt;A second and related issue is that in many applications there is a &lt;em&gt;warm-up&lt;/em&gt;, meaning that the first few times &lt;code&gt;runOperation()&lt;/code&gt; is executed it may take longer than subsequent executions, and that, because the operation is executed repeatedly, the time it takes after warming up may be more representative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time measurements
&lt;/h3&gt;

&lt;p&gt;Another consideration is how exactly &lt;code&gt;getCurrentTime()&lt;/code&gt; works, as we need to understand what we are measuring. Ideally, we are after time measurements that don't interfere with &lt;code&gt;runOperation()&lt;/code&gt;, that are high-resolution (so that our measurements are accurate) and that are monotonic. &lt;/p&gt;

&lt;h4&gt;
  
  
  Out of order executions
&lt;/h4&gt;

&lt;p&gt;A further complication is that just because we wrote our code to execute &lt;code&gt;runOperation()&lt;/code&gt; in between &lt;code&gt;getCurrentTime()&lt;/code&gt; calls, it doesn't mean that the the code will actually be executed in this manner, because processors often implement &lt;em&gt;out-of-order&lt;/em&gt; execution. With benchmarks, we want time measurements to be executed exactly as specified and not while  &lt;code&gt;runOperation()&lt;/code&gt; is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Towards an implementation
&lt;/h2&gt;

&lt;p&gt;Most modern operating systems provide some sort of abstraction for time measurements, such as &lt;code&gt;clock_gettime(2)&lt;/code&gt; in POSIX systems or &lt;code&gt;QueryPerformanceCounter&lt;/code&gt; in Windows systems. While these abstractions can be useful, it is possible to use native instructions to run accurate benchmarks without relying on any system or library calls.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;x86&lt;/code&gt; (and the nowadays more common 64-bit x86-64 &lt;em&gt;aka&lt;/em&gt; &lt;code&gt;x64&lt;/code&gt; &lt;em&gt;aka&lt;/em&gt; &lt;code&gt;amd64&lt;/code&gt;) architecture, we can use the &lt;a href="https://www.felixcloutier.com/x86/rdtsc" rel="noopener noreferrer"&gt;rdtsc&lt;/a&gt; instruction to read the Time Stamp Counter (TSC) register. If we read the TSC before and after executing our code of interest, we can determine how many CPU cycles elapsed, which we can use for comparisons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the TSC
&lt;/h3&gt;

&lt;p&gt;We can see how the TSC can be used for benchmarks in &lt;a href="https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf" rel="noopener noreferrer"&gt;Gabriele Paoloni's white paper&lt;/a&gt;. This white paper presents a good introduction to some of the challenges discussed when carrying out measurements and a viable approach for an implementation.&lt;/p&gt;

&lt;p&gt;The basic approach can be summarised as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPUID ; serialise
RDTSC ; read the clock
MOV start_cycles_high, edx
MOV start_cycles_low, eax
; Call the function to benchmark here
RDTSCP
MOV end_cycles_high, edx
MOV end_cycles_low, eax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;a href="https://www.felixcloutier.com/x86/cpuid" rel="noopener noreferrer"&gt;cpuid&lt;/a&gt; is used for &lt;em&gt;serialisation&lt;/em&gt;, i.e., ensuring that all previous instructions before the benchmarking code have been executed. In addition, &lt;a href="https://www.felixcloutier.com/x86/rdtscp" rel="noopener noreferrer"&gt;rdtscp&lt;/a&gt; is called for the &lt;code&gt;end&lt;/code&gt; measurement. This is because, unlike &lt;code&gt;rdtsc&lt;/code&gt;, &lt;code&gt;rdtscp&lt;/code&gt; waits for all previous instructions to finish executing before reading the counter. The reason why we need &lt;code&gt;cpuid&lt;/code&gt; when starting the benchmark and we can't just use &lt;code&gt;rdtscp&lt;/code&gt; is that we also want the function to benchmark to start executing after all other code has finished executing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improving measurements
&lt;/h4&gt;

&lt;p&gt;One of the first things we can address is that while a &lt;em&gt;serialisation&lt;/em&gt; instruction is needed, &lt;code&gt;cpuid&lt;/code&gt; is a relatively onerous instruction. &lt;code&gt;lfence&lt;/code&gt; is an less onerous instruction that is also serialising, and in non-Intel manufacturers, &lt;code&gt;mfence&lt;/code&gt;, which can be even more performant, is also serialising. Hence, we can use one of these instructions instead of &lt;code&gt;cpuid&lt;/code&gt; (let's call it &lt;code&gt;xfence&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A second change we can make is that, to make it more explicit that the &lt;code&gt;mov&lt;/code&gt; instructions following &lt;code&gt;rdtscp&lt;/code&gt; must be executed in that order, and after the code to be benchmarked, we can call &lt;code&gt;xfence&lt;/code&gt; between &lt;code&gt;rdtscp&lt;/code&gt; and the first &lt;code&gt;mov&lt;/code&gt;. Thus we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;XFENCE ; serialise
RDTSC ; read the clock
MOV start_cycles_high, edx
MOV start_cycles_low, eax
; Call the function to benchmark here
RDTSCP
XFENCE ; serialise
MOV end_cycles_high, edx
MOV end_cycles_low, eax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Warm-up measurements
&lt;/h4&gt;

&lt;p&gt;As previously discussed, executing instructions the first few times might take a different time than executions that follow them. We can address this by calling &lt;code&gt;rdtsc&lt;/code&gt; and &lt;code&gt;xfence&lt;/code&gt; a few times before our benchmark code, so that we get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;XFENCE
RDTSC
XFENCE
RDTSC
XFENCE
RDTSC
XFENCE ; serialise
RDTSC ; read the clock
MOV start_cycles_high, edx
MOV start_cycles_low, eax
; Call the function to benchmark here
RDTSCP
XFENCE ; serialise
MOV end_cycles_high, edx
MOV end_cycles_low, eax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Measuring in a loop
&lt;/h4&gt;

&lt;p&gt;Now that we have established how to conduct measurements, we can start writing some code to run benchmark our code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;START_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;runOperation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;likely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;END_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;end&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_e&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unexpected error occurred benchmarking type %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] ERROR&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;compute_statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code won't yet compile, because there are many things yet undefined, but we can see that it calls &lt;code&gt;runOperation()&lt;/code&gt; for &lt;code&gt;ITERATIONS&lt;/code&gt; time, calling &lt;code&gt;START_MEASUREMENT&lt;/code&gt; (which we can later define as a macro) before starting and calling &lt;code&gt;END_MEASUREMENT&lt;/code&gt; once it's done. In addition, we're calling &lt;code&gt;compute_statistics&lt;/code&gt; at the end of the loop, which will compute some statistics about the operation (such as the minimum, maximum and mean time), which is our desired result from the benchmark.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Different compilers
&lt;/h4&gt;

&lt;p&gt;Since we're using C and executing native instructions, we need to use the &lt;em&gt;asm&lt;/em&gt; keyword. Unfortunately, this is implementation defined. We'll address the Microsoft and GNU dialects, which will cover most implementations relevant for the x86 architecture.&lt;/p&gt;

&lt;p&gt;For Microsoft, the syntax is &lt;code&gt;__asm INSTRUCTION&lt;/code&gt;, whereas for GNU the syntax is &lt;code&gt;__asm__ ("INSTRUCTION")&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  C standard versions
&lt;/h4&gt;

&lt;p&gt;A further challenge is that different C versions (for example, ANSI C and C99) provide different types, and for compatibility we might want our code to use the latest types when available while still being able to run on older compilers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Baseline measurement
&lt;/h4&gt;

&lt;p&gt;Lastly, we want to run a baseline measurement for a do-nothing operation to determine the overhead of our measurement.&lt;/p&gt;

&lt;h4&gt;
  
  
  Final implementation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef HAVE_CONFIG_H
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;config.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#endif
&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef ITERATIONS
#define ITERATIONS (2048)
#endif
&lt;/span&gt;
&lt;span class="cm"&gt;/* C99 types */&lt;/span&gt;
&lt;span class="cp"&gt;#if defined(__STDC_VERSION__) &amp;amp;&amp;amp; __STDC_VERSION__ &amp;gt;= 199901L &lt;/span&gt;&lt;span class="cm"&gt;/* The compiler supports C99 */&lt;/span&gt;&lt;span class="cp"&gt;
#define SIZE_T_FMT "z"
#define SIZE_T_FMT_TYPE size_t
#define LONGLONG long long
#define LONGDOUBLE long double
#define LONGDOUBLE_FMT "L"
#elif defined(_MSC_VER) &lt;/span&gt;&lt;span class="cm"&gt;/* Some MSVC versions don't fully support C99 */&lt;/span&gt;&lt;span class="cp"&gt;
#define SIZE_T_FMT "I"
#define SIZE_T_FMT_TYPE size_t
#define LONGLONG __int64
#if _MSC_VER &amp;gt;= 1310
#define LONGDOUBLE long double
#define LONGDOUBLE_FMT "L"
#else
#define LONGDOUBLE double
#define LONGDOUBLE_FMT ""
#endif
#else
#define SIZE_T_FMT "l" &lt;/span&gt;&lt;span class="cm"&gt;/* Old compiler, use long */&lt;/span&gt;&lt;span class="cp"&gt;
#define SIZE_T_FMT_TYPE long
#if defined(__GNUC__) &lt;/span&gt;&lt;span class="cm"&gt;/* GCC supports long long as an extension */&lt;/span&gt;&lt;span class="cp"&gt;
#define LONGLONG long long
#else
#define LONGLONG long
#define __extension__ &lt;/span&gt;&lt;span class="cm"&gt;/* */&lt;/span&gt;&lt;span class="cp"&gt;
#endif
#define LONGDOUBLE double
#define powl pow
#define sqrtl sqrt
#define LONGDOUBLE_FMT ""
#endif
&lt;/span&gt;&lt;span class="cm"&gt;/* End C99 types */&lt;/span&gt;

&lt;span class="cm"&gt;/* Compatibility */&lt;/span&gt;
&lt;span class="cp"&gt;#if !defined(__has_attribute) &lt;/span&gt;&lt;span class="cm"&gt;/* Clang &amp;amp; newer GCC */&lt;/span&gt;&lt;span class="cp"&gt;
#define __has_attribute(x) 0
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* !defined(__has_attribute) */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#if !defined(__has_builtin) &lt;/span&gt;&lt;span class="cm"&gt;/* Clang */&lt;/span&gt;&lt;span class="cp"&gt;
#define __has_builtin(x) 0
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* !defined(__has_builtin) */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#if !defined(INFINITY)
#define INFINITY ((double) 1.0e120)
#endif
&lt;/span&gt;
&lt;span class="cp"&gt;#if defined(_MSC_VER) &lt;/span&gt;&lt;span class="cm"&gt;/* MSVC-specific */&lt;/span&gt;&lt;span class="cp"&gt;
#define NOINLINE __declspec(noinline) &lt;/span&gt;&lt;span class="cm"&gt;/* MSVC extension */&lt;/span&gt;&lt;span class="cp"&gt;
#elif __has_attribute(__noinline__) || (defined(__GNUC__) &amp;amp;&amp;amp; (__GNUC__ &amp;gt; 3) || (__GNUC__ == 3 &amp;amp;&amp;amp; defined(__GNUC_MINOR__) &amp;amp;&amp;amp; __GNUC_MINOR__ &amp;gt;= 1))
#define NOINLINE __attribute__ ((noinline)) &lt;/span&gt;&lt;span class="cm"&gt;/* GNU extension */&lt;/span&gt;&lt;span class="cp"&gt;
#else
#define NOINLINE &lt;/span&gt;&lt;span class="cm"&gt;/* not supported */&lt;/span&gt;&lt;span class="cp"&gt;
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* defined(_MSC_VER) */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#if __has_builtin(__builtin_expect) || (defined(__GNUC__) &amp;amp;&amp;amp; (__GNUC__ &amp;gt; 3) || (__GNUC__ == 3 &amp;amp;&amp;amp; defined(__GNUC_MINOR__) &amp;amp;&amp;amp; __GNUC_MINOR__ &amp;gt;= 1))
#define likely(x) __builtin_expect((x),1) &lt;/span&gt;&lt;span class="cm"&gt;/* GNU extension */&lt;/span&gt;&lt;span class="cp"&gt;
#else
#define likely(x) x
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* __has_builtin(__builtin_expect) */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#if defined(_MSC_VER) &lt;/span&gt;&lt;span class="cm"&gt;/* MSVC inline assembler */&lt;/span&gt;&lt;span class="cp"&gt;
#if !defined(intel) &lt;/span&gt;&lt;span class="cm"&gt;/* Use LFENCE for Intel processors and MFENCE for other manufacturers */&lt;/span&gt;&lt;span class="cp"&gt;
#define xFENCE __asm _emit 0x0f __asm _emit 0xae __asm _emit 0xf0 &lt;/span&gt;&lt;span class="cm"&gt;/* MFENCE */&lt;/span&gt;&lt;span class="cp"&gt;
#else
#define xFENCE __asm _emit 0x0f __asm _emit 0xae __asm _emit 0xe8 &lt;/span&gt;&lt;span class="cm"&gt;/* LFENCE */&lt;/span&gt;&lt;span class="cp"&gt;
#endif
#define RDTSC rdtsc
#define RDTSCP rdtscp
&lt;/span&gt;
&lt;span class="cp"&gt;#define WARMUP_MEASUREMENT() __asm { \
        xFENCE \
       __asm RDTSC \
        xFENCE \
        __asm RDTSC \
        xFENCE \
        __asm RDTSC \
        xFENCE \
}
&lt;/span&gt;
&lt;span class="cp"&gt;#define START_MEASUREMENT(HI, LO) __asm { \
        xFENCE \
        __asm RDTSC \
        __asm mov LO,eax \
        __asm mov HI,edx \
}
&lt;/span&gt;
&lt;span class="cp"&gt;#define END_MEASUREMENT(HI, LO) __asm { \
        __asm RDTSCP \
        xFENCE \
        __asm mov LO,eax \
        __asm mov HI,edx \
}
&lt;/span&gt;
&lt;span class="cp"&gt;#define ZERO_REGISTER(OUT) __asm mov OUT,0
#elif defined(__GNUC__) &lt;/span&gt;&lt;span class="cm"&gt;/* GCC-style extended asm */&lt;/span&gt;&lt;span class="cp"&gt;
#if !defined(intel) &lt;/span&gt;&lt;span class="cm"&gt;/* Use LFENCE for Intel processors and MFENCE for other manufacturers */&lt;/span&gt;&lt;span class="cp"&gt;
#define xFENCE ".byte 0x0f, 0xae, 0xf0\n" &lt;/span&gt;&lt;span class="cm"&gt;/* MFENCE */&lt;/span&gt;&lt;span class="cp"&gt;
#else
#define xFENCE ".byte 0x0f, 0xae, 0xe8\n" &lt;/span&gt;&lt;span class="cm"&gt;/* LFENCE */&lt;/span&gt;&lt;span class="cp"&gt;
#endif
#define RDTSC ".byte 0x0f, 0x31\n"        &lt;/span&gt;&lt;span class="cm"&gt;/* RDTSC */&lt;/span&gt;&lt;span class="cp"&gt;
#define RDTSCP ".byte 0x0f, 0x01, 0xf9\n" &lt;/span&gt;&lt;span class="cm"&gt;/* RDTSCP */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define WARMUP_MEASUREMENT() __asm__ volatile ( \
        xFENCE \
        RDTSC \
        xFENCE \
        RDTSC \
        xFENCE \
        RDTSC \
        xFENCE \
        : : : "%eax", "%edx", "memory" \
)
&lt;/span&gt;
&lt;span class="cp"&gt;#define START_MEASUREMENT(HI, LO) __asm__ volatile ( \
        xFENCE \
        RDTSC \
        : "=d" (HI), "=a" (LO) : : "memory" \
)
&lt;/span&gt;
&lt;span class="cp"&gt;#define END_MEASUREMENT(HI, LO) __asm__ volatile ( \
        RDTSCP \
        xFENCE \
        : "=d" (HI), "=a" (LO) : : "%ecx", "memory" \
)
#define ZERO_REGISTER(OUT) __asm__ volatile ("xor %0, %0" : "=r"(OUT) : : )
#else &lt;/span&gt;&lt;span class="cm"&gt;/* Unsupported compiler. */&lt;/span&gt;&lt;span class="cp"&gt;
#define WARMUP_MEASUREMENT() &lt;/span&gt;&lt;span class="cm"&gt;/* */&lt;/span&gt;&lt;span class="cp"&gt;
#define START_MEASUREMENT(HI, LO) HI = 0; LO = 0
#define END_MEASUREMENT(HI, LO) HI = 0; LO = 0
#define ZERO_REGISTER(OUT) OUT = 0
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* defined(_MSC_VER) */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cm"&gt;/* End Compatibility */&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;LONGLONG&lt;/span&gt; &lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* Function signatures */&lt;/span&gt;
&lt;span class="n"&gt;NOINLINE&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;do_nothing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;NOINLINE&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;compute_statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cm"&gt;/* End function signatures */&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;do_nothing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;ZERO_REGISTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;ZERO_REGISTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;compute_statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="n"&gt;sum1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sum2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mean_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variance_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;INFINITY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;INFINITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;sum1&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;max_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;min_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;min_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mean_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sum2&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;powl&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mean_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;variance_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sum2&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0L&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mean_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variance_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LONGDOUBLE&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;u32&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_high_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_high_e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;u64&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;deltas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;WARMUP_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="cm"&gt;/* Nothing */&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] Starting benchmark&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;START_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;do_nothing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;likely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;END_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;end&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_e&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unexpected error occurred benchmarking type %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] ERROR&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;compute_statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s]&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt; [%"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e - %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e] mean: %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e (std. dev.: %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e) N:%"&lt;/span&gt; &lt;span class="n"&gt;SIZE_T_FMT&lt;/span&gt; &lt;span class="s"&gt;"u&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sqrtl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIZE_T_FMT_TYPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/* Something */&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] Starting benchmark&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ITERATIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;START_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;likely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;END_MEASUREMENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cycles_high_e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_s&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_s&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;end&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cycles_high_e&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mo"&gt;040&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cycles_low_e&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unexpected error occurred benchmarking type %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] ERROR&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;compute_statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s]&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt; [%"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e - %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e] mean: %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e (std. dev.: %"&lt;/span&gt; &lt;span class="n"&gt;LONGDOUBLE_FMT&lt;/span&gt; &lt;span class="s"&gt;"e) N:%"&lt;/span&gt; &lt;span class="n"&gt;SIZE_T_FMT&lt;/span&gt; &lt;span class="s"&gt;"u&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"NULL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sqrtl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variance&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIZE_T_FMT_TYPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>benchmarking</category>
      <category>performance</category>
      <category>c</category>
      <category>x86</category>
    </item>
    <item>
      <title>Smidyo x Apeleg = Vector Express</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Fri, 12 Aug 2022 11:07:00 +0000</pubDate>
      <link>https://dev.to/apeleg/smidyo-x-exact-realty-vector-express-34bn</link>
      <guid>https://dev.to/apeleg/smidyo-x-exact-realty-vector-express-34bn</guid>
      <description>&lt;p&gt;Apeleg have partnered with &lt;a href="https://smidyo.com" rel="noopener noreferrer"&gt;Smidyo&lt;/a&gt; in a joint venture to provide &lt;a href="https://vector.express" rel="noopener noreferrer"&gt;Vector Express&lt;/a&gt;. Vector Express is a SaaS platform that addresses and simplifies many common tasks when working with vector files, providing conversion between a wide range of vector image formats as well as processing and analysis.&lt;/p&gt;

&lt;p&gt;Vector Express is a unique offering because of the diversity of formats that it can handle, from AutoCAD DXF and DWG files to HP-GL to more common formats SVG and PDF and because of its flexibility: it can be used manually with the frontend at &lt;a href="https://vector.express" rel="noopener noreferrer"&gt;Vector Express&lt;/a&gt; or integrated with other systems with a &lt;a href="https://github.com/vector-express/vectorexpress-api" rel="noopener noreferrer"&gt;flexible and well-documented API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At Apeleg, we view this project as a long-term partnership that will further our goal of offering infrastructure to our customers to automate and improve their business processes and are excited to be able to take a more active role in developing Vector Express.&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;Vector Express was born as an internal project in Smidyo to support Smidyo's main offering, Smidyo's Quotation Portal, a platform for quote automation. Vector Express played a vital role in the platform for businesses in the laser cutting sector, which require handling a large volume of vector images and where an accurate and reliable analysis of vector files is essential to providing accurate price estimates.&lt;/p&gt;

&lt;p&gt;As the platform grew so did Vector Express and soon it was clear that it could be useful as a service in its own right. Apeleg was involved in some of the design and development of Vector Express version 2, which introduced a new API and a more modular design for greater scalability.&lt;/p&gt;

&lt;p&gt;At the time, Vector Express ran on a server with a graphical interface to run the different operations. The new version of Vector Express maintained and extended the existing functionality while eliminating the need for a graphical interface. It was also engineered with containers in mind so that it can be easily deployed in a way that is scalable and that its functionality can be extended for users requiring bespoke functionality.&lt;/p&gt;

&lt;p&gt;Since Vector Express version 2 was released, it has grown in use and adoption, becoming an independent offering of Smidyo's and it has been extended with new functionality, from being a conversion tool to becoming a tool that can also process images and run various analyses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;First and foremost, our priority is ensuring the continued operation of the Vector Express API with the reliability and accuracy that the service has become known for among its free and paid users. To attain this, we are migrating Vector Express to dedicated infrastructure to improve response time and processing capacity.&lt;/p&gt;

&lt;p&gt;Once this first step is completed, we already have some features planned for improving the service. Although Vector Express has been designed with modularity in mind, it runs mostly synchronously and has a complex setup of interrelated dependencies. As we have gained experience from Vector Express and other projects, we believe quality of service can be improved by switching to an event-based and asynchronous model powered by microservices, which will not only improve response times but will also provide significantly enhanced horizontal scaling capabilities and isolation.&lt;/p&gt;

&lt;p&gt;We also want to include &lt;a href="https://github.com/ApelegHQ/svgcut" rel="noopener noreferrer"&gt;svgcut&lt;/a&gt; as a processor, as well as improve the frontend to make it a standalone application that can be used for those that don't require using an API and need more capabilities than the free plan offers.&lt;/p&gt;

</description>
      <category>vector</category>
      <category>infrastructure</category>
      <category>processing</category>
      <category>saas</category>
    </item>
    <item>
      <title>Handling IP addresses</title>
      <dc:creator>Ricardo Iván Vieitez Parra</dc:creator>
      <pubDate>Fri, 12 Aug 2022 11:04:35 +0000</pubDate>
      <link>https://dev.to/apeleg/handling-ip-addresses-2701</link>
      <guid>https://dev.to/apeleg/handling-ip-addresses-2701</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgsyad0c0d11jeqxu6st.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgsyad0c0d11jeqxu6st.png" title="IP addresses are sent along with all network traffic." alt="Screenshot of Wireshark" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IP addresses pose unique technical challenges because they are sent in the clear with every network request and because they may in some cases identify or help identify an individual, making them personal data. In the EU, this was affirmed already in &lt;a href="https://curia.europa.eu/juris/document/document.jsf?docid=184668&amp;amp;doclang=EN" rel="noopener noreferrer"&gt;case C-582/14&lt;/a&gt; and, with the coming into force of the GDPR, this criterion has been applied to the transfer of IP addresses to the United States in the popular website analytics tool Google Analytics by data protection agencies in several countries already, such as &lt;a href="https://noyb.eu/sites/default/files/2022-01/E-DSB%20-%20Google%20Analytics_DE_bk.pdf" rel="noopener noreferrer"&gt;Austria&lt;/a&gt;, &lt;a href="https://autoriteitpersoonsgegevens.nl/sites/default/files/atoms/files/handleiding_privacyvriendelijk_instellen_google_analytics.pdf" rel="noopener noreferrer"&gt;the Netherlands&lt;/a&gt; and &lt;a href="https://www.cnil.fr/en/use-google-analytics-and-data-transfers-united-states-cnil-orders-website-manageroperator-comply" rel="noopener noreferrer"&gt;France&lt;/a&gt;, and others that may soon follow suit, like &lt;a href="https://www.datatilsynet.no/aktuelt/aktuelle-nyheter-2022/google-analytics-kan-vare-ulovlig/" rel="noopener noreferrer"&gt;Norway&lt;/a&gt;. Similarly, in a recent case in Germany, &lt;a href="https://openjur.de/u/2384915.html" rel="noopener noreferrer"&gt;a website operator was ordered to compensate a visitor for embedding Google Fonts&lt;/a&gt; and thus violating the visitor's privacy by sharing their IP address with Google.&lt;/p&gt;

&lt;p&gt;Since IP addresses are sent along with every packet on the Internet and precisely because they identify the sender to some extent, they also have many practical uses. For instance, they are a valuable data point for detecting and investigating data breaches and other security incidents. They can also be used as input to automated moderation or filtering systems for purposes like blocking spam or online fraud and can also provide vital analytics for responding to traffic, like finding optimal route paths for transmitting content to our users.&lt;/p&gt;

&lt;p&gt;Fortunately, regulations like the GDPR contemplate these use cases under categories like 'overriding legitimate interest', which means that not &lt;em&gt;all&lt;/em&gt; use or processing of IP addresses is disallowed without explicit user consent. However, since IP addresses are personal information, it is important to ensure that they are only used in connection to essential purposes that don't require explicit consent or that consent is obtained prior to processing. The particular challenge of IP addresses compared to other personal information is that, by the nature of how the Internet works, they can be very easily relayed to third parties by things as simple as having the user download a file.&lt;/p&gt;

&lt;p&gt;To avoid this situation, we are left with three options: not using external resources, obtaining the user's consent or self-hosting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not using (certain) external resources
&lt;/h2&gt;

&lt;p&gt;While this addresses the concern of sharing the user's IP address without consent, it's not always a viable option, because those resources may very well provide value to our website and our users, for example, jQuery might what our website uses to provide an interactive page, or those resources might be fonts that are important to use for consistent branding. Nonetheless, the option of not using an external resource is a valid one to consider because, if feasible, it is generally the easiest alternative. This option is valid for resources that are not really used or which are easily replaceable.&lt;/p&gt;

&lt;p&gt;Apart from not sharing IP addresses with third parties, the advantage of not using certain resources is that we get to improve the user's experience by having a small page that loads faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obtaining the user's consent
&lt;/h2&gt;

&lt;p&gt;While this is a valid option to consider, it might not always be practical or a preferred solution, because the user consent needs to come first, before any resource is loaded. Take the example of public CDNs, which host resources that may be essential for having our website work, or at least to provide a rich and high-quality user experience. If we seek to have the user's consent, depending on what we use those external resources for, in practice it means that we will deliver a degraded user experience until the consent is obtained. While this could be acceptable for certain sections or functionality of our page, it probably isn't for core functionality. More importantly, it can unnecessarily pressure the user into giving consent (removing the 'freely given' element of it) since doing otherwise implies having a poorer experience interacting with our site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosting
&lt;/h2&gt;

&lt;p&gt;Self-hosting, as the name implies, is hosting resources ourselves in our own infrastructure. While doing this can in some cases be an involved process, especially if we are implementing self-hosting on a site that currently loads several resources from third party origins, when done well it has the advantages of not leaking visitors' IP addresses to others, not requiring explicit consent and not resulting in limited functionality or interactivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server logs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8d7pl8q0brlv4oc77xv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8d7pl8q0brlv4oc77xv.png" title="The typical server access log includes IP addresses of incoming connections by default." alt="Listing of a typical access log" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Self-hosing doesn't address &lt;em&gt;all&lt;/em&gt; of the challenges that come with processing personal information, but it does put us back in control and from that position we can implement policies that protect our users' privacy. One of those challenges is that most web servers by default store incoming IP addresses in their various logs. The fact that IP addresses are stored is not necessarily a problem, as they can provide useful information for, for example, adequately responding to a security incident.&lt;/p&gt;

&lt;p&gt;However, it's crucial to treat these entries with IP addresses as containing personal information and ensuring the right procedures and policies are in place, starting with the use to be given to the information. For example, while it is most certainly appropriate to keep logs for security purposes, using the IP entries in log files to also correlate sessions and derive behavioural analytics is likely to require the users' informed and actively given consent.&lt;/p&gt;

&lt;p&gt;A second consideration when keeping log files with IP addresses is elaborating a data retention policy. The benefits of having logs of IP addresses for security purposes diminish over time, and need to be weighed against the disadvantages, namely that storing information opens us up to leaking that information (for example, by accident or due to server compromise) and that users might request their personal information be deleted, and handling these requests manually can be time-consuming and expensive. Hence, in many cases the optimal solution is retaining logs for a period long enough to respond to incidents but short enough to avoid the information turning into a liability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different jurisdictions
&lt;/h3&gt;

&lt;p&gt;Different jurisdictions have different regulations and requirements about processing personal data, and what is permissible or even required in one place can be disallowed in another. Therefore, in as much as it is possible, the preferred solution is avoiding transferring personal information between jurisdictions, especially between those that don't have comparable levels of data protection. One example are data transfers between the EU and the US, which after the &lt;a href="https://curia.europa.eu/juris/document/document.jsf?docid=228677&amp;amp;doclang=en" rel="noopener noreferrer"&gt;ECJ invalidated the Privacy Shield framework&lt;/a&gt; require additional considerations to ensure that all EU regulations are being followed.&lt;/p&gt;

&lt;p&gt;If we host our server in the United States and receive visitors from the EU, safeguards need to be in place to ensure that all personal data being transferred, including IP addresses, are going to be handled appropriately and in accordance with the EU regulations. Since this can be burdensome, a solution for organisations using a CDN with many local points of presence might be to simply implement firewall policies at the edge and strip requests of all personal information, thus avoiding this requirement. For example, Cloudflare offers request transform rules that can remove information present in request headers, like IP addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analytics services
&lt;/h2&gt;

&lt;p&gt;Analytics provide insightful information about how our web properties are used, which can in turn be valuable feedback for improving user experience and identifying areas for improvement. On the other hand, when implementing analytics, as with everything else, we must consider how our visitors' personal data will be processed and the basis for that processing. There exist a wide range of services, including the popular and ubiquitous Google Analytics, that enable publishers to collect and process various types of metrics.&lt;/p&gt;

&lt;p&gt;However, using third party tools presents many of the same challenges as loading content from external sources do. Although Google Analytics has an opt-mechanism to avoid collecting users' IP addresses, as mentioned earlier, these measures have been found to be inadequate in many countries in the EU. The solutions are also in many ways the same as for loading external content.&lt;/p&gt;

&lt;p&gt;Since analytics services are in most cases non-essential, the alternative of collecting users' consent could in this case be more viable than it is for loading essential libraries, and is implemented in many websites nowadays in the shape of consent prompts. It is still however not necessarily good for neither user experience nor user trust having to present these prompts and warn of the risks of cross-border data transfers.&lt;/p&gt;

&lt;p&gt;When using analytics services provided by a third party, it can be worth considering to proxy connections to the service through our own infrastructure instead of having users connect directly to the third party analytics collection endpoint. This way, it is possible to scrub the data being sent and remove any personal information. In the case of Google Analytics, this means proxying requests to &lt;code&gt;https://www.google-analytics.com/collect&lt;/code&gt; with our own domain.&lt;/p&gt;

&lt;p&gt;Analytics services can also be self-hosted. While this is a more expensive solution from a management perspective, it is the solution that affords the greatest flexibility for implementing and enforcing privacy protections. There are many offerings in this space, including established projects like &lt;a href="https://matomo.org/" rel="noopener noreferrer"&gt;Matomo&lt;/a&gt; (formerly Piwik) and &lt;a href="http://www.openwebanalytics.com/" rel="noopener noreferrer"&gt;Open Web Analytics&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>cookies</category>
      <category>ipaddress</category>
    </item>
  </channel>
</rss>
