<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[A blog to (be) inspire(d) (by) others]]></title><description><![CDATA[Kristof is a software dev and works a consultant at Xebia XMS Belgium focussing on DevSecOps and empowering fellow developers through coaching and inspiring.]]></description><link>https://dotnet.kriebbels.me</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 17:14:11 GMT</lastBuildDate><atom:link href="https://dotnet.kriebbels.me/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Introduction to My (Certified??) Ethical Hacker (CEH) Journey!]]></title><description><![CDATA[Introduction
I am going to learn about ethical hacking, which means using hacking skills to protect systems and data. The importance of cybersecurity continues to grow as technology becomes more essential in our lives. Understanding cybersecurity wil...]]></description><link>https://dotnet.kriebbels.me/introduction-to-my-certified-ethical-hacker-ceh-journey</link><guid isPermaLink="true">https://dotnet.kriebbels.me/introduction-to-my-certified-ethical-hacker-ceh-journey</guid><category><![CDATA[cybersecurity]]></category><category><![CDATA[CEHv12 ]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Mon, 11 Nov 2024 13:47:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731333372610/1a632fc7-e6d4-4a00-8a97-7be19d882aeb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>I am going to learn about ethical hacking, which means using hacking skills to protect systems and data. The importance of cybersecurity continues to grow as technology becomes more essential in our lives. Understanding cybersecurity will help me to grow as a software architect in an enterprise size companies. Fifteen years ago, there was a gap between software developers and system engineers. These days, that gap has been closed due to native cloud software development. To spike my career further, I want to be the bridge between the software developers and the cybersecurity experts. Security is difficult and, in my humble opinion, you tend to implement practises when you understand them.</p>
<p>I will learn a 5-day course named <a target="_blank" href="https://iclass.eccouncil.org/courses/certified-ethical-hacker-ceh-v12-sk/">Certified Ethical Hacker (CEH)</a>  in my time. My goal is getting a better understanding. I will take the CEH exam. But my real goals are to have a more in-depth understanding of the whole world of cybersecurity and be the bridge between Security and Development.</p>
<h2 id="heading-overview-of-the-course">Overview of the Course</h2>
<p>The CEH program covers many topics. After seeing the video Module 00, It seems taht I will explore areas like:</p>
<ul>
<li>Foot printing: Gathering information about a target.</li>
<li>Vulnerability Analysis: Finding weaknesses in systems.</li>
<li>Malware Threats: Learning about different types of harmful software.</li>
</ul>
<p>This course should help me think like a hacker while also learning how to defend against cyber threats.</p>
<h2 id="heading-learning-approach">Learning Approach</h2>
<p>As I take the CEH course, it is essential for me to build a strong foundation first. This means learning the basics before moving on to more complex topics. The course is structured with various modules, and I will have both lectures and labs to practice what I learn. </p>
<ul>
<li>Practice in Labs: Creating a Virtual environment where I can practise, so I can engage with the given labs. That should give me hands-on experience and a chance to use different tools. However, they do supply me with a remote lab environment where I can practise. Maybe I will start using there environment and not losing time setting up my own.</li>
<li>Review and Revisit: I will not hesitate to go back to previous lessons and labs. </li>
<li>Books: They do supply me with a book that consists out of 2000 pages :|  . Do I fully understand why I am going to do? </li>
</ul>
<h2 id="heading-exams-in-the-ceh-program">Exams in the CEH Program</h2>
<p>There will be two exams in the CEH program:</p>
<ul>
<li><p>Multiple Choice Exam: This is a multiple-choice test with 125 questions. I hear that I have four hours to complete it, and the passing score ranges from 69% to 84%...</p>
</li>
<li><p>Practical Exam: This exam includes 20 challenges based on lab exercises. Passing both exams will earn me the title of CEH Master, which is a significant achievement in the field of cybersecurity. This will be the more difficult one, I think.</p>
</li>
</ul>
<h2 id="heading-what-can-you-do-with-such-an-exam">What can you do with such an exam?</h2>
<p>Completing the CEH course could open doors for me in cybersecurity and having a CEH certification is a start at least for roles like:</p>
<ul>
<li>Security Analyst</li>
<li>Penetration Tester</li>
<li>Forensics Investigator</li>
</ul>
<p>However, as I stated in the beginning, my goal is to be the bridge between software development and cybersecurity to become a better consultant in development teams in big enterprise, or maybe, who know, a security analyst? ... time will tell.</p>
]]></content:encoded></item><item><title><![CDATA[Tamperproof HTTP Requests]]></title><description><![CDATA[Tamperproof HTTP Requests
In this article we explore data integrity and authenticity when dealing with sensitive information.
This section outlines the fundamental importance of making HTTP request bodies tamperproof, particularly when handling perso...]]></description><link>https://dotnet.kriebbels.me/tamperproof-http-requests</link><guid isPermaLink="true">https://dotnet.kriebbels.me/tamperproof-http-requests</guid><category><![CDATA[JOSE]]></category><category><![CDATA[JWE]]></category><category><![CDATA[Tamperproof]]></category><category><![CDATA[jws]]></category><category><![CDATA[JWT]]></category><category><![CDATA[http]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 12 Oct 2024 16:23:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728750314256/552b7f7a-5a55-4b2c-ac3f-61df073662b8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-tamperproof-http-requests">Tamperproof HTTP Requests</h1>
<p>In this article we explore data integrity and authenticity when dealing with sensitive information.</p>
<p>This section outlines the fundamental importance of making HTTP request bodies tamperproof, particularly when handling personally identifiable information (PII). We introduce digital signatures as a key mechanism for data integrity.</p>
<h2 id="heading-why-should-you-care">Why should you care?</h2>
<p>When extending the user registration process, using Auth0 (an OIDC Provider), it is important to ensure data integrity and authenticity. Particularly when dealing with sensitive information that could lead to personal identity identification (PII) like the national register numbers. </p>
<p>In this blog post, I will explore difficult ways how to achieve this. Making the <code>HTTP</code> request body is tamper-proof is <strong>a</strong> step in protecting data as it moves from one server to another. The use of signatures for <code>HTTP</code> request bodies provides a robust mechanism for ensuring data integrity and security in this context. Frameworks like <code>JOSE</code> (JSON Object Signing and Encryption) can help in this matter.</p>
<p>A lot of the internet is already protected by using the <code>HTTPS</code> protocol, right? Well, <code>HTTPS</code> only encrypts the data; it does not guarantee that the content is not tampered with during transit. <code>HTTPS</code> provides a secure channel but does not protect against all types of tampering. For instance, if data is decrypted and re-encoded, the integrity may be compromised without detection. In scenarios where sensitive data is transferred – such as through webhooks – signing the request body ensures the data's integrity independently of the transport layer's security.</p>
<p><code>HTTP</code> request body signatures add a layer of security by allowing the recipient to verify that the body has not been altered in transit. They act as a digital signature, much like those used in emails, ensuring the integrity of the sent content. </p>
<p>I will also investigate if using an access or ID token could help in this matter. </p>
<h2 id="heading-previously-on">Previously on ...</h2>
<p>Here, we recap earlier discussions on signatures and OpenID Connect, setting the stage for a deeper exploration into data security practices in HTTP requests.</p>
<p>I wrote about OpenID Connect before and how to mock your provider, and thus creating and faking tokens...</p>
<ul>
<li>https://dotnet.kriebbels.me/oauth2-open-id-connect-accessidtoken</li>
<li>https://dotnet.kriebbels.me/signature-validation-required-microsoft-says-no</li>
<li>https://dotnet.kriebbels.me/how-to-read-a-claim-from-a-token-in-dotnet-6</li>
<li>https://xebia.com/blog/openid-connect-mocking-you/</li>
<li>https://xebia.com/blog/openid-connect-mocking-you/</li>
</ul>
<p>I did a talk as well on how to mock your OIDC Provider:</p>
<ul>
<li>https://www.visug.be/Events/92</li>
<li>https://www.updateconference.net/en/2023/session/mock-your-openid-connect-provider</li>
</ul>
<p>This article aims to further expand upon previously covered concepts and enhance understanding.</p>
<h2 id="heading-understanding-jwt-jose-and-accessid-tokens">Understanding <code>JWT</code>, <code>JOSE</code> and Access/ID/... Tokens</h2>
<p>Before we explore individual token types, this section provides an overview of <code>JWT</code> and its role within the broader <code>JOSE</code> ecosystem. That is important for safeguarding data communicated via OpenID Connect and OAuth2 protocols.</p>
<p>OpenID Connect and OAuth2 protocols often leverage <code>JWT</code> to communicate authorization and identification details.</p>
<p>Discussions with colleagues and customers highlight common misuses of <code>JWT</code> as information repositories, necessitating a balance between security and data sensitivity.</p>
<p>There are a lot of tokens in the OpenID Connect world, but because the goal of this document is about making something tamperproof, we will focus on the access token as an example.</p>
<h2 id="heading-access-tokens-explained">Access Tokens Explained</h2>
<p>In this section, gain insights into access tokens, particularly within the <code>JWT</code> format, and how they serve as credentials for accessing protected resources, highlighting their role in ensuring authenticity and confidentiality.</p>
<p>An <strong>access token</strong> is a credential used to access protected resources. When used in a <code>JWT</code> format, it typically contains claims about the user and any permissions granted. These tokens can be JSON Web Signature (<code>JWS</code>) or <code>JSON</code> Web Encryption (<code>JWE</code>) encoded to ensure authenticity and confidentiality, respectively.</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNp1VV1v2jAU_StW9ko3Stu1RVMlIKmqTd1QiTpp4sUkF7hqsDPboU1R__uu4wRMwhyJJNfn3M9DvAsSmUIwDDT8LUAkECJfKb6ZC0Yr58pggjkXhk0yBLpx3TyN8jzDhBuUoot-xDTN4JUrsAzvbQZqiwl0GXYDlEWHoA2KynFtdWj3yxODW26gTqNlPERqbdTundVRz-7uDvAhmyiwwIc4nrIn2w1dO_8pySwt2_GGVekl-_47Zr9GhVmzWL6AYEupmH2VCt-9thxitALOcCWaSGws05K9IjmbKpfxDyi9-ApXa8PkkrU9cFNQW0FoummWcsMZCgMrhaY8kYDrA1FBpBUf0lbJdeMyU9lnX2LFhc6lsiNKioNbu1I4OY7WVnsodrk8vIRCSFSZk8Aor2dQuCxd_APluA8NL6orJ_FaPpVjbMLLRjVU576mYzE4YyeROvi-t98W6s4NpliQ4P83l4Y-5VozXDK9nw1qtuUZpr6KO1GnSiZAzEYPtg3RG5WSGBbSUFu0IxXYUT4BzUhoODHyRrVPkABuYQ8NesEG1IZjSv__nSXOA7OGDcyDIT0uOHkLep79mSvkiwy0BezqcoJc4YarciIzqRzz0-Xoth8NarKHieHN-Lj7anVxY6lSUD5yMLmKbiMPqSGRIm3FvY7Ci8H5KVTX41U4-trve1gD9DFqObzv2-sEqOsvvLCXB81QgA-4qJYHWEph7vkGs9IhHiDbAn0PeY-NqNFZj2kS8pm2emzRZvheT-n8Mn_zNrlS8nUNPPUQnwew8SCCZDt-WR3PIYxGYQvTHlYn_8pRtw_R-ObmutWHeI3JiyB9O9DA5mz3P-big2TICyNnpUiCoVEF9IIip-9YcxQ1RkjRSPXojqvq1OoFdHL8kZIgS55p-PgHSf46VA"><img src="https://mermaid.ink/img/pako:eNp1VV1v2jAU_StW9ko3Stu1RVMlIKmqTd1QiTpp4sUkF7hqsDPboU1R__uu4wRMwhyJJNfn3M9DvAsSmUIwDDT8LUAkECJfKb6ZC0Yr58pggjkXhk0yBLpx3TyN8jzDhBuUoot-xDTN4JUrsAzvbQZqiwl0GXYDlEWHoA2KynFtdWj3yxODW26gTqNlPERqbdTundVRz-7uDvAhmyiwwIc4nrIn2w1dO_8pySwt2_GGVekl-_47Zr9GhVmzWL6AYEupmH2VCt-9thxitALOcCWaSGws05K9IjmbKpfxDyi9-ApXa8PkkrU9cFNQW0FoummWcsMZCgMrhaY8kYDrA1FBpBUf0lbJdeMyU9lnX2LFhc6lsiNKioNbu1I4OY7WVnsodrk8vIRCSFSZk8Aor2dQuCxd_APluA8NL6orJ_FaPpVjbMLLRjVU576mYzE4YyeROvi-t98W6s4NpliQ4P83l4Y-5VozXDK9nw1qtuUZpr6KO1GnSiZAzEYPtg3RG5WSGBbSUFu0IxXYUT4BzUhoODHyRrVPkABuYQ8NesEG1IZjSv__nSXOA7OGDcyDIT0uOHkLep79mSvkiwy0BezqcoJc4YarciIzqRzz0-Xoth8NarKHieHN-Lj7anVxY6lSUD5yMLmKbiMPqSGRIm3FvY7Ci8H5KVTX41U4-trve1gD9DFqObzv2-sEqOsvvLCXB81QgA-4qJYHWEph7vkGs9IhHiDbAn0PeY-NqNFZj2kS8pm2emzRZvheT-n8Mn_zNrlS8nUNPPUQnwew8SCCZDt-WR3PIYxGYQvTHlYn_8pRtw_R-ObmutWHeI3JiyB9O9DA5mz3P-big2TICyNnpUiCoVEF9IIip-9YcxQ1RkjRSPXojqvq1OoFdHL8kZIgS55p-PgHSf46VA?type=png" alt /></a></p>
<p>An <strong>ID token</strong> contains information about the user when access is granted. This is always in a <code>JWT</code> format. </p>
<p>These tokens can (should!) have a <code>JSON</code> Web Signature (<code>JWS</code>). This ensures authenticity.</p>
<p>When the information is really sensitive, they can be encrypted using the <code>JSON</code> Web Encryption (<code>JWE</code>) to ensure confidentiality.</p>
<h3 id="heading-making-the-tokens-tamperproof">Making the tokens tamperproof</h3>
<p>Learn how the <code>JOSE</code> framework enables tamper proofing of access tokens. This section describes the use of JSON Web Signatures and <code>JSON</code> Web Encryption for securing token integrity and confidentiality.</p>
<p>By making the access token tamperproof, the <code>JOSE</code> framework is used to Secure the Payload.</p>
<p>The <strong>JSON Object Signing and Encryption</strong> (JOSE) framework offers a suite of technologies to secure communications:</p>
<ul>
<li><strong><code>JWT</code></strong>: JSON-based claims as a token.</li>
<li><strong><code>JWS</code></strong>: JSON Web Signatures to secure and protect against tampering.</li>
<li><strong><code>JWE</code></strong>: JSON Web Encryption to protect sensitive data.</li>
<li><strong><code>JWK</code></strong>: JSON Web Key defines cryptographic keys in JSON.</li>
</ul>
<p><code>JOSE</code> enables you to sign and encrypt HTTP request bodies, ensuring integrity and confidentiality.</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNptk21rwjAQx79Kyd7WoVXnw2BQbWQM9qqywSjI2Z422CYliZtO_O5LW5Ws9fIi4e53_4S73InEIkEyJVsJReosg-eIO8bePpdOp_Ni9rDloTdPeGVWIdtyTFYBaLhF6ZVfUR7LY6GvAHFJjjIHlpiLTyUeEZ1ijhGZmuMalDm5lv8DJIN1hqoETrV-RArJcpDHuciErDMfBv6kS71LssUs8aBtblFZm5sJmaC0SW8-pBNqkQpjwZPGvSMa9L3ePaqtOAz8p27XYjVKzRqCi2657kBtvaBfLgvNGEcb6FdmARvB9QJylh1r4hWzb9QsBtfxTaEz11HAVUehZJtGWsh-L13qDYqDFQQpxU-KkFjEo4e5hXChcbbb_u9DQP2gwTSb1Xp_JdSuA52Nx6NGHZYpi3cclaohr3xzGT9H_Gy-Iey1CI88JlMt9-iSfZGAxoCBGYecTDeQKePFhGkh3-tBqebFJQXwLyGuzPkPp639yA"><img src="https://mermaid.ink/img/pako:eNptk21rwjAQx79Kyd7WoVXnw2BQbWQM9qqywSjI2Z422CYliZtO_O5LW5Ws9fIi4e53_4S73InEIkEyJVsJReosg-eIO8bePpdOp_Ni9rDloTdPeGVWIdtyTFYBaLhF6ZVfUR7LY6GvAHFJjjIHlpiLTyUeEZ1ijhGZmuMalDm5lv8DJIN1hqoETrV-RArJcpDHuciErDMfBv6kS71LssUs8aBtblFZm5sJmaC0SW8-pBNqkQpjwZPGvSMa9L3ePaqtOAz8p27XYjVKzRqCi2657kBtvaBfLgvNGEcb6FdmARvB9QJylh1r4hWzb9QsBtfxTaEz11HAVUehZJtGWsh-L13qDYqDFQQpxU-KkFjEo4e5hXChcbbb_u9DQP2gwTSb1Xp_JdSuA52Nx6NGHZYpi3cclaohr3xzGT9H_Gy-Iey1CI88JlMt9-iSfZGAxoCBGYecTDeQKePFhGkh3-tBqebFJQXwLyGuzPkPp639yA?type=png" alt /></a></p>
<h2 id="heading-understanding-the-versatility-of-json-web-tokens">Understanding the Versatility of JSON Web Tokens</h2>
<p><code>JSON</code> Web Tokens (<code>JWT</code>) are often thought of as mere access tokens, but their potential extends far beyond this basic use case. A <code>JWT is a compact, URL-safe means of representing claims between two parties. These tokens are particularly useful in scenarios that require verification and integrity. In this documentation, we will explore how</code>JWT`s can be utilized beyond traditional access tokens and how they can ensure the integrity and non-tamperability of HTTP request bodies.</p>
<h2 id="heading-the-concept-of-super-tokens">The Concept of 'Super Tokens'!</h2>
<p>Overloading access tokens or ID tokens with too much information can lead to what is known as "super tokens". These are risky because they could get logged in various places (e.g., proxies, logs), potentially exposing sensitive data unnecessarily. Instead, balancing token content with just enough claim data ensures better security and usability.</p>
<p>Including too much in a single token can lead to technical problems as well. When a token gets to big, it can not be saved into a cookie, or used in the URL of a browser.</p>
<p>Storing large amounts of data in a token can lead to performance issues. Tokens should remain lightweight to travel over networks efficiently.</p>
<p>Super tokens present a single point of failure. If a super token is compromised, it can grant extensive access, leading to potentially severe security breaches. Managing permissions using super tokens ensure that only the right users have access to certain parts of a system can become complex and error-prone.</p>
<h3 id="heading-what-should-not-be-stored-in-a-token">What should not be stored in a token?</h3>
<ul>
<li><p>Highly sensitive data such as passwords, credit card details, or private keys should never be stored in tokens. This is because tokens are often stored in less secure environments, such as cookies or local storage, which could lead to exposure if an attacker gains access.</p>
</li>
<li><p>Information that is subject to frequent change should not be stored in tokens, as updating a token across a system can be cumbersome. A token is valid for the specified time. This means that, in that time window, that data is valid.</p>
</li>
</ul>
<h2 id="heading-http-header-vs-http-body"><code>HTTP</code> Header vs <code>HTTP</code> Body?</h2>
<p>Tokens are commonly attached to <code>HTTP</code> headers for authentication purposes. For instance, an access token in the header can authenticate API requests.</p>
<p>Headers should only contain information necessary for message transmission like authentication tokens and content type identifiers. Headers should be lightweight and used to convey metadata.</p>
<p>The body is used for the main content of the <code>HTTP</code> message. Sensitive data that is sensitive, dynamic or is not used for authorization should be safely passed here... </p>
<p>However, it becomes essential to ensure the tamper-proofing of the request body.</p>
<p>And thus, we have the reason why I did some digging into this topic:
Making the body tamperproof can be done by </p>
<ul>
<li>Levering the <code>JOSE</code> framework</li>
<li>Using a Signature in the <code>HTTP</code> Header</li>
</ul>
<h2 id="heading-jwt-structure"><code>JWT</code> Structure</h2>
<p>Above, we discussed that the <code>JOSE</code> framework has two formats: </p>
<ul>
<li><code>JWT</code></li>
<li><code>JWE</code></li>
</ul>
<p>A <code>JWT</code> consists of three parts:</p>
<ol>
<li><strong>Header</strong>: Contains the type of token (<code>JWT</code>) and the hashing algorithm used.</li>
<li><strong>Payload</strong>: A set of claims, which can be any information you want to share.</li>
<li><strong>Signature</strong>: Used to verify the integrity and authenticity of the token.</li>
</ol>
<p>Example of a <code>JWT</code> signed with a shared secret (HS256):</p>
<pre><code class="lang-json"><span class="hljs-comment">// Header</span>
{
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"HS256"</span>,
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>
}

<span class="hljs-comment">// Payload</span>
{
  <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
  <span class="hljs-attr">"scope"</span>: <span class="hljs-string">"openid profile email"</span>,
  <span class="hljs-attr">"country"</span>: <span class="hljs-string">"belgium"</span>,
  <span class="hljs-attr">"email"</span>: <span class="hljs-string">"john@doe.com"</span>
}

<span class="hljs-comment">// Signature</span>
HMACSHA256(
  base64UrlEncode(header) + <span class="hljs-string">"."</span> +
  base64UrlEncode(payload),
  secret
)
</code></pre>
<h3 id="heading-body-and-jwt-in-http-requests">Body and <code>JWT</code> in <code>HTTP</code> Requests</h3>
<p>In this section, read how <code>JWT</code> can enhance HTTP request body security, ensuring data sent is from an authentic source. We cover encoding sensitive data within JWTs for tamper proofing.</p>
<p>While <code>JWT</code> are commonly used for authentication, they are not limited to being access tokens. They can also serve as secure message carriers or embedded within HTTP request bodies to ensure data integrity. </p>
<p>The following steps outline the process:</p>
<ul>
<li><p>By applying <code>JWT</code> encoding on the body of an HTTP request, any alteration to the body would be detected through signature verification. This ensures that the data is indeed from an authentic source and has not been tampered with on its way to the server.</p>
</li>
<li><p>You can encode sensitive parts of the HTTP message (for example, headers or the body itself) into the <code>JWT</code> payload. Only an entity with the correct secret or public key can validate the <code>JWT</code> and trust the data.</p>
</li>
<li><p>Using <code>JWT</code> not in an authorization context simplifies the process. There's no need for a centralized authority to verify token signatures. Just an agreement between two parties and where to find a shared secret or the location of the public key.</p>
</li>
</ul>
<h4 id="heading-example-http-request">Example HTTP Request</h4>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNptlFFv2yAQx78KYi-b5C5p0q6tHyolsaNo0raotjpp8svZviQoGDzAXd0o3304JBK1Cy_o-N3_juPgQAtZIg2pxr8NigIjBlsFVSaIHTUowwpWgzBkwRkKM7QnqF5QObtjrh4f3SIka4WWRbIypn7qIuizwk9pkEjrSC5owraCbBjyUhPQ5PvvlDBBclm2PW0XMCSrNF2T9a8kJSOo2Ug3ecXO6g7x2GdUzGo72S4SmMam9bnRTGxJ3eScFWSPLRkRvbMJl0RjodB8eafnHSxpigK1Hi2B8U7pCXUthUYa0ApVBay0NT103hk1O6wwo6Fd5qDtKvDsz6AY5Bx1BxxcuIzWilWg2oXkUjnPTzezh3E8OTt7TIqvxueWpzHk5lKVqHxysriNH2KPtGeWouzFvYuj6eT6I2qoeBvNvo3HHmvQNkpPcDnu5gfQUC-adtNDORPoA9PT8ICNFGYJFeOtI1bIX9D2KgRkZgvNA6JB6Cvd9UPPLWFv51u6vqlfvU1QSv7bIZQe8XWClYcI287z_fb9PUTxLOox_csa5H8SGtYhnt_f3_XqkO5YsRe2CR006XLu9o-ZONo2hMbIpBUFDY1qMKBNXYK5PG8aboBra8WSGal-uD_g9BUE1D7rP1JemON_9h5PoA"><img src="https://mermaid.ink/img/pako:eNptlFFv2yAQx78KYi-b5C5p0q6tHyolsaNo0raotjpp8svZviQoGDzAXd0o3304JBK1Cy_o-N3_juPgQAtZIg2pxr8NigIjBlsFVSaIHTUowwpWgzBkwRkKM7QnqF5QObtjrh4f3SIka4WWRbIypn7qIuizwk9pkEjrSC5owraCbBjyUhPQ5PvvlDBBclm2PW0XMCSrNF2T9a8kJSOo2Ug3ecXO6g7x2GdUzGo72S4SmMam9bnRTGxJ3eScFWSPLRkRvbMJl0RjodB8eafnHSxpigK1Hi2B8U7pCXUthUYa0ApVBay0NT103hk1O6wwo6Fd5qDtKvDsz6AY5Bx1BxxcuIzWilWg2oXkUjnPTzezh3E8OTt7TIqvxueWpzHk5lKVqHxysriNH2KPtGeWouzFvYuj6eT6I2qoeBvNvo3HHmvQNkpPcDnu5gfQUC-adtNDORPoA9PT8ICNFGYJFeOtI1bIX9D2KgRkZgvNA6JB6Cvd9UPPLWFv51u6vqlfvU1QSv7bIZQe8XWClYcI287z_fb9PUTxLOox_csa5H8SGtYhnt_f3_XqkO5YsRe2CR006XLu9o-ZONo2hMbIpBUFDY1qMKBNXYK5PG8aboBra8WSGal-uD_g9BUE1D7rP1JemON_9h5PoA?type=png" alt /></a></p>
<p>An example use case could be a secure data submission where JSON payload (representing a transaction) is signed using <code>JWT</code> technology before it is sent to prevent unauthorized changes. The National Register Number (<code>nrn</code>) is the real identification of the user.</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/transaction</span> HTTP/1.1
<span class="hljs-attribute">Date</span>: Fri, 11 Oct 2024 09:38:52 GMT
<span class="hljs-attribute">Host</span>: api.dummy.com
<span class="hljs-attribute">Content-Type</span>: application/json

<span class="json">{
  <span class="hljs-attr">"amount"</span>: <span class="hljs-string">"1500"</span>,
  <span class="hljs-attr">"currency"</span>: <span class="hljs-string">"USD"</span>,
  <span class="hljs-attr">"recipient"</span>: <span class="hljs-string">"Alice"</span>,
  <span class="hljs-attr">"jwt"</span>: <span class="hljs-string">"eyJhbGciOiJSUzI1NiJ9.ewogICJucm4iOiI4MzEyMDcwMjQ1MCIKfQ.ezfyvYmmQ4Cq8nXS1Hy0Duo9i-4yooV3BHk3NLbF2dKMnBgpymsigq951AQ1d_sXEfVOGlOqXSGynV8PL2vR52lO1vOXHU8Cm4yoCgCAwyG5k9XWCi9DSiBj8SXT0xLxXI94p0Oy7COhNUeEnoVrRRJ4XeTLB0bBPuFVjFgJT4435ZnkRMsY7oHe7czSdg1lL-ZgFjirq2YVAbx5wI1DyJ0QPiIVN126pZ-Tsx06I9pCukQARPDqLMESszmd7rx1e4OcaW4GnFicGSkQ8pqOYIXzfSpT-NNlHSlygSioCrF9VgwPbPZDyzqJNcrAQovMrLCyIliD92GPeVHinQdrog"</span>
}</span>
</code></pre>
<p>After decoding the field <code>jwt</code>, it should resemble the following request</p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/transaction</span> HTTP/1.1
<span class="hljs-attribute">Date</span>: Fri, 11 Oct 2024 09:38:52 GMT
<span class="hljs-attribute">Host</span>: api.dummy.com
<span class="hljs-attribute">Content-Type</span>: application/json

<span class="json">{
  <span class="hljs-attr">"amount"</span>: <span class="hljs-string">"1500"</span>,
  <span class="hljs-attr">"currency"</span>: <span class="hljs-string">"USD"</span>,
  <span class="hljs-attr">"recipient"</span>: <span class="hljs-string">"Alice"</span>,
  <span class="hljs-attr">"jwt"</span>: {
        <span class="hljs-attr">"nrn"</span>: <span class="hljs-string">"83120702450"</span>
    }
}</span>
</code></pre>
<p>Or you can sign the entire body with the needed change on the <a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc7519"><code>Content-Type</code> header</a></p>
<pre><code class="lang-http"><span class="hljs-keyword">POST</span> <span class="hljs-string">/transaction</span> HTTP/1.1
<span class="hljs-attribute">Date</span>: Fri, 11 Oct 2024 09:38:52 GMT
<span class="hljs-attribute">Host</span>: api.dummy.com
<span class="hljs-attribute">Content-Type</span>: application/jwt

<span class="apache"><span class="hljs-attribute">eyJhbGciOiJSUzI1NiJ9</span>.ewogICJhbW<span class="hljs-number">91</span>bnQiOiAiMTUwMCIsCiAgImN<span class="hljs-number">1</span>cnJlbmN<span class="hljs-number">5</span>IjogIlVTRCIsCiAgInJlY<span class="hljs-number">2</span>lwaWVudCI<span class="hljs-number">6</span>ICJBbGljZSIsCiAgImp<span class="hljs-number">3</span>dCI<span class="hljs-number">6</span>IHsKICAgICAgICAibnJuIjogIjgzMTIwNzAyNDUwIgogICAgfQp<span class="hljs-number">9</span>.QCC<span class="hljs-number">1</span>KQn<span class="hljs-number">9</span>lTAaPXqokVySRdMlLRoC<span class="hljs-number">4</span>ALiQjagyyZbSPkicFe<span class="hljs-number">5</span>HyEUZoEB<span class="hljs-number">9</span>PtXLMM<span class="hljs-number">8</span>LCc<span class="hljs-number">9</span>-vt<span class="hljs-number">4</span>ygiRhitImT_WLHNmBSBkubrbUwO<span class="hljs-number">8</span>FxZ_GSZFuPrA<span class="hljs-number">5</span>vnk<span class="hljs-number">4</span>F<span class="hljs-number">63</span>Ro<span class="hljs-number">6</span>N<span class="hljs-number">86</span>krvE<span class="hljs-number">46</span>cHOX<span class="hljs-number">3</span>-q-<span class="hljs-number">2</span>AByl<span class="hljs-number">82</span>leRlv_LywTfQIw-TnOvwfNaL<span class="hljs-number">5</span>bCGDa<span class="hljs-number">9</span>rv<span class="hljs-number">7</span>bbZd<span class="hljs-number">2</span>LD<span class="hljs-number">7</span>FusV<span class="hljs-number">0</span>t<span class="hljs-number">7</span>_oU<span class="hljs-number">0</span>ZCPpOHq-FolKQCLOy<span class="hljs-number">9</span>RUzXzkxWDlYNw<span class="hljs-number">5</span>AlTfkQ_RYV<span class="hljs-number">9</span>QjwmfNYMwh<span class="hljs-number">2</span>BnmpxfBSDc<span class="hljs-number">0</span>aqSfPmcvD<span class="hljs-number">2</span>c_J<span class="hljs-number">27</span>hznGjkCORLYjNoprhJw<span class="hljs-number">2</span>_F<span class="hljs-number">8</span>JDuVF<span class="hljs-number">38</span>JxD-<span class="hljs-number">8</span>Kvr-G<span class="hljs-number">0</span>_x<span class="hljs-number">5</span>E<span class="hljs-number">0</span>oLRF<span class="hljs-number">5</span>aBLdc<span class="hljs-number">1</span>vp-tQ</span>
</code></pre>
<h2 id="heading-json-web-encryption-jwe">JSON Web Encryption (JWE)</h2>
<p>This section explains the structure and utility of JWE tokens, detailing their multiple encryption layers to provide comprehensive data security.</p>
<p>JWE tokens encapsulate multiple encryption layers. Here's a breakdown of its structure:</p>
<ul>
<li><p><strong><code>JWE</code> Encrypted Key</strong>: This is the encrypted version of the Content Encryption Key (<code>CEK</code>). The <code>CEK</code> is essential for decrypting the actual payload.</p>
</li>
<li><p><strong><code>JWE</code> Initialization Vector</strong>: This element maximizes security by ensuring that identical data never results in the same encryption output.</p>
</li>
<li><p><strong><code>JWE</code> Authentication Tag</strong>: This ensures that the data integrity is maintained, verifying that the data has not been tampered with.</p>
</li>
<li><p><strong><code>JWE</code> Ciphertext</strong>: This is the encrypted data payload that you aim to secure.</p>
</li>
</ul>
<h3 id="heading-example-deciphering-the-jwe-token">Example: Deciphering the <code>JWE</code> Token</h3>
<p>To decrypt a <code>JWE</code> token, follow these steps:</p>
<ol>
<li>Understand the <code>JWE</code> Header:<ul>
<li>Identify the encryption algorithm used from the JWE header.</li>
</ul>
</li>
<li>Request Decryption for <code>JWE</code> Encrypted Key:<ul>
<li>Send a request to the server to obtain the Content Encryption Key (<code>CEK</code>).</li>
</ul>
</li>
<li>Decrypt the Payload:<ul>
<li>Using the <code>CEK</code>, decrypt the <code>JWE</code> ciphertext to extract the original payload.</li>
</ul>
</li>
</ol>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNp9lG9vmzAQxr-K5b3ZJLKlSbu20RQpAaJu1dRpqTZp4o0DR7AKNjs7bWiU777jTysX2pk3xv7dPQ93xgce6wT4jBv4uwMVQyDFFkURKUajFGhlLEuhLPNzCcoO19eA94Dtesuw0XzeTWfsJ4iE2QzYt98hu6IXQPZlg5_m7GtCgEwrFqoYq9JKrdgi32qUNuv0lbbAUG4zy3T6nLILlJD0eUe_tVXr03cZywJ4Fkk1Ng5qR502pbqGqk3SRrLRy68wpVYJeyCtJtbXytZSjndKwN774fWH_3mnfXazsUIqSN6sWee1KZkvywzQwt6-iYd7iyK27IbUpBI5-yGqXIuEe7wALIRMqL-HOjzi1IkCIj6j6UYYmnnO-i-BUmxyMDVwaPUiXqIsBFa-zjW2ke9OF5fjcNIFO8wt2XS5VTOG3FIjnQOXnPhn4WXokAZiKnhP9zwMppOT16hhxrNg8Xk8dlhLZZS9hKtx_bwCDfMF0_px0Jx66ALTZjhASmdkJQqZVy1xBfk90H8jPLagQuceM0KZkQGUaS9sLR-7Lp2clntnUyDqh4x-I4f4OIHCQeqDt7zbvuxDEC6CHtNv1sB_k2hYh3B5cXHeq8NtJuM7Bca00KT2XO8fI3WkYyh2Vq8rFfOZxR14fFcmwj5dNXyWitzQKiTSavze3kfNteRxumL-aP3EHP8BMjp9qQ"><img src="https://mermaid.ink/img/pako:eNp9lG9vmzAQxr-K5b3ZJLKlSbu20RQpAaJu1dRpqTZp4o0DR7AKNjs7bWiU777jTysX2pk3xv7dPQ93xgce6wT4jBv4uwMVQyDFFkURKUajFGhlLEuhLPNzCcoO19eA94Dtesuw0XzeTWfsJ4iE2QzYt98hu6IXQPZlg5_m7GtCgEwrFqoYq9JKrdgi32qUNuv0lbbAUG4zy3T6nLILlJD0eUe_tVXr03cZywJ4Fkk1Ng5qR502pbqGqk3SRrLRy68wpVYJeyCtJtbXytZSjndKwN774fWH_3mnfXazsUIqSN6sWee1KZkvywzQwt6-iYd7iyK27IbUpBI5-yGqXIuEe7wALIRMqL-HOjzi1IkCIj6j6UYYmnnO-i-BUmxyMDVwaPUiXqIsBFa-zjW2ke9OF5fjcNIFO8wt2XS5VTOG3FIjnQOXnPhn4WXokAZiKnhP9zwMppOT16hhxrNg8Xk8dlhLZZS9hKtx_bwCDfMF0_px0Jx66ALTZjhASmdkJQqZVy1xBfk90H8jPLagQuceM0KZkQGUaS9sLR-7Lp2clntnUyDqh4x-I4f4OIHCQeqDt7zbvuxDEC6CHtNv1sB_k2hYh3B5cXHeq8NtJuM7Bca00KT2XO8fI3WkYyh2Vq8rFfOZxR14fFcmwj5dNXyWitzQKiTSavze3kfNteRxumL-aP3EHP8BMjp9qQ?type=png" alt /></a></p>
<h3 id="heading-jws-verification"><code>JWS</code> Verification</h3>
<p>Understand the process of using JWS verification to confirm the integrity of data post-decryption, ensuring its trustworthiness.</p>
<p>After decryption, if the data includes a <code>JWS</code> token, its integrity can be confirmed through verification. This step ensures that the data has not been altered and is indeed from a trusted source.</p>
<h2 id="heading-using-signature-in-header">Using Signature in Header</h2>
<p>We discuss the technique of signing HTTP requests by attaching a digital signature to the header, enabling servers to verify request authenticity and integrity.</p>
<p>The concept of signing involves creating a digital signature for the body of a <code>HTTP</code> request. This digital signature is then included in the request headers, allowing the server to validate the request's authenticity and integrity.</p>
<ul>
<li>The Request Body: The sensitive data you want to protect.</li>
<li><code>RSA</code>-<code>SHA256</code> Signature: A cryptographic hash of the request body, encrypted with a private key. This hash is sent to the server for verification.</li>
</ul>
<h3 id="heading-steps">Steps</h3>
<ul>
<li><p>Generate <code>RSA</code> Key Pair: You need a <code>RSA</code> private key for signing and a corresponding public key for signature verification</p>
</li>
<li><p>For each request</p>
<ul>
<li><p>sign the Request: Calculate the <code>SHA256</code> hash of the request body, and encrypt the hash using your private key</p>
</li>
<li><p>Attach Signature to Header: Include your signature e.g. with a header name <code>Signature</code> or <code>X-Payload-Signature</code> header when you send your HTTP request.</p>
</li>
<li><p>Server-side Verification: The server uses the public key to verify the received signature and the integrity of the request body.</p>
</li>
</ul>
</li>
</ul>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNp1lG9v2jAQxr-Klb3oG9go_R9NlQKEMU2TUMOqaeKNSQ44NbGzs0ObVf3usxMKJmmSFxjf73l8vnP86sUyAc_3FPwtQMQwQb4hni0FM0_OSWOMOReajVMEodvzEdAOaCnqiJAamDQTe943cV3kPvsGAoib4EMUsB9QsjlHqjU1yfr39wfRCT0n3NmxUX1d0Zd7LhI2lkSgcikSFBs2L1YpxhZoOdbpGUfcwf5PbepIOlPXkLNzn00lsZDHW_Zgi6R0Z9pjnsZFanONZsHw6prNuNpWOcv1u5iNZFJ2OkS4EUxvoVKyQpndVfpGHTr1gdY2UWvDdUHgWMyAJ2ZzZ4fYGZNURc5-9-e8TCVP-sdgZyUjMPWfLRbzw46eUW9Zbf9ezH2lXd0DaEKwXTgktyaZHYSnPTiuZn_7ChNgj0C4xphrlN3L_FLgNJdpWcvK47Kd0rEUa6SMfRcaNoS6ZPaoBYXph7DnXZdez8uAMo6J-WRerdHSM9EMlp5vhiuuzKjnzD9yQr5KQVngtV556eWEGadyLFNJtfLTZXA3CId7scMs4EW73LR62txIkqmiSw7HV-Fd6JAKYvO9NNa9CScXw_OPqLbj1SS4HgwcVoO5BxqG04F9P4DafpML-zpoigJc4KJ6HGAthZ7yDNOyJmaQ7sC0hvdYYAqd9pjiQvWV7XhDFuG_fZfOL_MXJ8iJ5PPWHEKH-DyEzEHssRw9bU77MAmDSYNpNquVf2XUrkM4ur29adRhscX4SYBSNTS0Odv421K8mWPICy2jUsSer6mAnlfkibkb9re35695qswsJKgl_ayv-Oqm73nm1v4j5Tvz9h9uau9G"><img src="https://mermaid.ink/img/pako:eNp1lG9v2jAQxr-Klb3oG9go_R9NlQKEMU2TUMOqaeKNSQ44NbGzs0ObVf3usxMKJmmSFxjf73l8vnP86sUyAc_3FPwtQMQwQb4hni0FM0_OSWOMOReajVMEodvzEdAOaCnqiJAamDQTe943cV3kPvsGAoib4EMUsB9QsjlHqjU1yfr39wfRCT0n3NmxUX1d0Zd7LhI2lkSgcikSFBs2L1YpxhZoOdbpGUfcwf5PbepIOlPXkLNzn00lsZDHW_Zgi6R0Z9pjnsZFanONZsHw6prNuNpWOcv1u5iNZFJ2OkS4EUxvoVKyQpndVfpGHTr1gdY2UWvDdUHgWMyAJ2ZzZ4fYGZNURc5-9-e8TCVP-sdgZyUjMPWfLRbzw46eUW9Zbf9ezH2lXd0DaEKwXTgktyaZHYSnPTiuZn_7ChNgj0C4xphrlN3L_FLgNJdpWcvK47Kd0rEUa6SMfRcaNoS6ZPaoBYXph7DnXZdez8uAMo6J-WRerdHSM9EMlp5vhiuuzKjnzD9yQr5KQVngtV556eWEGadyLFNJtfLTZXA3CId7scMs4EW73LR62txIkqmiSw7HV-Fd6JAKYvO9NNa9CScXw_OPqLbj1SS4HgwcVoO5BxqG04F9P4DafpML-zpoigJc4KJ6HGAthZ7yDNOyJmaQ7sC0hvdYYAqd9pjiQvWV7XhDFuG_fZfOL_MXJ8iJ5PPWHEKH-DyEzEHssRw9bU77MAmDSYNpNquVf2XUrkM4ur29adRhscX4SYBSNTS0Odv421K8mWPICy2jUsSer6mAnlfkibkb9re35695qswsJKgl_ayv-Oqm73nm1v4j5Tvz9h9uau9G?type=png" alt /></a></p>
<pre><code class="lang-http">
<span class="hljs-keyword">POST</span> <span class="hljs-string">/transaction</span> HTTP/1.1
<span class="hljs-attribute">Date</span>: Fri, 11 Oct 2024 09:38:52 GMT
<span class="hljs-attribute">Host</span>: api.dummy.com
<span class="hljs-attribute">Digest</span>: SHA-512=tVL/etooLtB3qNVs693Ka1xpbsjgJvf8Xb/gprvktjYRnNPac9eEWw7XVrXxbfuLh45eLiGBLMEeepHvZ2cuvA==
<span class="hljs-attribute">Signature</span>: keyId="aa2bd832-191e-4d2b-98d4-b0d4778844f9",created=1728639532,algorithm="hs2019",headers="(request-target) host digest (created)",signature="aAaII33mSJsfuXuTRJet5tJF6cQuYL77+b0gU1UZQMVjrz6jf1uNm5ixjN/CiId8Q5lTf9N308MH9ktSGWvzrtq67v73hG9PxEtCWuUR5tEiBdUk4Jt8xYszAuJYfGCqkFeoIiB8dbWNcTRRrZSAJAUPbSoY4eVyl0w91zvsr2wv8Gu3vo18XxHqtccOA0yHV4HVdJdbX1l0XLicTILTC2U27gxbpL8qsHZ1jgGByk/Wmm3KHmFtgEVGLVj3kbc712r5l54se4cSoQGst+rAy3xk//07x3icjLynObflLtpy3qqZgAR1L01xH1ISK7WCsy7G8e8ueQuGU5hAbir0lA=="
<span class="hljs-attribute">Content-Length</span>: 91
<span class="hljs-attribute">Content-Type</span>: application/json

<span class="json">{
  <span class="hljs-attr">"amount"</span>: <span class="hljs-string">"1500"</span>,
  <span class="hljs-attr">"currency"</span>: <span class="hljs-string">"USD"</span>,
  <span class="hljs-attr">"recipient"</span>: <span class="hljs-string">"Alice"</span>,
  <span class="hljs-attr">"nrn"</span>: <span class="hljs-string">"83120702450"</span>
}</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Reflecting on the information presented, this conclusion underscores the role of <code>JWT</code> and related technologies in securing sensitive information across web communications.</p>
<p>I have come to an understanding that a <code>JWT</code> is a format, a simple carrier format and can be used broader than only a token in the header.</p>
<p><code>JWT</code> and <code>JWE</code> are part of the <code>JOSE</code> (JSON Object Signing and Encryption) framework. <code>JWT</code> is popular now, because Oauth2 and OpenID Connect uses the <code>JWT</code> for formatting the access and ID tokens. And using that framework, helps us safeguards sensitive information</p>
<p>When an access or ID token is uses the <code>JWT</code> format, it should not be used as an information repository. The <code>JWT</code> format can benefit your application architecture, by formatting the <code>HTTP</code> Request body.</p>
<p>However, there are other possibilities that keep the <code>HTTP</code> Request Body human-readable, by only adding a signature <code>HTTP</code> Headers.</p>
<h2 id="heading-sources">Sources</h2>
<p>A list of tools, references, and resources consulted while writing this article provides you with additional context and avenues for further exploration into this topic.</p>
<h3 id="heading-tools-to-play-with">Tools to play with</h3>
<ul>
<li><a target="_blank" href="https://mkjose.org/">JOSE Generator</a></li>
<li><a target="_blank" href="https://mkjwk.org/">Private and Public Key Generator</a></li>
<li><a target="_blank" href="https://documentation.ibanity.com/support/http-signature-generator">Tool that helps you gain insight in creating a signature for a HTTP Request Body</a><ul>
<li><a target="_blank" href="https://generate-uuid.com/which-uuid-version-should-you-use">UUID4 generator, to be used in the tool above</a></li>
</ul>
</li>
</ul>
<h3 id="heading-sources-for-this-article">Sources for this article</h3>
<ul>
<li><a target="_blank" href="https://belgianmobileid.github.io/slate/jose">belgianmobileid aka ITSME information about JOSE</a></li>
<li>https://medium.com/@idenisko/understanding-the-jwe-token-a-practical-guide-942224f6a9b6</li>
<li>https://developer.visa.com/pages/encryption_guide/jwe-jws</li>
<li>https://auth0.com/docs/get-started/apis/configure-json-web-encryption</li>
<li>https://openid.net/developers/certified-openid-connect-implementations/</li>
<li>https://openid.net/specs/draft-jones-json-web-encryption-02.html</li>
<li>https://jwt.io/introduction/</li>
<li>https://oauth.net/2/</li>
<li>https://dev.to/ariefwara/rest-api-body-payload-signature-2277</li>
<li>https://hookdeck.com/webhooks/guides/how-to-implement-sha256-webhook-signature-verification</li>
<li><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc7519"><code>Content-Type: application/jwt</code></a></li>
<li><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc4627"><code>Content-Type: application/json</code></a></li>
<li><a target="_blank" href="https://www.openbankingeurope.eu/media/2096/obe-json-web-signature-profile-for-open-banking.pdf">A really nice read on how protecting data is used in Open Banking in Europe. Even design principles are listed</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Signature validation required? Microsoft Says No.]]></title><description><![CDATA[No signature validation using AddMicrosoftAccount()
TLDR; Microsoft's AddMicrosoftAccount() method does not do signature validation for tokens, which poses potential security risks. This article explores the implications of this, using an analogy of ...]]></description><link>https://dotnet.kriebbels.me/signature-validation-required-microsoft-says-no</link><guid isPermaLink="true">https://dotnet.kriebbels.me/signature-validation-required-microsoft-says-no</guid><category><![CDATA[Entra]]></category><category><![CDATA[OpenID Connect]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[Microsoft]]></category><category><![CDATA[Aspnetcore]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Nuget]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 05 May 2024 18:26:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714933451062/dd6b2543-ab30-4d47-a766-5f9e643bb2e5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-no-signature-validation-using-addmicrosoftaccount">No signature validation using AddMicrosoftAccount()</h1>
<p>TLDR; Microsoft's <code>AddMicrosoftAccount()</code> method does not do signature validation for tokens, which poses potential security risks. This article explores the implications of this, using an analogy of concert ticket validation, to explain the importance of signature validation in OpenID Connect (OIDC) systems. It also delves into Microsoft's approach to OIDC, highlighting some integration challenges and the risks of not properly validating signatures, especially in scenarios where secure communication channels cannot be guaranteed.</p>
<p>NuGet Packages mentioned:</p>
<ul>
<li><p><a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.MicrosoftAccount">NuGet Gallery | Microsoft.AspNetCore.Authentication.MicrosoftAccount 8.0.4</a></p>
</li>
<li><p><a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect">NuGet Gallery | Microsoft.AspNetCore.Authentication.OpenIdConnect 8.0.4</a></p>
</li>
</ul>
<h2 id="heading-previously-onhttpswwwnugetorgpackagesmicrosoftaspnetcoreauthenticationopenidconnect"><a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect">Previously on</a></h2>
<p><a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect">In a previous piece for XPRT Magazine, I wrote an art</a><a target="_blank" href="https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.MicrosoftAccount">icl</a>e about mocking your <a target="_blank" href="https://xebia.com/blog/mock-your-openid-connect-provider">OpenID Connect Provider</a>. For the latest magazine, I rewrote the application that allowed me to demonstrate how to mock the authorization code flow with PKCE. This modification is important for a live demo at <a target="_blank" href="https://www.techorama.be">Techorama, which is held annually</a>. I will be attending as a speaker on this subject. Moreover, during the event of <a target="_blank" href="https://dotnetfriday.nl/">Dotnet Friday</a>, a question about mocking OIDC (OpenID Connect) for Microsoft Entra was raised, prompting an exploration of OIDC's capabilities with Microsoft accounts. However, without any experience, I cannot say where the difficulties lay.</p>
<h2 id="heading-context">Context</h2>
<p>Lately, my fascination with web development and identity security has taken a new turn. While prepping for a tech demo, I stumbled upon complexities that many developers face—using OAuth and OpenID Connect for securing apps in a testing context, using a browser. It's compelling how these systems are vital yet somewhat obscured in daily coding routines.</p>
<p>The tech scene itself is evolving, with an increasing emphasis on robust security protocols. Recent breaches and escalated security mandates make it imperative for applications to be fortified yet user-friendly. Hence, the dive into the authenticity mechanisms of OIDC with a focus on e.g. Microsoft Entra was not merely by chance but a necessity. As I worked through integrating Microsoft accounts into the authentication flow of my demo app, it revealed facets and pitfalls of current authentication packages.</p>
<h2 id="heading-introduction-to-oidc-and-its-necessity">Introduction to OIDC and Its Necessity</h2>
<p>If you've ever logged into a service or app using your Facebook, Google, or Microsoft account, then you've encountered OpenID Connect (OIDC) without perhaps realizing it. This protocol is extensively used because it streamlines the authentication process for millions of users across various platforms by allowing them to sign in with existing identities. This is a better scenario than providing another company with your credentials. Those companies are mentioned a lot in the news. <a target="_blank" href="https://www.clearygottlieb.com/-/media/files/alert-memos-2018/eu-regulated-companies-faced-with-personal-data-breach--reconciling-obligations-under-gdpr--mar.pdf">According to EU-law, companies have an obligation to inform the user about what information is stolen.</a></p>
<h3 id="heading-what-is-oidc-an-analogy">What is OIDC? — An Analogy</h3>
<p>Imagine you're attending a concert where the ticket purchase is done through an app using Google Pay, which doesn't expose your bank account details. Here, the concert venue represents the application you want access to.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714932615941/2efec56d-2edf-4877-b5c1-972edd3d657b.jpeg" alt class="image--center mx-auto" /></p>
<p>Google acts as the OIDC service — and validates your purchase without sharing your sensitive bank details—and the ticket represents the authorization given to you by OIDC to access the venue.</p>
<p>In this analogy, your ticket is not just a piece of paper but contains a sophisticated hologram (representing a digital certificate).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714932567237/08a283b5-679c-4905-a790-98cdd520116f.jpeg" alt class="image--center mx-auto" /></p>
<p>This hologram shows that the ticket is genuine when inspected under a specific light (the public key) matching a sticker (the private key) you were given when purchasing the ticket. This matching process ensures the ticket’s authenticity privately without exposing sensitive data—a core principle in OIDC using Authorization Code Flow with PKCE (Proof Key for Code Exchange). PKCE adds an extra layer of security, ensuring that even if the criminals grab your ticket, they can’t misuse it because they cannot provide the purchase proof that the concert venue will ask on entrance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714932720998/587290ad-fa7a-4491-84b7-f4fd8a372447.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-why-oidc">Why OIDC?</h3>
<p>The necessity of OIDC lies in its ability to standardize secure and scalable user authentication across diverse digital systems. Using familiar accounts like Facebook, Google, or Microsoft for authentication doesn’t just reduce the burden of managing multiple usernames and passwords for users; it also outsources the security responsibilities to entities that specialize in security, thereby enhancing overall safety. By using OIDC, businesses can offload much of the cybersecurity risks associated with user data management and password protection.</p>
<h2 id="heading-experiencing-oidc-with-microsoft-entra">Experiencing OIDC with Microsoft Entra</h2>
<p>While my experiences are limited to working with Auth0 by Okta, other providers that provide OpenID as well, e.g., Entra. However, I do know Microsoft from the past. That Microsoft does use a standard but creates a dialect from that standard.</p>
<p>Let us find out if they now abide by the standard.</p>
<h3 id="heading-integration-challenges">Integration Challenges</h3>
<p><a target="_blank" href="https://github.com/kriebb/MockOpenIdConnectIdpAspnetcore/tree/4ca8f4fd4aaa41f6539f504020ba7b321bdefc3f">For a working source code</a>, to mock out the OIDC using the Microsoft Account package.</p>
<p><a target="_blank" href="https://github.com/kriebb/MockOpenIdConnectIdpAspnetcore/tree/804153f8ba7eff309e8f053bf5f84d474de1dbfd">This link</a> is the commit that gives you a working example using the OIDC package.</p>
<h4 id="heading-conflicting-and-outdated-sources">Conflicting and outdated sources</h4>
<p>When you download from Entry a sample application for Asp.NET Core, you get a deprecated one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1714931879983/ef3e1693-19a5-4303-b21f-c475fdbe132c.png" alt class="image--center mx-auto" /></p>
<p>It lets me download the following:</p>
<p><code>active-directory-aspnetcore-webapp-openidconnect-v2-aspnetcore3-1.zip</code></p>
<p>While their documentation seems up-to-date on what library you should use, I find not matching information in the code samples.</p>
<p>For example:</p>
<p>The following is found on the quick-start: <code>https://learn.microsoft.com/en-gb/entra/identity-platform/quickstart-web-app-dotnet-core-sign-in</code></p>
<p>However, because I wanted to showcase that when you use the Microsoft Account NuGet package, I wanted to try that out. Just going forward without looking too much into it.</p>
<p><code>Microsoft.AspNetCore.Authentication.MicrosoftAccount</code> is available for long-term support! (Currently, that is version 8.0.4, and on the NuGet site, it links to the main page as a project source: <code>https://github.com/dotnet/aspnetcore/tree/v8.0.4</code>) This repository contains the generic OIDC NuGet package source code, as well as the Microsoft Account one. <code>https://github.com/dotnet/aspnetcore/blob/main/src/Security/Authentication/</code></p>
<h4 id="heading-sub-is-not-provided"><code>sub</code> is not provided</h4>
<p>When mocking out Entra, I noticed some small changes between the sample I used for the Microsoft Account and the one from the OpenIdConnect Generic package.</p>
<p>Notice in the example below, there is no <code>sub</code> claim to be found, and you get by default more claims than in the generic OIDC Library.</p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&amp;tabs=http">Get a user - Microsoft Graph v1.0 | Microsoft Learn</a></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">UserInfoEndpointResponseBody</span>(<span class="hljs-params">
    [property: JsonPropertyName(<span class="hljs-string">"@odata.context"</span></span>)] <span class="hljs-keyword">string</span> ODataContext,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"businessPhones"</span></span>)] <span class="hljs-keyword">string</span>[] BusinessPhones,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"displayName"</span></span>)] <span class="hljs-keyword">string</span> DisplayName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"givenName"</span></span>)] <span class="hljs-keyword">string</span> GivenName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"jobTitle"</span></span>)] <span class="hljs-keyword">string</span>? JobTitle,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"mail"</span></span>)] <span class="hljs-keyword">string</span> Mail,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"mobilePhone"</span></span>)] <span class="hljs-keyword">string</span>? MobilePhone,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"officeLocation"</span></span>)] <span class="hljs-keyword">string</span>? OfficeLocation,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"preferredLanguage"</span></span>)] <span class="hljs-keyword">string</span>? PreferredLanguage,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"surname"</span></span>)] <span class="hljs-keyword">string</span> Surname,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"userPrincipalName"</span></span>)] <span class="hljs-keyword">string</span> UserPrincipalName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"id"</span></span>)] <span class="hljs-keyword">string</span> Id
)</span>;
</code></pre>
<p>This is the refactored sample I used for the OIDC Library according to this link:</p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/entra/identity-platform/userinfo#consider-using-an-id-token-instead">Microsoft identity platform UserInfo endpoint - Microsoft identity platform | Microsoft Learn</a></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> record <span class="hljs-title">UserInfoEndpointResponseBody</span>(<span class="hljs-params">
    [property: JsonPropertyName(<span class="hljs-string">"@odata.context"</span></span>)] <span class="hljs-keyword">string</span> ODataContext,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"sub"</span></span>)] <span class="hljs-keyword">string</span> Id,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"name"</span></span>)] <span class="hljs-keyword">string</span> DisplayName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"given_name"</span></span>)] <span class="hljs-keyword">string</span> GivenName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"family_name"</span></span>)] <span class="hljs-keyword">string</span> Surname,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"preferred_username"</span></span>)] <span class="hljs-keyword">string</span> UserPrincipalName,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"email"</span></span>)] <span class="hljs-keyword">string</span> Mail,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"phone_number"</span></span>)] <span class="hljs-keyword">string</span>? MobilePhone,
    [property: <span class="hljs-title">JsonPropertyName</span>(<span class="hljs-params"><span class="hljs-string">"locale"</span></span>)] <span class="hljs-keyword">string</span>? PreferredLanguage
)</span>;
</code></pre>
<h4 id="heading-token-signature-is-not-validated">token signature is not validated</h4>
<p>In the Microsoft Account library, there is no code that gives me the option to validate the signature. It just does not validate. Using the given commit, you will notice that the JWKS endpoint is not consulted: <code>https://github.com/dotnet/aspnetcore/blob/main/src/Security/Authentication/MicrosoftAccount/src/MicrosoftAccountHandler.cs</code></p>
<h3 id="heading-signature-validation-analogy-concert-tickets">Signature Validation Analogy: Concert Tickets</h3>
<p>Imagine you've purchased a ticket to see your favourite band perform live. This ticket allows you entry into the concert venue, but it’s not just any ticket. It’s embedded with a unique holographic seal that proves it's genuine. This is akin to the cryptographic signature on a token in the OIDC process.</p>
<p>Now, suppose a scalper tries to sell counterfeit tickets outside the venue. The venue security (acting as the client in the OIDC process) uses a special light (public key) to check the authenticity of the holographic seal (signature) on your ticket (the token). If the holographic seal lights up correctly, it confirms the ticket wasn't tampered with and is valid, allowing you entrance to the concert. If the ticket fails this test, it means it might have been tampered with, similar to a potential token modification in a cyberattack.</p>
<h3 id="heading-importance-of-signature-validation">Importance of Signature Validation</h3>
<p>In the context of the concert:</p>
<p>— <strong>Prevention of Fraud:</strong> Just as the holographic seal prevents counterfeit or altered tickets from passing as genuine, signature validation in OIDC prevents tampered tokens from being used to falsely claim an identity or permissions.</p>
<p>— <strong>Security Protocol Integrity:</strong> Should the holographic seal be poorly crafted, allowing fake tickets to appear valid, the entire security protocol of the venue would be undermined, just as weak or absent signature validation can expose a system to breaches.</p>
<h4 id="heading-potential-risks-without-proper-validation">Potential Risks Without Proper Validation</h4>
<p>During a concert:</p>
<ol>
<li><p><strong>Unauthorized Access:</strong> If someone with a counterfeited or tampered ticket gets past security, similar to a cyberattacker using a manipulated token, they gain unauthorized access. This could lead to overcrowding, an unpleasant experience for genuine ticket holders, or other security risks.</p>
</li>
<li><p><a target="_blank" href="https://purplesec.us/privilege-escalation-attacks/"><strong>Horizontal and Vertical Attacks</strong></a><strong>:</strong> In concert terms, a horizontal attack might involve attendees accessing areas reserved for other ticket holders of the same level (e.g., general admission), whereas a vertical attack would be akin to someone with a general admission ticket gaining entry to a VIP area. Without signature validation, similar breaches in software systems can lead to unauthorized data or functionality access.</p>
</li>
</ol>
<h4 id="heading-let-me-dive-into-the-source-code-of-the-oidc-library">Let me dive into the source code of the OIDC Library</h4>
<p>When using the OIDC Library, it is stated that the default signature is not validated by default. <code>https://github.com/dotnet/aspnetcore/blob/main/src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs</code></p>
<p>Notice the line in the code: <code>https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation</code></p>
<p>The decision to allow TLS validation in place of explicit signature checking in direct communication scenarios acknowledges the security provided by modern TLS configurations. This means that the token should not go over any proxies or any other systems that can deep inspect packages and thus give the possibility to intercept and temper. A token is always fetched using the supplied <code>Backchannel</code> of the library. That means that the Web Application will fetch the token. The end user is never involved in this process. When you deploy in Azure, you should be able to trust Azure about the inspection that they do or not do with your traffic. Note that everything with tokens is fascinating to hackers:</p>
<ul>
<li><p>T<a target="_blank" href="https://learn.microsoft.com/en-us/security/operations/token-theft-playbook">oken Theft Playbook</a>: Token theft occurs when threat actors compromise and replay tokens issued to a user, bypassing multifactor authentication and gaining access to organizational resources. This page includes prerequisites like access to Microsoft Entra ID sign-in and audit logs, recommendations such as enabling advanced hunting features, and requirements for configuring a SIEM (Security Information and Event Management) tool for centralized log visibility and threat detection.</p>
</li>
<li><p><a target="_blank" href="https://www.bing.com/aclick?ld=e8RdcFD6fLirJmy-looP-E2DVUCUzKghqWLrM6Ddr1TTvzNP7pFWSmiRyjbDXjX94MITkHu2csa02k-oegDhF0VL9tuRHvFzikkNX-Gtom2BH5zvITQjZtZ__BzB_g9RgaqwW6b9104UGJbyMewAXOE5l7ZqFbCX0jA0QX73YSlbw2WBbC&amp;u=aHR0cHMlM2ElMmYlMmZ3d3cud2l6LmlvJTJmJTNmdXRtX3NvdXJjZSUzZGJpbmclMjZ1dG1fbWVkaXVtJTNkcHBjJTI2dXRtX2NhbXBhaWduJTNkYnJhbmQtc2VhcmNoLWVtZWElMjZ1dG1fdGVybSUzZHdpeiUyNTIwaW8lMjZ1dG1fY29udGVudCUzZFdpeiUyNTIwaW8lMjZ1dG1fZGV2aWNlJTNkbSUyNm1zY2xraWQlM2Q2MDdlMjE4MDRlZGExNTU2ZWQ1YTQ3Yjc4NzA4MDQ1YQ&amp;rlid=607e21804eda1556ed5a47b78708045a"><strong>Compromised Microsoft Key</strong></a>: The incident involved the threat actor acquiring a private encryption key (MSA key) and using it to forge access tokens for Outlook Web Access (OWA) and <a target="_blank" href="http://Outlook.com">Outlook.com</a>. The compromised key could have allowed the threat actor to forge access tokens for various Azure Active Directory applications.</p>
</li>
</ul>
<p>However, having not to validate the signature means that it simplifies implementations by reducing overhead where secure communication channels can be guaranteed. Remember that in any scenario where the communication may involve indirect or less secure channels, signature validation becomes a MUST for ensuring that the ID Token has not been tampered with or falsified in transit.</p>
<p>Thus, do not use the Microsoft Account library because you cannot configure the library to validate the signature in case there is no direct communication. I fail to see why you want to use the Microsoft Account library.</p>
<p>The links below indicate that <code>AddMicrosoftAccount()</code> is deprecated. But the source code in the package does not have any of the annotations that it will/is deprecated or obsolete.</p>
<ul>
<li>The Closed issue on <code>https://github.com/dotnet/AspNetCore.Docs/issues/14455</code> references the still open issue <code>https://github.com/dotnet/aspnetcore/issues/10037</code> from <code>May 7, 2019</code>.</li>
</ul>
<h2 id="heading-outro">Outro</h2>
<p>Reflecting on this journey of navigating through OIDC and Microsoft Entra, I am both enlightened and a bit overwhelmed. The nuances of modern identity management systems like OIDC are vast. Yet, understanding them is not just about building secure applications, but also about empowering them to be robust in the face of evolving digital threats. My goal has been to bring to light the often overlooked aspects of app security — a commitment I will continue to explore and share insights on.</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Asp.net Core MVC: An In-Depth Look at JQuery Validate Scripts]]></title><description><![CDATA[Previously on...
In a previous blog post, I described LibMan or Npm for a new project. I explored how to manage the required scripts.
I find it important to understand the history of things. This helps me to learn why we use this technology, and what...]]></description><link>https://dotnet.kriebbels.me/exploring-aspnet-core-mvc-an-in-depth-look-at-jquery-validate-scripts</link><guid isPermaLink="true">https://dotnet.kriebbels.me/exploring-aspnet-core-mvc-an-in-depth-look-at-jquery-validate-scripts</guid><category><![CDATA[asp.net core]]></category><category><![CDATA[mvc]]></category><category><![CDATA[Validation]]></category><category><![CDATA[jQuery]]></category><category><![CDATA[Unobtrusive ]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 22 Jul 2023 18:29:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690050104371/9f473363-4f17-4267-8504-de69dd06f699.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app">In a previous blog post, I described LibMan or Npm for a new project.</a> I explored how to manage the required scripts.</p>
<p>I find it important to understand the history of things. This helps me to learn why we use this technology, and what were the shortcomings of the previous tech. <a target="_blank" href="https://www.uopeople.edu/blog/why-is-history-important/">Understanding history helps build the future.</a></p>
<h1 id="heading-context">Context</h1>
<p>During my education at <a target="_blank" href="https://www.hogent.be/sites/hogent/assets/File/DOW/TI%20201103%20VIRA%20HoGent.pdf">BINF at Hogeschool Gent</a>, I was primarily taught ASP.NET WebForms as the go-to framework for web development. I focused more on backend development in my career. A new project starts and I realized that I missed out on the advancements in web development. Creating a scaffolded Asp.net core MVC Project led me to understand the history a bit better of ASP.NET MVC, AJAX, and jQuery.</p>
<h2 id="heading-aspnet-webforms-drawbacks">ASP.NET WebForms drawbacks</h2>
<p>ASP.NET WebForms is a framework introduced by Microsoft for building web applications using the .NET platform. It was similar to Windows Forms development. That allowed us to create web pages that closely resembled desktop user interfaces.</p>
<p>However, using ASP.NET WebForms has several drawbacks. I will not go into the details of what it was in detail. I will address the issues that web forms had.</p>
<ul>
<li><p>The tight integration of server controls with HTML and JavaScript made it difficult to test and maintain applications.</p>
</li>
<li><p>The complex view state management mechanism resulted in large and complex view states, negatively impacting performance.</p>
</li>
<li><p>The postback model used in WebForms caused full page reloads for each user interaction. That leads to slower user experiences.</p>
</li>
</ul>
<h2 id="heading-introduction-of-ajax-and-aspnet-ajax">Introduction of AJAX and ASP.NET AJAX</h2>
<p>In 2005, the concept of AJAX (Asynchronous JavaScript and XML) emerged as a way to enable server communication but without a full page reload! Microsoft recognized the potential of AJAX and integrated it into the ASP.NET framework with the release of ASP.NET AJAX in 2007.</p>
<p>Using Ajax in web forms provided developers with server controls, client libraries, and toolkits. Features such as partial page rendering, update panels, and rich client-side controls improved the interactivity of web applications.</p>
<h2 id="heading-aspnet-mvc-and-jquery-integration">ASP.NET MVC and jQuery integration</h2>
<p>Despite the advancements brought by AJAX, the tight coupling, view state, and postback model concerns persisted in WebForms. In response, Microsoft introduced ASP.NET MVC in 2007 as a flexible framework that followed the Model-View-Controller architectural pattern. This pattern promotes a clear separation of concerns and facilitated the separation of UI elements from their underlying logic.</p>
<p>To simplify client-side development within ASP.NET MVC, jQuery was integrated. jQuery provides a user-friendly API for DOM manipulation, event handling, adhoc backend calls and animations.</p>
<h2 id="heading-htmlhelpers-or-taghelpers">HtmlHelpers or TagHelpers</h2>
<p>I want to mention the way that Asp.net core MVC Razor pages are built. In the case of client validation, it does not seem to matter much what approach is used: TagHelpers or HtmlHelpers. <code>jQuery Validate</code> searches for data attributes on the generated HTML.</p>
<p>Tag Helpers in ASP.NET Core are components that enable server-side code to participate in generating and processing HTML elements. They provide a more <strong>HTML-centric way of working</strong> with server-side code.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Tag Helper: &lt;a&gt; element with an `asp-controller` attribute --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">asp-controller</span>=<span class="hljs-string">"Home"</span> <span class="hljs-attr">asp-action</span>=<span class="hljs-string">"Index"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>In the above code snippet, the <code>&lt;a&gt;</code>-element is a Tag Helper. The <code>asp-controller</code> and <code>asp-action</code> attributes are Tag Helper attributes that help generate the appropriate <code>href</code> attribute for the anchor element.</p>
<p>HTML Helpers are methods in ASP.NET Core that <strong>assist</strong> in generating HTML markup. They are invoked within Razor views and help create HTML elements with the necessary attribute values.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- HTML Helper: &lt;a&gt; element with controller and action parameters --&gt;</span>
@Html.ActionLink("Home", "Index", "Home")
</code></pre>
<p><code>Html.ActionLink</code> is an HTML Helper method. It generates an anchor element with the text "Home" and sets the <code>href</code> attribute based on the specified controller and action values.</p>
<p>To quote the docs from Microsoft</p>
<blockquote>
<p>The Visual Studio editor helps you write <strong>all</strong> of the markup in the Tag Helper approach of the register form, while Visual Studio provides no help for most of the code in the HTML Helpers approach. <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-7.0#intellisense-support-for-tag-helpers">IntelliSense support for Tag Helpers</a> goes into detail on working with Tag Helpers in the Visual Studio editor.</p>
</blockquote>
<h2 id="heading-client-side-validation-in-aspnet-mvc">Client-side validation in ASP.NET MVC</h2>
<p>In WebForms, server-side validation was the primary method employed. However, we developers added the client-side validation to enhance the user experience. The postbacks in web forms were too slow to have to wait on the validation. We had to code the validation rules twice: in javascript and on the backend. Clientside validation was there for the user experience and the serverside validation was there for the same basic validation to ensure no user can circumvent the rules. The backend could also do more advanced validation.</p>
<p>Asp.net core MVC has a different approach. jQuery Validation was introduced into the framework. This plugin allows us to define validation rules and messages for form fields. Rules can be specified using HTML attributes, enabling customization and client-side validation setup.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690038189024/23f5e657-35f5-4020-92c7-3be479777631.png" alt class="image--center mx-auto" /></p>
<p>To streamline the integration of client-side validation into ASP.NET MVC, the jQuery Validate Unobtrusive plugin was introduced. This plugin utilizes HTML5 data attributes to specify validation rules.</p>
<p>I come to the point where I understand why the following scripts are here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690038729698/3ac1b865-7c7c-4c3b-95a3-cdce902acf17.png" alt class="image--center mx-auto" /></p>
<p>But now I got the question, how are the Html 5 data attributes used in the scaffolded project and do I still need to code my validation rules twice, once on the backend and now using HTML 5 data attributes? I will explore this by creating a Registration form and working my way through this until I understand it.</p>
<h1 id="heading-how-aspnet-core-mvc-validation-works">How ASP.NET core MVC validation works</h1>
<p>In this example, I show how C# data attributes are used in ASP.NET MVC to generate validation. The client-side validation scripts use the HTML5 <code>data-val-*</code> attributes to perform client-side validation.</p>
<h2 id="heading-step-1-create-a-model-class">Step 1: Create a Model Class</h2>
<p>Create a model class that represents the data you want to capture from the user. For this example, let's say we have a simple Registration model with two properties: <code>Name</code> and <code>Email</code>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">record</span> <span class="hljs-title">Registration</span>
{
    [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"Name is required."</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"Email is required."</span>)</span>]
    [<span class="hljs-meta">EmailAddress(ErrorMessage = <span class="hljs-meta-string">"Invalid email address."</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>Here, we are using C# validation attributes like <code>[Required]</code> and <code>[EmailAddress]</code> to define the validation rules for the <code>Name</code> and <code>Email</code> properties.</p>
<h2 id="heading-step-2-create-a-view">Step 2: Create a View</h2>
<p>Create a view that is strongly typed to the Registration model. I do this by right-clicking and selecting <em>Creating a RazorPage</em> based on the model <em>Registration</em>.</p>
<pre><code class="lang-xml">@page
@model ScaffoldedProject.Models.Registration

@{
    ViewData["Title"] = "Registration";
}

<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Registration<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Registration<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">asp-action</span>=<span class="hljs-string">"Registration"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">asp-validation-summary</span>=<span class="hljs-string">"ModelOnly"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control-label"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">asp-validation-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control-label"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">asp-validation-for</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Create"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">asp-action</span>=<span class="hljs-string">"Index"</span>&gt;</span>Back to List<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
</code></pre>
<p>In the example VS2022 provided, I can see that tag helper such as <code>asp-for</code>, <code>asp-validation-summary</code>, <code>asp-validation-for</code>, and <code>asp-action</code> is used to generate the HTML form elements, display validation summary and field-specific validation messages, and define the form submit action.</p>
<p>The <code>asp-validation-*</code> tag helpers are responsible for rendering the data attributes needed for client-side validation. These data attributes are then utilized by the <code>jquery.validate.unobtrusive.js</code> script to perform client-side validation based on the rules defined in the C# validation attributes.</p>
<h3 id="heading-what-about-intellisense-and-type-safety">What about Intellisense and type safety?</h3>
<p>When working with HTML, I got intellisense:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690043467942/228566ab-acaf-449b-ae0b-0160bb2e4a05.png" alt class="image--center mx-auto" /></p>
<p>When I choose a property that does not exist in the model, I do get a build error as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690043521933/5b760eb5-98e7-4c85-b908-88e35ecd05b7.png" alt class="image--center mx-auto" /></p>
<p>I got the Registration in Red, because VS2022 does not find a controller</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690043565163/2cd38c24-2ee6-4374-8a83-3e4273304621.png" alt class="image--center mx-auto" /></p>
<p>I fixed this error by creating a RegistrationController in a folder called Controllers</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690043619899/8947289b-2f11-4f2d-b6d2-36bb777e5346.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-3-render-the-view">Step 3: Render the View</h2>
<p>When you run the application and browse to the URL associated with this view, the HTML form elements will be rendered based on the model and the validation attributes. The generated HTML will include data attributes based on the validation attributes:</p>
<ul>
<li><p>the <code>Required</code> attribute applied to the <code>Name</code> property of the RegistrationModel</p>
<pre><code class="lang-csharp">      [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"Name is required."</span>)</span>]
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
</code></pre>
<p>  using the following snippet of the razor from above</p>
<pre><code class="lang-xml">             <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control-label"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">asp-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">asp-validation-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>  Results in the following generated HTML.</p>
<pre><code class="lang-xml">  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control-label"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"Name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control input-validation-error"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">data-val</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">data-val-required</span>=<span class="hljs-string">"Name is required."</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">""</span> <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"Name-error"</span> <span class="hljs-attr">aria-invalid</span>=<span class="hljs-string">"true"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger field-validation-error"</span> <span class="hljs-attr">data-valmsg-for</span>=<span class="hljs-string">"Name"</span> <span class="hljs-attr">data-valmsg-replace</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"Name-error"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Name is required.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>  the same story applies for the <code>EmailAddress</code> attribute on the <code>Email</code> property</p>
<pre><code class="lang-xml">  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control-label"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"Email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control input-validation-error"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">data-val</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">data-val-email</span>=<span class="hljs-string">"Invalid email address."</span> <span class="hljs-attr">data-val-required</span>=<span class="hljs-string">"Email is required."</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">""</span> <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"Email-error"</span> <span class="hljs-attr">aria-invalid</span>=<span class="hljs-string">"true"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-danger field-validation-error"</span> <span class="hljs-attr">data-valmsg-for</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">data-valmsg-replace</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"Email-error"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Email is required.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
</li>
</ul>
<p>These data attributes are used by jQuery Validate and jQuery Validate Unobtrusive. In Summary, These scripts perform client-side validation, defined in the C# data attributes.</p>
<h2 id="heading-step-4-client-side-validation">Step 4: Client-side Validation</h2>
<p>The <code>data-val-required</code> attribute and the <code>data-val-email</code> attribute will be used by jQuery Validate to validate the required and email fields respectively. jQuery Validate will be able to do this because jQuery Validate Unobtrusive defined the rules and added support to those rules in the jQuery Validate framework.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690048191082/49289bad-db77-4d04-b5ce-12e3fd53bebd.png" alt class="image--center mx-auto" /></p>
<p>The above text displays after the <code>inputbox</code> loses focus.</p>
<h1 id="heading-difference-between-jquery-validate-and-jquery-validate-unobtrusive">Difference between jQuery Validate and jQuery Validate Unobtrusive</h1>
<p>The difference between jQuery Validate and jQuery Validate Unobtrusive lies in how they handle client-side validation based on the data attributes generated from C# validation attributes.</p>
<p>The two scripts, <code>jquery.validate.js</code> and <code>jquery.validate.unobtrusive.js</code> are included in the <code>ValidationscriptsPartial.cshtml</code> in an ASP.NET core MVC project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690038729698/3ac1b865-7c7c-4c3b-95a3-cdce902acf17.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-jquery-validate">jQuery Validate</h2>
<p>This script allows you to define validation rules and error messages for form fields using a flexible API. I can customize the validation rules and messages for each field. It supports custom validation methods and remote validation.</p>
<p>jQuery Validate will scan the HTML form elements for the data attributes and applies the specified validation rules based on those attributes. When the form is submitted, jQuery Validate intercepts the submission and validates the fields based on the defined rules. If any validation errors occur, it displays error messages and prevents form submission until all fields are valid.</p>
<h3 id="heading-example">Example</h3>
<p>In the code of <code>jquery.validate</code> I found the following code for <code>required</code> and <code>email</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// https://jqueryvalidation.org/jQuery.validator.methods/</span>
    <span class="hljs-attr">methods</span>: {

        <span class="hljs-comment">// https://jqueryvalidation.org/required-method/</span>
        <span class="hljs-attr">required</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"> value, element, param </span>) </span>{

            <span class="hljs-comment">// Check if dependency is met</span>
            <span class="hljs-keyword">if</span> ( !<span class="hljs-built_in">this</span>.depend( param, element ) ) {
                <span class="hljs-keyword">return</span> <span class="hljs-string">"dependency-mismatch"</span>;
            }
            <span class="hljs-keyword">if</span> ( element.nodeName.toLowerCase() === <span class="hljs-string">"select"</span> ) {

                <span class="hljs-comment">// Could be an array for select-multiple or a string, both are fine this way</span>
                <span class="hljs-keyword">var</span> val = $( element ).val();
                <span class="hljs-keyword">return</span> val &amp;&amp; val.length &gt; <span class="hljs-number">0</span>;
            }
            <span class="hljs-keyword">if</span> ( <span class="hljs-built_in">this</span>.checkable( element ) ) {
                <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getLength( value, element ) &gt; <span class="hljs-number">0</span>;
            }
            <span class="hljs-keyword">return</span> value !== <span class="hljs-literal">undefined</span> &amp;&amp; value !== <span class="hljs-literal">null</span> &amp;&amp; value.length &gt; <span class="hljs-number">0</span>;
        },

        <span class="hljs-comment">// https://jqueryvalidation.org/email-method/</span>
        <span class="hljs-attr">email</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"> value, element </span>) </span>{

            <span class="hljs-comment">// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address</span>
            <span class="hljs-comment">// Retrieved 2014-01-14</span>
            <span class="hljs-comment">// If you have a problem with this implementation, report a bug against the above spec</span>
            <span class="hljs-comment">// Or use custom methods to implement your own email validation</span>
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.optional( element ) || <span class="hljs-regexp">/^[a-zA-Z0-9.!#$%&amp;'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/</span>.test( value );
        },
</code></pre>
<p>So I can see that jQuery Validate offers the rules that I need.</p>
<h2 id="heading-jquery-validate-unobtrusive">jQuery Validate Unobtrusive</h2>
<p>This script is an additional script that works in conjunction with jQuery Validate and ASP.NET MVC. It helps bridge the gap between C# validation attributes and jQuery Validate by applying the validation rules defined in C# to the client-side validation. Note that only the attributes in the jQuery Validate Ubobtrusive can be used. When I want to use custom attributes, I will need to do some extra work.</p>
<p>When I include the <code>jquery.validate.unobtrusive.js</code> file, it reads the data attributes and wires up jQuery Validate to use those rules for client-side validation. It takes care of mapping the C# validation attributes (such as Required, StringLength, etc.) to the appropriate jQuery Validate rules.</p>
<p><code>jquery.validate.unobtrusive.js</code> depends on <code>jquery.validate.js</code>. It does not override or replace the core functionality provided by <code>jquery.validate.js</code>.</p>
<h3 id="heading-example-1">Example</h3>
<p>In the code of <code>jquery.validate.unobtrusive.js</code> I found the following code for <code>email</code> attribute.</p>
<pre><code class="lang-javascript">    adapters....addBool(<span class="hljs-string">"email"</span>)....;

   adapters.addBool = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">adapterName, ruleName</span>) </span>{
        <span class="hljs-comment">/// &lt;summary&gt;Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where</span>
        <span class="hljs-comment">/// the jQuery Validate validation rule has no parameter values.&lt;/summary&gt;</span>
        <span class="hljs-comment">/// &lt;param name="adapterName" type="String"&gt;The name of the adapter to be added. This matches the name used</span>
        <span class="hljs-comment">/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).&lt;/param&gt;</span>
        <span class="hljs-comment">/// &lt;param name="ruleName" type="String" optional="true"&gt;[Optional] The name of the jQuery Validate rule. If not provided, the value</span>
        <span class="hljs-comment">/// of adapterName will be used instead.&lt;/param&gt;</span>
        <span class="hljs-comment">/// &lt;returns type="jQuery.validator.unobtrusive.adapters" /&gt;</span>
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.add(adapterName, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">options</span>) </span>{
            setValidationValues(options, ruleName || adapterName, <span class="hljs-literal">true</span>);
        });
    };
</code></pre>
<p>And of course for the <code>required</code> attribute.</p>
<pre><code class="lang-javascript">
 adapters.add(<span class="hljs-string">"required"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">options</span>) </span>{
        <span class="hljs-comment">// jQuery Validate equates "required" with "mandatory" for checkbox elements</span>
        <span class="hljs-keyword">if</span> (options.element.tagName.toUpperCase() !== <span class="hljs-string">"INPUT"</span> || options.element.type.toUpperCase() !== <span class="hljs-string">"CHECKBOX"</span>) {
            setValidationValues(options, <span class="hljs-string">"required"</span>, <span class="hljs-literal">true</span>);
        }
    });

     <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setValidationValues</span>(<span class="hljs-params">options, ruleName, value</span>) </span>{
        options.rules[ruleName] = value;
        <span class="hljs-keyword">if</span> (options.message) {
            options.messages[ruleName] = options.message;
        }
    }
</code></pre>
<h1 id="heading-can-i-update-jquery-jquery-validate-and-jquery-validate-unobtrusive">Can I update <code>jQuery</code>, <code>jQuery Validate</code> and <code>jQuery Validate Unobtrusive</code>?</h1>
<p>Now I understand the link between everything, and after writing my previous post about LibMan and npm, I can answer this question.</p>
<p>The generated <code>data-val-*</code> attributes are the interface for the validation rules. When using the tag helpers, that happens using the <code>asp-validation-for</code> attribute.</p>
<p>I can confidently update to a more recent version of jQuery Validate Unobtrusive. This is the framework I need to manage. It depends on jQuery Validate and jQuery. When updating to a newer script Unobtrusive script, I can refer to the <a target="_blank" href="https://github.com/aspnet/jquery-validation-unobtrusive/releases">release notes</a> of this framework.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690048004412/445c36da-df69-4bfb-807e-e834ddbd34fa.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app">I will not use LibMan but instead, opt for npm. If I have other dependencies that utilize jQuery and jQuery Validate, I can easily identify conflicts when updating.</a></p>
<h1 id="heading-outro">Outro</h1>
<p>I've shared the history and evolution I learned of ASP.NET MVC, AJAX, and jQuery. With the release of ASP.NET MVC, the integration of jQuery provides a user-friendly API for client-side development. This integration, combined with the use of data attributes and validation attributes in ASP.NET MVC, allows for seamless client-side validation. There is also an evolution towards tag helpers instead of Html helpers.</p>
<p>By utilizing C# validation attributes, I can easily define validation rules for our model properties which are automatically translated into HTML form elements with corresponding data attributes.</p>
<p>Understanding this process has given me the confidence to update these scripts using tools like npm to manage dependencies and avoid conflicts within my application.</p>
<p>In one of my next posts, I will figure out how to add support for FluentValidation and how to support custom attributes on my models.</p>
<h1 id="heading-sources">Sources</h1>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-7.0">Tag Helpers in</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-7.0">Core | Microsoft Learn</a></p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start?view=aspnetcore-7.0&amp;tabs=visual-studio">https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start?view=aspnetcore-7.0&amp;tabs=visual-studio</a></p>
<p><a target="_blank" href="https://github.com/aspnet/jquery-validation-unobtrusive/releases">Releases · aspnet/jquery-validation-unobtrusive (</a><a target="_blank" href="http://github.com">github.com</a><a target="_blank" href="https://github.com/aspnet/jquery-validation-unobtrusive/releases">)</a></p>
<p><a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://en.wikipedia.org/wiki/ASP.NET_Web_Forms">Web Forms - Wikipedia</a></p>
<p><a target="_blank" href="https://www.dotnetcurry.com/aspnet/1492/aspnet-history-part-1">The History of</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://www.dotnetcurry.com/aspnet/1492/aspnet-history-part-1">– Part I | DotNetCurry</a></p>
<p><a target="_blank" href="https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app">Upgrade Your Client-Side Script Approach in a Basic Dotnet</a> <a target="_blank" href="http://Asp.Net">Asp.Net</a> <a target="_blank" href="https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app">Core MVC App (</a><a target="_blank" href="http://kriebbels.me">kriebbels.me</a><a target="_blank" href="https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app">)</a></p>
<p><a target="_blank" href="https://stackoverflow.com/questions/1333488/does-anyone-know-the-history-of-asp-net-webforms">Does anyone know the history of</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://stackoverflow.com/questions/1333488/does-anyone-know-the-history-of-asp-net-webforms">Webforms? - Stack Overflow</a></p>
]]></content:encoded></item><item><title><![CDATA[Upgrade Your Client-Side Script Approach in a Basic Dotnet Asp.Net Core MVC App]]></title><description><![CDATA[Previously on...
In my previous articles, I discussed DevOps, DotNet and Security. This article builds upon those three components and explores the role of package managers in managing server-side and client-side libraries in a .NET MVC project.
Cont...]]></description><link>https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app</link><guid isPermaLink="true">https://dotnet.kriebbels.me/upgrade-your-client-side-script-approach-in-a-basic-dotnet-aspnet-core-mvc-app</guid><category><![CDATA[npm]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[mvc]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[libman]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 16 Jul 2023 06:44:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1689447837530/a0553bb1-2e6b-45a5-9e5f-4ca1055736bc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>In my previous articles, I discussed <a target="_blank" href="https://dotnet.kriebbels.me/series/devops">DevOps</a>, <a target="_blank" href="https://dotnet.kriebbels.me/series/dotnet">DotNet</a> and <a target="_blank" href="https://dotnet.kriebbels.me/series/security">Security</a>. This article builds upon those three components and explores the role of package managers in managing server-side and client-side libraries in a .NET MVC project.</p>
<h1 id="heading-context">Context</h1>
<p>I find myself working on a new Asp.Net Core project. In the previous projects, the pen-testers and the SAST scan informed me that I use old versions of javascript libraries like jQuery. Managing and updating these libraries are not provided by default it seems. This led me to explore how to manage those files.</p>
<p>At the beginning of time, we used linked files and created scripts. We as developers manually copied and included libraries in our projects. Over time, the development community has witnessed an evolution in the way libraries are managed.</p>
<p>All this was prone to errors and made updates difficult. For the backend developers, GAC was the first solution to try to manage the DLL hell. The introduction of package managers like NuGet was a successor. It offered a centralized repository for clientside and serverside libraries. The goal was to simplify management and the updating process. Javascript developers needed something less coupled to NuGet and npm was born.</p>
<p>JavaScript has been the go-to language for some backend applications but more for web applications. To manage client-side libraries, we developers have relied on tools like npm and Yarn. These package managers allow us to integrate libraries and frameworks such as jQuery, AngularJS, and React.</p>
<p>JavaScript package managers like npm and yarn are popular. Npm has become the choice. It has compatibility with server-side JavaScript frameworks like Node.js.</p>
<p>In the .NET world, a newly scaffolded ASP.NET Core project does not include clientside package management for the already given client libraries.</p>
<p>First thing first. I am talking about package managers. What is the purpose of a package manager so I can understand it better? What do I need to do because it is not included in a default scaffolded ASP.Net Core project?</p>
<h1 id="heading-why-a-package-manager">Why a package manager?</h1>
<p>Package managers serve an important role in software development:</p>
<ul>
<li>Simplifying Dependency Management</li>
</ul>
<p>Managing dependencies manually can quickly become complex and error-prone. Package managers automate the process of library installation. No more copy and paste.</p>
<ul>
<li>Ensuring Version Control</li>
</ul>
<p>Each library update may introduce bug fixes, security patches, or new features. Package managers help enforce version control by providing a centralized repository of libraries and their corresponding versions. This allows me to select the most suitable version and traceability.</p>
<ul>
<li>Streamlining interdependencies</li>
</ul>
<p>Package managers enable reproducible builds, ensuring that the same set of libraries and versions are used across different machines or deployments. That will reduce the risk of compatibility issues because the package manager will try to figure out what common packages are compatible with each other.</p>
<ul>
<li>Discoverability</li>
</ul>
<p>Package managers provide a centralized repository or registry where I can discover new libraries, frameworks, and tools.</p>
<ul>
<li>Security and Maintenance</li>
</ul>
<p>By regularly updating packages through package managers, I can address security concerns and reduce the risk of bugs and attacks.</p>
<h1 id="heading-show-me-something-already">Show me something already</h1>
<p>I will scaffold an asp.net core MVC project. I will investigate the javascript files. Discover what package managers there are. I will try to manage them using a package manager and convert them to use another one.</p>
<h2 id="heading-an-aspnet-core-mvc-fresh-project">An Asp.Net Core MVC Fresh Project</h2>
<p>Let us look at what I received after I created an Asp.Net Core MVC Application using VS 2022.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689427478397/7ac6cacc-c87c-4008-a5b2-fdb20cafafd7.png" alt class="image--center mx-auto" /></p>
<p>I notice a lot of given client javascript files.</p>
<ul>
<li><p><code>site.js</code>: This file is a custom JavaScript file where I can write my client-side javascript code.</p>
</li>
<li><p><code>bootstrap.js</code>: This file is the JavaScript component of the Bootstrap framework. It adds dynamic behaviour to the Bootstrap UI components.</p>
</li>
<li><pre><code class="lang-typescript">  <span class="hljs-comment">/*!
    * Bootstrap v5.1.0 (https://getbootstrap.com/)
    * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
    * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
    */</span>
</code></pre>
</li>
<li><p><code>jquery.js</code>: This is the jQuery library file. It provides an API for manipulating and interacting with HTML elements.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">/*!
   * jQuery JavaScript Library v3.5.1
   * https://jquery.com/
   *
   * Includes Sizzle.js
   * https://sizzlejs.com/
   *
   * Copyright JS Foundation and other contributors
   * Released under the MIT license
   * https://jquery.org/license
   *
   * Date: 2020-05-04T22:49Z
   */</span>
</code></pre>
</li>
<li><p><code>jquery.validate.js</code>: This is a popular jQuery called jQuery Validation plugin that provides extensive form validation capabilities.</p>
<pre><code class="lang-typescript">   * jQuery Validation Plugin v1<span class="hljs-number">.17</span><span class="hljs-number">.0</span>
   *
   * https:<span class="hljs-comment">//jqueryvalidation.org/</span>
</code></pre>
</li>
<li><p><code>jquery.validate.unobtrusive.js</code>: This file is a jQuery plugin that works in conjunction with jQuery Validation and the ASP.NET Core MVC framework. The purpose of jQuery Validation Unobtrusive is to validate user input on the client side before submitting the form to the server. More on that in a later blog post.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Unobtrusive validation support library for jQuery and jQuery Validate</span>
  <span class="hljs-comment">// Copyright (c) .NET Foundation. All rights reserved.</span>
  <span class="hljs-comment">// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.</span>
  <span class="hljs-comment">// @version v3.2.11</span>
</code></pre>
</li>
</ul>
<p>I can safely say that four of the five files are part of a package. The downside is that Microsoft delivers us library as files. That gives us the possibility to add or change code. From the moment that I or somebody else does this, hell can break loose later on in the development cycle. Imagine a bugfix or I want to use new features. But for that, I need a new file. Updating the file will translate into losing the functionality of the changes I made. So I need to compare the sources... Those practices are not anymore in this day and age.</p>
<p>Let us try to add some package management.</p>
<h1 id="heading-what-package-manager-do-we-have">What Package Manager do we have?</h1>
<p>As a dotnet backend developer, I use NuGet. When I take on the role of a FrontEnd developer, I seem to have these choices:</p>
<ol>
<li><p><strong>npm</strong> (Node Package Manager) is the default package manager for the JavaScript/Typescript ecosystem. It is widely used for managing dependencies.</p>
</li>
<li><p><strong>Yarn</strong> is a fast and reliable package manager developed by Facebook. It aims to address some performance and security issues found in npm. Yarn uses the same <code>package.json</code> format as npm and is compatible with existing npm packages.</p>
</li>
<li><p><strong>Pnpm</strong> is a fast and space-efficient package manager that reduces duplication of dependencies across projects. It uses a unique approach called "shared dependencies" to save disk space and improve installation speed.</p>
</li>
</ol>
<p>But what does Microsoft offer? Microsoft has something that is called LibMan.</p>
<h1 id="heading-enter-libman">Enter LibMan</h1>
<p>LibMan (short for Library Manager) is a client-side library acquisition tool and not a traditional package manager. It is part of the Microsoft ecosystem and is primarily used in combination with ASP.NET Core projects to manage client-side library assets.</p>
<p>LibMan simplifies acquiring client-side libraries. It is designed to integrate with ASP.NET Core projects. It allows me to specify the libraries I require. It will download the files directly from external sources like Content Delivery Networks (CDNs), GitHub repositories or other locations.</p>
<p>It does not provide the same level of dependency management and version control as npm or Yarn.</p>
<p>Let me try out LibMan.</p>
<h2 id="heading-creating-a-libmanjson">Creating a <code>LibMan.json</code></h2>
<p>Since VS 2017 there is support for LibMan. I use Visual Studio 2022 Community 17.6.4. When I right-click on my project I get the possibility to manage ClientSide Libraries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689430290798/d32fae56-5fe1-4dd4-8a3f-a0b460455edc.png" alt class="image--center mx-auto" /></p>
<p>However, In the Menu Project, I only have a user interface for NuGet Manager.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689430352752/57314e1b-b354-4e17-a642-37775684943e.png" alt class="image--center mx-auto" /></p>
<p>After I click on <code>Manage Client-Side Libraries</code>, a <code>libman.json</code> file is created.</p>
<p>There I can define library location. This file includes information about the libraries, versions, target paths and source. The target paths are already used in the HTML and JavaScript files that I receive when I create an asp.net core MVC project from scratch. Because I do not change the target path, all should still work as intended.</p>
<p>For this project, I reversed-engineered it to the following <code>libman.json</code> file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"defaultProvider"</span>: <span class="hljs-string">"cdnjs"</span>,
  <span class="hljs-attr">"libraries"</span>: [
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"bootstrap@5.1.0"</span>,
      <span class="hljs-attr">"destination"</span>: <span class="hljs-string">"wwwroot/lib/bootstrap/dist"</span>,
      <span class="hljs-attr">"files"</span>: [
        <span class="hljs-string">"js/bootstrap.js"</span>,
        <span class="hljs-string">"js/bootstrap.min.js"</span>
      ]
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery@3.5.1"</span>,
      <span class="hljs-attr">"destination"</span>: <span class="hljs-string">"wwwroot/lib/jquery/dist"</span>,
      <span class="hljs-attr">"files"</span>: [
        <span class="hljs-string">"jquery.js"</span>,
        <span class="hljs-string">"jquery.min.js"</span>
      ]
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery-validate@1.17.0"</span>,
      <span class="hljs-attr">"destination"</span>: <span class="hljs-string">"wwwroot/lib/jquery-validation/dist"</span>,
      <span class="hljs-attr">"files"</span>: [
        <span class="hljs-string">"jquery.validate.js"</span>,
        <span class="hljs-string">"additional-methods.js"</span>,
        <span class="hljs-string">"jquery.validate.min.js"</span>,
        <span class="hljs-string">"additional-methods.min.js"</span>
      ]
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery-validation-unobtrusive@3.2.11"</span>,
      <span class="hljs-attr">"destination"</span>: <span class="hljs-string">"wwwroot/lib/jquery-validation-unobtrusive/"</span>,
      <span class="hljs-attr">"files"</span>: [
        <span class="hljs-string">"jquery.validate.unobtrusive.js"</span>,
        <span class="hljs-string">"jquery.validate.unobtrusive.min.js"</span>

      ]
    }
  ]
}
</code></pre>
<p>When saving the file, Visual Studio goes to work and I got the following output:</p>
<pre><code class="lang-plaintext">Restore operation started
Restoring libraries for project ScaffoldedProject
Restoring library bootstrap@5.1.0... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/js/bootstrap.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/js/bootstrap.min.js... (ScaffoldedProject)
wwwroot/lib/bootstrap/dist/js/bootstrap.js written to destination (ScaffoldedProject)
wwwroot/lib/bootstrap/dist/js/bootstrap.min.js written to destination (ScaffoldedProject)
Restoring library jquery@3.5.1... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js... (ScaffoldedProject)
wwwroot/lib/jquery/dist/jquery.js written to destination (ScaffoldedProject)
wwwroot/lib/jquery/dist/jquery.min.js written to destination (ScaffoldedProject)
Restoring library jquery-validate@1.17.0... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/additional-methods.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/additional-methods.min.js... (ScaffoldedProject)
wwwroot/lib/jquery-validation/dist/jquery.validate.js written to destination (ScaffoldedProject)
wwwroot/lib/jquery-validation/dist/additional-methods.js written to destination (ScaffoldedProject)
wwwroot/lib/jquery-validation/dist/jquery.validate.min.js written to destination (ScaffoldedProject)
wwwroot/lib/jquery-validation/dist/additional-methods.min.js written to destination (ScaffoldedProject)
Restoring library jquery-validation-unobtrusive@3.2.11... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js... (ScaffoldedProject)
Downloading file https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js... (ScaffoldedProject)
wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js written to destination (ScaffoldedProject)
wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js written to destination (ScaffoldedProject)
Restore operation completed
</code></pre>
<p>When I do not have access to Visual Studio, I can use the CLI with the following command: <code>libman restore</code>.</p>
<h2 id="heading-updating-packages">Updating packages</h2>
<p>Can we now update safely to the latest minor? Because the package uses SemVer, I should be able to update it without problems. However, updating a Major version will need some extra investigation. I quote SemVer.org</p>
<blockquote>
<p>Given a version number MAJOR.MINOR.PATCH, increment the:</p>
<ol>
<li><p>MAJOR version when you make incompatible API changes</p>
</li>
<li><p>MINOR version when you add functionality in a backward compatible manner</p>
</li>
<li><p>PATCH version when you make backward compatible bug fixes</p>
</li>
</ol>
<p>Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.</p>
</blockquote>
<p>In the libman.json, Visual Studio offers a tooltip with more information about a package:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689433295928/250e5989-c83a-4199-92de-8b9495f01093.png" alt class="image--center mx-auto" /></p>
<p>In the image above I notice that there is a newer version. Security-wise, I should always use the latest stable version that is most compatible with what I use or need.</p>
<p>The update <code>libman.json</code> looks like this (redacted):</p>
<pre><code class="lang-json">**redacted**
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"bootstrap@5.3.0"</span>,
**redacted**
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery@3.7.0"</span>,
**redacted**
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery-validate@1.19.5"</span>,
**redacted**
    },
    {
      <span class="hljs-attr">"library"</span>: <span class="hljs-string">"jquery-validation-unobtrusive@4.0.0"</span>,
**redacted**
</code></pre>
<p><code>Bootstrap</code>, <code>JQuery</code> and <code>JQuery-Validate</code> is updated to the latest Minor. That ensures backward compatibility with new features. However, the <code>jQuery-Validation-unobstrusive</code> got a new Major version. This means that breaking changes can occur. Not only in the library itself but in what it uses as a dependency. When I look at the GitHub repository, I notice that the package manager NuGet is used and for <a target="_blank" href="https://www.nuget.org/packages/Microsoft.jQuery.Unobtrusive.Validation#dependencies-body-tab">jQuery NuGet Version 1.8</a> is used. So I already start to feel the pain of manually working out the dependencies between all those files.</p>
<h2 id="heading-so-why-not-npm-or-yarn-or">So... why not npm or yarn or ...</h2>
<p>LibMan is not a full-fledged package manager. I will use npm and yarn as a comparison.</p>
<p>npm and Yarn have:</p>
<ul>
<li><p>a lot of packages from the <strong>official</strong> package registry. They excel in managing complex dependency trees and versioning control. This all makes it easier to ensure compatibility between different packages.</p>
</li>
<li><p>large and active developer communities, which means there is extensive community support, documentation, and tutorials available. LibMan is only an acquiring tool.</p>
</li>
<li><p>build configuration options. This allows me to define custom scripts, and automate tasks. This flexibility can be beneficial for large-scale projects or when you require more fine-grained control over build processes.</p>
</li>
<li><p>good compatibility with build tools like Webpack, Babel, and ESLint.</p>
</li>
<li><p>support for plugins and extensions that further extend their capabilities.</p>
</li>
</ul>
<p>In this project, there are dependencies between them. It makes more sense to ensure compatibility between all those files.</p>
<p>What would that look like? To mimic the functionality of the <code>libman.json</code> file using npm, I can leverage npm's <code>package.json</code> file. I can manage the dependencies as regular npm packages. The following is <code>package.json</code> file that replicates the <code>libman.json</code> configurations:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"@Scaffold-1.0.0"</span>,
   <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"update-libs"</span>: <span class="hljs-string">"npm update bootstrap jquery jquery-validation jquery-validation-unobtrusive"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"bootstrap"</span>: <span class="hljs-string">"^5.3.0"</span>,
    <span class="hljs-attr">"jquery"</span>: <span class="hljs-string">"^3.7.0"</span>,
    <span class="hljs-attr">"jquery-validation"</span>: <span class="hljs-string">"^1.19.5"</span>,
    <span class="hljs-attr">"jquery-validation-unobtrusive"</span>: <span class="hljs-string">"^4.0.0"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {  }
}
</code></pre>
<p>In this <code>package.json</code> file:</p>
<ul>
<li><p>All the required libraries (<code>bootstrap</code>, <code>jquery</code>, <code>jquery-validation</code>, <code>jquery-validation-unobtrusive</code>) are defined as regular dependencies under the <code>"dependencies"</code> section.</p>
</li>
<li><p>The script allows me to update the libraries later using the <code>npm run update-libs</code> command if newer versions become available.</p>
</li>
</ul>
<p>To install the dependencies and set up the required folder structure, I can run <code>npm install</code> or I can do a right click in Visual Studio and choose <code>Restore Packages</code>. This will install the defined packages, and create the necessary directories under <code>node_modules</code>.</p>
<pre><code class="lang-plaintext">PATH=.\node_modules\.bin;C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VisualStudio\NodeJs\win-x64;C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VisualStudio\NodeJs;C:\Program Files\Microsoft Visual Studio\2022\Community\Web\External;%PATH%;C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Git\cmd
"C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VisualStudio\NodeJs\npm.CMD" install
added 6 packages, and audited 7 packages in 6s
2 packages are looking for funding
  run `npm fund` for details
</code></pre>
<p>With this setup, I can handle the installation, updating, and version control of the specified libraries in a similar way to <code>libman.json</code>. Visual Studio visualises this on the project level, under dependencies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689434897101/9a95ed56-372a-4ffb-90e5-8d6f8ea9cea3.png" alt class="image--center mx-auto" /></p>
<p>The files are downloaded where npm handles them, in <code>node_modules</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689435110214/4a3d3ba5-afce-4c49-a519-f609a17ba276.png" alt class="image--center mx-auto" /></p>
<p>And now the pain begins. I need to change all the html files that have referenced the lib folder. I also need to ensure that only the needed files from the <code>node_modules</code> are available when the project is published. I include the following in my <code>csproj</code> file.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">ItemGroup</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">None</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"node_modules\**\*"</span>
        <span class="hljs-attr">CopyToPublishDirectory</span>=<span class="hljs-string">"PreserveNewest"</span>
        <span class="hljs-attr">CopyToPublishDirectoryExclude</span>=<span class="hljs-string">"**/*.ts; **/*.map"</span>
        <span class="hljs-attr">CopyToPublishDirectoryAlways</span>=<span class="hljs-string">"false"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">Content</span> <span class="hljs-attr">Include</span>=<span class="hljs-string">"node_modules\**\*.min.js"</span>
           <span class="hljs-attr">CopyToPublishDirectory</span>=<span class="hljs-string">"PreserveNewest"</span>
           <span class="hljs-attr">CopyToPublishDirectoryAlways</span>=<span class="hljs-string">"false"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ItemGroup</span>&gt;</span>
</code></pre>
<p>The funny thing is that when I add the <code>node_modules</code> folder, it disappears from the Dependencies in the Solution Explorer... Down the rabbit hole, I go. I notice that there are other dependencies, that I did not specify using <code>LibMan.json</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1689435660419/84797621-65cf-4d55-9c7f-6d59b51de010.png" alt class="image--center mx-auto" /></p>
<p>However, here I will end the blog post. I think I made it clear what the difference is between LibMan and e.g. npm and why I should address this from the start before I do my coding to ensure I have a working version. I should at least use LibMan, to protect the project from people that want to manually changes the javascript files.</p>
<h1 id="heading-outro">Outro</h1>
<p>I have explored the importance and purpose of package managers. I find package managers to be indispensable tools in my workflow. I do not understand why the scaffolded project does not come with preconfigured <code>libman.json</code> or with a <code>package.json</code></p>
<p>LibMan offers a direct link to a source and will make it harder for us developers to change the javascript files to change something. Having such a <code>libman.json</code>, makes it easier to migrate to a later version. It gives a sense of urgency to try to update these files to the latest (minor) version, ensuring we have the latest secure versions.</p>
<p>However, the fun begins when you want to use more packages and have common dependencies. From then on, npm will help you out.</p>
<p>What do you think? What did I miss? Do you have any other insights? Let me know! Let us engage.</p>
<h1 id="heading-sources">Sources</h1>
<p>Below I give an overview of the sources I used to write this.</p>
<p><a target="_blank" href="https://www.google.com/search?q=javascript+client+package+managers&amp;oq=javascript+client+package+managers&amp;aqs=edge..69i57j0i546l2.8172j0j4&amp;sourceid=chrome&amp;ie=UTF-8">javascript client package managers - Google Search</a></p>
<p><a target="_blank" href="https://blog.logrocket.com/javascript-package-managers-compared/">JavaScript package managers compared: npm, Yarn, or pnpm? - LogRocket Blog</a></p>
<p><a target="_blank" href="https://medium.com/@garadiya0/which-package-manager-to-choose-for-your-next-javascript-project-13eab214a05c?source=tag_page---------32-84--------------------aa75c5a1_98b6_401a_8774_bb6d743c4e45-------17">Which package manager to choose for your next javascript project? | by Himanshu Garadiya | Jun, 2023 | Medium</a></p>
<p><a target="_blank" href="https://www.c-sharpcorner.com/blogs/package-managers-in-javascript">Package Managers in JavaScript (</a><a target="_blank" href="http://c-sharpcorner.com">c-sharpcorner.com</a><a target="_blank" href="https://www.c-sharpcorner.com/blogs/package-managers-in-javascript">)</a></p>
<p><a target="_blank" href="https://snyk.io/blog/bower-is-dead/">Bower is dead, long live npm. And Yarn. And webpack. | Snyk</a></p>
<p><a target="_blank" href="https://semver.org/">Semantic Versioning 2.0.0 | Semantic Versioning (</a><a target="_blank" href="http://semver.org">semver.org</a><a target="_blank" href="https://semver.org/">)</a></p>
<p><a target="_blank" href="https://github.com/aspnet/jquery-validation-unobtrusive/commit/6c2113ee25f10092b206cb409c6d3e33a9ee44c8#diff-e4bed5b736f205989dd4fdb6d78acfe9126577983d325d378ce91794d74e63c8">Add nuspec and build file (#77) · aspnet/jquery-validation-unobtrusive@6c2113e (</a><a target="_blank" href="http://github.com">github.com</a><a target="_blank" href="https://github.com/aspnet/jquery-validation-unobtrusive/commit/6c2113ee25f10092b206cb409c6d3e33a9ee44c8#diff-e4bed5b736f205989dd4fdb6d78acfe9126577983d325d378ce91794d74e63c8">)</a></p>
<p><a target="_blank" href="https://jspm.org/">https://jspm.org/</a></p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/client-side/libman/?view=aspnetcore-7.0">Client-side library acquisition in</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/client-side/libman/?view=aspnetcore-7.0">Core with LibMan | Microsoft Learn</a></p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/client-side/libman/libman-vs?view=aspnetcore-7.0">Use LibMan with</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/client-side/libman/libman-vs?view=aspnetcore-7.0">Core in Visual Studio | Microsoft Learn</a></p>
<p><a target="_blank" href="https://github.com/aspnet/LibraryManager">aspnet/LibraryManager (</a><a target="_blank" href="http://github.com">github.com</a><a target="_blank" href="https://github.com/aspnet/LibraryManager">)</a></p>
<p><a target="_blank" href="https://www.npmjs.com/">npm (</a><a target="_blank" href="http://npmjs.com">npmjs.com</a><a target="_blank" href="https://www.npmjs.com/">)</a></p>
<p><a target="_blank" href="https://medium.com/@easylob/a-alternative-way-to-use-visual-studio-with-npm-5427d938ff05">An alternative way to use Visual Studio with npm | by EasyLOB | Medium</a></p>
]]></content:encoded></item><item><title><![CDATA[How to read a claim from a token in DotNet 6?]]></title><description><![CDATA[Previously On
In my previous articles, I discussed the creation of a mocked OpenID Connect provider and the evolution of the HttpClient. Today, I want to discuss how user attributes (claims) are presented to the application using tokens.
Context
When...]]></description><link>https://dotnet.kriebbels.me/how-to-read-a-claim-from-a-token-in-dotnet-6</link><guid isPermaLink="true">https://dotnet.kriebbels.me/how-to-read-a-claim-from-a-token-in-dotnet-6</guid><category><![CDATA[OpenID Connect]]></category><category><![CDATA[access-token]]></category><category><![CDATA[dotnetcore]]></category><category><![CDATA[tokens]]></category><category><![CDATA[claim]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 09 Jul 2023 18:18:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688926460700/1d186bae-0339-416c-96a4-9618d948c62c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously On</h1>
<p>In my previous articles, I discussed the c<a target="_blank" href="https://xpirit.com/mock-your-openid-connect-provider/">reation of a mocked OpenID Connect provider</a> and <a target="_blank" href="https://dotnet.kriebbels.me/understanding-the-httpclient-an-overview-with-code">the evolution of the HttpClient</a>. Today, I want to discuss how user attributes (claims) are presented to the application using tokens.</p>
<h1 id="heading-context">Context</h1>
<p>When I explored a codebase, I noticed that the access tokens and ID tokens are retrieved from the <code>HttpRequest.</code> This happened using custom code to access the headervalue of <code>id_token</code> and <code>access_token</code>. However, Asp.net core does give us the possibility to access those claims using <code>HttpContext.User.Claims</code> property.</p>
<p>In my code, I typically use the <code>AddJwtBearer</code> methods for backend services. When working on an MVC application, I tend to use the <code>AddOpenIdConnect</code> method. I find it a bit unclear when to use what. I want to clarify the differences between the two. It is not the scope of this article to state clearly the functional purpose of all the types of tokens.</p>
<p>Before we dive into the mechanics of accessing and utilizing claims, let's discuss what claims are and their purpose.</p>
<h1 id="heading-claims">Claims</h1>
<p>A claim represents a piece of information about a user. An example of a claim is a user's name, email address, and role,...</p>
<h2 id="heading-tokens">Tokens</h2>
<p>A token is a string that serves as proof of identity or permission. Tokens are used to authenticate and authorize users.</p>
<p>Claims are stored in a token by e.g. Saml, Oauth2, OpenIdConnect or other authorization providers. The application will use the tokens for authentication and authorization purposes. The application is in Oauth2/OpenIdConnect jargon called a resource server. I will slightly mention 3 types of tokens: JWT, SAML and Opaque.</p>
<h3 id="heading-jwt-json-web-token">JWT (JSON Web Token):</h3>
<p>JWT is a compact, URL-safe, and self-contained token format that consists of three base64-encoded parts separated by dots.</p>
<p>The three parts are the header, the payload, and the signature.</p>
<pre><code class="lang-xml">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
</code></pre>
<p>When decoded using jwt.ms, I get the following content</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"HS256"</span>,
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>
}.{
  <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
  <span class="hljs-attr">"iat"</span>: <span class="hljs-number">1516239022</span>
}.[Signature]
</code></pre>
<p>In this example, <code>sub</code>, <code>name</code> and <code>iat</code> are claims.</p>
<h3 id="heading-saml-security-assertion-markup-language-token">SAML (Security Assertion Markup Language) Token</h3>
<p>SAML tokens are XML-based tokens used for exchanging authentication and authorization data between identity providers and service providers ( the application = resource server).</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Assertion</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"urn:oasis:names:tc:SAML:2.0:assertion"</span> <span class="hljs-attr">ID</span>=<span class="hljs-string">"_934873948nc4"</span> <span class="hljs-attr">IssueInstant</span>=<span class="hljs-string">"2022-03-01T12:34:56Z"</span> <span class="hljs-attr">Version</span>=<span class="hljs-string">"2.0"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Issuer</span>&gt;</span>https://identityprovider.com<span class="hljs-tag">&lt;/<span class="hljs-name">Issuer</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Subject</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">NameID</span>&gt;</span>1234567890<span class="hljs-tag">&lt;/<span class="hljs-name">NameID</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">SubjectConfirmation</span> <span class="hljs-attr">Method</span>=<span class="hljs-string">"urn:oasis:names:tc:SAML:2.0:cm:bearer"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SubjectConfirmationData</span> <span class="hljs-attr">NotOnOrAfter</span>=<span class="hljs-string">"2022-03-01T12:40:00Z"</span> <span class="hljs-attr">Recipient</span>=<span class="hljs-string">"https://serviceprovider.com"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">SubjectConfirmation</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Subject</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Conditions</span> <span class="hljs-attr">NotBefore</span>=<span class="hljs-string">"2022-03-01T12:34:56Z"</span> <span class="hljs-attr">NotOnOrAfter</span>=<span class="hljs-string">"2022-03-01T12:37:56Z"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">AudienceRestriction</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Audience</span>&gt;</span>https://serviceprovider.com<span class="hljs-tag">&lt;/<span class="hljs-name">Audience</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">AudienceRestriction</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Conditions</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">AttributeStatement</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Attribute</span> <span class="hljs-attr">Name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">NameFormat</span>=<span class="hljs-string">"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AttributeValue</span>&gt;</span>john.doe@example.com<span class="hljs-tag">&lt;/<span class="hljs-name">AttributeValue</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Attribute</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Attribute</span> <span class="hljs-attr">Name</span>=<span class="hljs-string">"role"</span> <span class="hljs-attr">NameFormat</span>=<span class="hljs-string">"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AttributeValue</span>&gt;</span>User<span class="hljs-tag">&lt;/<span class="hljs-name">AttributeValue</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Attribute</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">AttributeStatement</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">AuthnStatement</span> <span class="hljs-attr">AuthnInstant</span>=<span class="hljs-string">"2022-03-01T12:34:56Z"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">AuthnContext</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AuthnContextClassRef</span>&gt;</span>urn:oasis:names:tc:SAML:2.0:ac:classes:Password<span class="hljs-tag">&lt;/<span class="hljs-name">AuthnContextClassRef</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">AuthnContext</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">AuthnStatement</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Assertion</span>&gt;</span>
```
</code></pre>
<p>In the example above, the creator of the token is <code>https://identityprovider.com</code> . The token is for the application ( = resource server ) called <code>https://serviceprovider.com</code>.</p>
<p>The tags <code>Issuer</code> and <code>Subject</code>, together with the attributes <code>email</code> and <code>role</code> are claims.</p>
<h3 id="heading-opaque-token">Opaque Token</h3>
<p>An opaque token is a token that is not self-contained. That means the token does not contain readable information. I need the IDP server to know what claims this token represents. An opaque token is typically a long and random string with no useful information embedded within the token itself.</p>
<p>Here's an example of an opaque token:</p>
<pre><code class="lang-xml">JP67LLI73Y2DF3428IYV888PZFGTXZVH5H9S
</code></pre>
<p>In this example, due to the nature of an opaque token, there are no claims defined. To have that information, I need to make a call to an introspective endpoint.</p>
<h2 id="heading-tokens-purposes">Tokens purposes</h2>
<p>OAuth2 has introduced the access_token and OpenIDConnect has introduced an id_token. The OpenIDConnect protocol is built on top of the OAuth2 protocol. When there is an OpenIDConnect server involved, the server can send an <code>access_token</code> and an <code>id_token</code>. <a target="_blank" href="https://auth0.com/blog/id-token-access-token-what-is-the-difference/">It is important to know when to use what type of token</a>. Most of the time but not always, an <code>access_token</code> can be decoded and the claims can be extracted. An id_token can always be decoded. An ID Token is always a JWT.</p>
<p>What if an <code>access_token</code> is an opaque token? The Oauth2 protocol defines an introspection endpoint. That allows the resource server to retrieve claims based on the supplied token. This is more secure. Everyone can decode a JWT token. It is not advisable to send over sensitive data using a JWT token.</p>
<h3 id="heading-id-token">Id Token</h3>
<p>An ID token contains specific information about the user and is for authentication/authorization purposes.</p>
<p>E.g. Upon logging into the web application, the user is redirected to the identity provider for authentication (e.g. Google/Auth0/Microsoft). Once authenticated, the IdP generates an ID token, such as a JWT, containing the user's ID, name (e.g., John Doe), and email address (e.g., <a target="_blank" href="mailto:john.doe@example.com">john.doe@example.com</a>). The web application receives and validates the ID token. This means that we consider the user's identity is verified.</p>
<h3 id="heading-access-token">Access Token</h3>
<p>An access token is primarily used to access protected resources. resources delivered by our resource server ( = application ). When the request has a valid <code>access_token</code> defined in the header, the application ( resource server) allows the request to be processed further in the pipeline.</p>
<p>E.g. After the user has successfully authenticated themselves and obtained the ID token, they want to place an order, which requires proper authorization. It is not because the application knows who you are, that you are allowed to place an order! The client application requests an access token from the identity provider. The identity provider verifies the user's credentials and checks their permissions. When the Idp provider can validate that the user may place an order, the Idp will issue an access token. What also can be, is that the IDP server will provide a token, but without mentioning the access_rights. The resource needs to be sure that all needed claims are there and valid, so that the user may place an order.</p>
<h1 id="heading-middleware-with-tokens-and-claims">Middleware with Tokens and Claims</h1>
<p>From here on, I will focus only on the JWT tokens and the OAuth2 and OpenIDConnect protocols.</p>
<h2 id="heading-overview">Overview</h2>
<p>To understand how claims are processed within an ASP.NET Core application, let's take a helicopter overview of the journey of an HTTP request. Read more about Middleware: <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-7.0">Core Middleware | Microsoft Learn</a></p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNq9VT1v2zAQ_SsHTi3gAC3aSYMBo04RDymM2kYXLSx5jolQpEqe4qRB_nuPkg3rw1bdpZxI6fHd3XtH8lUor1FkIuKvCp3CuZEPQRa5Ax6lDGSUKaUj2EQMw68_UNIOw1cfUMlIX7yj4K09B51VjHS8lGS8uzdaW9zLgEPk2j-iWySmWKJK6PNsPpjffyW7IypTWvhM-YEnlXIznV7MPYO79XoJ35MkkZo9F8FMdKky5pGO512mS-hRottnClIRLOZASR1gYpgphTE2HxruNKQlWJkHJ6kKyNG0Sb7C2hQIixgrDPDNEzxJa_Rp12hmnFotWsaVMKuDjWthUUPAWHoXEd59_vAx0Xd-vz-FQcug2t8IGlPvabBeSWtfrsxlOm05msGK2BFQVpoignF1mrAMxiX7bS_wnik7qoEvJVtzdehhZ2ZHcw-EZti2bWMWrtZ93bXsPxpw1GIYfFjbzWhLHjIJaPEpHbTGg14kp_NWnfXyCpkvHO4Mlhi2PhQg2wBQO1SPsXsCNu6IwTNdfoY8FduT-MTQ0fcT8C3wkzei63f27N9jjtxCy-AVcvC9oV33DjmOsVtphHjuIVK13V5L1pKmkaFnqZiIAkMhjeaX5DX9zAVTFZiLjKcat7KylIvcvTGUZfWrF6dERqHCiahKzU16eHhEtpWs5ESgNny075vXqX6k3v4AVJNIQw"><img src="https://mermaid.ink/img/pako:eNq9VT1v2zAQ_SsHTi3gAC3aSYMBo04RDymM2kYXLSx5jolQpEqe4qRB_nuPkg3rw1bdpZxI6fHd3XtH8lUor1FkIuKvCp3CuZEPQRa5Ax6lDGSUKaUj2EQMw68_UNIOw1cfUMlIX7yj4K09B51VjHS8lGS8uzdaW9zLgEPk2j-iWySmWKJK6PNsPpjffyW7IypTWvhM-YEnlXIznV7MPYO79XoJ35MkkZo9F8FMdKky5pGO512mS-hRottnClIRLOZASR1gYpgphTE2HxruNKQlWJkHJ6kKyNG0Sb7C2hQIixgrDPDNEzxJa_Rp12hmnFotWsaVMKuDjWthUUPAWHoXEd59_vAx0Xd-vz-FQcug2t8IGlPvabBeSWtfrsxlOm05msGK2BFQVpoignF1mrAMxiX7bS_wnik7qoEvJVtzdehhZ2ZHcw-EZti2bWMWrtZ93bXsPxpw1GIYfFjbzWhLHjIJaPEpHbTGg14kp_NWnfXyCpkvHO4Mlhi2PhQg2wBQO1SPsXsCNu6IwTNdfoY8FduT-MTQ0fcT8C3wkzei63f27N9jjtxCy-AVcvC9oV33DjmOsVtphHjuIVK13V5L1pKmkaFnqZiIAkMhjeaX5DX9zAVTFZiLjKcat7KylIvcvTGUZfWrF6dERqHCiahKzU16eHhEtpWs5ESgNny075vXqX6k3v4AVJNIQw?type=png" alt /></a></p>
<p>Imagine a scenario where you have a <code>WeatherForecastController</code> in your application. Upon receiving an HTTP request, the middleware pipeline kicks in and performs tasks, such as authentication and authorization. The middleware responsible for handling authentication will extract and validate the ID token and access token from the request's headers or cookies.</p>
<p>If the access token is opaque, meaning it cannot be decoded locally, the authentication middleware will need to communicate with the token introspection endpoint provided by the OpenID Connect provider to retrieve relevant claims.</p>
<p>Once the tokens have been validated and decoded, the claims are extracted and stored in the HttpContext's claims collection. These claims are then available throughout the request lifecycle.</p>
<p>It's important to note that if e.g. the audience, issuer, and time validity of the tokens don't match the expected values, then the middleware will discard the tokens. The action of the controller will not be called!</p>
<h2 id="heading-how-to-manipulate-the-claims-mapping-process">How to manipulate the Claims mapping process?</h2>
<p>In some cases, I want to filter or map the claims received from the tokens to fit your domain-specific requirements or align with a different naming convention. <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core provides a mechanism to achieve this.</p>
<h3 id="heading-oauth2">Oauth2</h3>
<p>Asp.net core does a lot for us. It is all about using the method <code>AddAuthentication</code> and <code>AddJwtBearer</code> when we just want to work with the OAuth2 protocol. Essentially it comes down to the following code.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">//Program.cs</span>

<span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =&gt;
        {
            <span class="hljs-comment">//Ensuring the token comes from the IDP we expect!</span>
            options.Authority = <span class="hljs-string">"https://identityprovider.com"</span>;
            <span class="hljs-comment">//Ensure the token we want to process is the one that is for us</span>
            options.Audience = <span class="hljs-string">"https://api.myapp.com"</span>;
            options.TokenValidationParameters = <span class="hljs-keyword">new</span> TokenValidationParameters
            {
                ValidateIssuer = <span class="hljs-literal">true</span>,
                ValidateAudience = <span class="hljs-literal">true</span>
                <span class="hljs-comment">//...Other settings for validation of the token</span>
            };
            Events = <span class="hljs-keyword">new</span> JwtBearerEvents
            {
                OnTokenValidated = <span class="hljs-keyword">async</span> ctx =&gt;
                {
                    <span class="hljs-keyword">var</span> claims = <span class="hljs-keyword">new</span> List&lt;Claim&gt;
                    {
                        <span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"ExtraClaim"</span>, <span class="hljs-string">"SomeValue"</span>)
                    };
                <span class="hljs-keyword">var</span> extraIdentity = <span class="hljs-keyword">new</span> ClaimsIdentity(claims);   
                ctx.Principal.AddIdentity(extraIdentity );
                }
            }
        });
<span class="hljs-comment">//...</span>

IApp app = builder.Build();
    app.UseRouting();
    app.UseAuthentication(); <span class="hljs-comment">// Enable authentication middleware</span>
    app.UseAuthorization(); <span class="hljs-comment">// Enable authorization middleware</span>

    app.UseEndpoints(endpoints =&gt;
    {
        endpoints.MapControllers();
    });
</code></pre>
<p>Read <a target="_blank" href="https://joonasw.net/view/adding-custom-claims-aspnet-core-2">here</a> for more information.</p>
<h3 id="heading-openid-connect">OpenID connect</h3>
<p>OpenID Connect allows us to work differently. Unlike the <code>AddJwtBearer</code> method, we now have a <code>ClaimsActions</code> dictionary.</p>
<p>The <code>ClaimActions</code> dictionary is an option available when configuring the OpenID Connect authentication middleware using the <code>AddOpenIdConnect()</code> method. It allows me to customize the claim-handling behaviour of the middleware during the authentication process.</p>
<p>The <code>ClaimActions</code> dictionary provides a way to manipulate and control how the claims are mapped to the <code>ClaimsIdentity</code> in the authentication middleware. The dictionary maps the claim types to specific actions that should be performed on the claims during the mapping process. By using the <code>ClaimActions.Clear(),</code> the default mapping that Asp.net core does, will not occur.</p>
<p>Here is an example of setting up the <code>ClaimActions</code> dictionary:</p>
<pre><code class="lang-csharp">services.AddAuthentication()
    .AddOpenIdConnect(<span class="hljs-string">"OpenID"</span>, options =&gt;
    {
        <span class="hljs-comment">// Other configuration options</span>
        <span class="hljs-comment">//...</span>
        <span class="hljs-comment">//disable dotnet claimactions</span>
        options.ClaimActions.Clear(); 

        <span class="hljs-comment">//only map the claims I want!</span>
        options.ClaimActions.MapUniqueJsonKey(<span class="hljs-string">"role"</span>, <span class="hljs-string">"role"</span>);
        options.ClaimActions.MapUniqueJsonKey(<span class="hljs-string">"sub"</span>, <span class="hljs-string">"userId"</span>);
        options.ClaimActions.MapUniqueJsonKey(<span class="hljs-string">"email"</span>, <span class="hljs-string">"emailAddress"</span>);
        options.ClaimActions.MapUniqueJsonKey(<span class="hljs-string">"custom_claim"</span>, <span class="hljs-string">"customClaimName"</span>);

        <span class="hljs-comment">// Additional configuration</span>
    });
</code></pre>
<h2 id="heading-addjwtbearer-or-addopenidconnect">AddJwtBearer or AddOpenIdConnect?</h2>
<p>I can use the <code>AddOpenIdConnect</code> method instead of the <code>AddJwtBearer</code> method for validating access tokens and performing claims mapping.</p>
<p>The <code>AddJwtBearer</code> method is typically used when you have a separate authentication server that issues JWT tokens and you want to validate these tokens in my application. It is a lightweight middleware that focuses solely on token validation and does not perform any claims mapping or user information retrieval.</p>
<p>The <code>AddOpenIdConnect</code> method is used when you want to use OpenID Connect, which is an extension of OAuth 2.0 for authentication. It provides additional features like identity provider discovery, user authentication, claims-based authorization, and more. The <code>AddOpenIdConnect</code> middleware not only validates the tokens but also handles user information retrieval and claims mapping automatically.</p>
<h1 id="heading-claimstransformation">ClaimsTransformation</h1>
<p>For more advanced scenarios, I can implement a custom <code>ClaimsTransformer</code>. This allows me to intercept the claims before they are stored in the <code>HttpContext</code> and manipulate them as needed. This approach allows you to filter out unnecessary claims or transform their names to match your application's terminology.</p>
<p>In the following example, I want to parse the <code>provider</code> and <code>userid</code> from the <code>sub</code>-claim defined by the IdpProvider Auth0.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Auth0ProviderClaimsTransformation</span> : <span class="hljs-title">IClaimsTransformation</span>
{
    <span class="hljs-comment">// Regular expression pattern to parse Auth0 user ID</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> auth0UserIdPattern = <span class="hljs-string">@"^(.*)\|(.*)$"</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> Task&lt;ClaimsPrincipal&gt; <span class="hljs-title">TransformAsync</span>(<span class="hljs-params">ClaimsPrincipal principal</span>)</span>
    {
        <span class="hljs-keyword">var</span> identity = (ClaimsIdentity)principal.Identity;

        <span class="hljs-comment">// Get the sub claim (Auth0 user ID)</span>
        <span class="hljs-keyword">var</span> subClaim = identity.FindFirst(<span class="hljs-string">"sub"</span>);

        <span class="hljs-keyword">if</span> (subClaim != <span class="hljs-literal">null</span>)
        {
            <span class="hljs-comment">// Extract provider and user ID from Auth0 user ID</span>
            <span class="hljs-keyword">var</span> matches = Regex.Match(subClaim.Value, auth0UserIdPattern);
            <span class="hljs-keyword">if</span> (matches.Success)
            {
                <span class="hljs-keyword">var</span> provider = matches.Groups[<span class="hljs-number">0</span>].Value;;
                <span class="hljs-keyword">var</span> userId = matches.Groups[<span class="hljs-number">1</span>].Value;

                <span class="hljs-comment">// Add provider and userId claims</span>
                identity.AddClaim(<span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"provider"</span>, provider));
                identity.AddClaim(<span class="hljs-keyword">new</span> Claim(<span class="hljs-string">"userid"</span>, userId));
            }
        }

        <span class="hljs-keyword">return</span> Task.FromResult(principal);
    }
}
```
</code></pre>
<p>I have to register the class as a scoped service on the service collection and it works automagically.</p>
<pre><code class="lang-csharp">builder.Services.AddTransient&lt;IClaimsTransformation, Auth0ProviderClaimsTransformation &gt;();
</code></pre>
<p>More on that <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/security/authentication/claims?view=aspnetcore-7.0#extend-or-add-custom-claims-using-iclaimstransformation">here</a>.</p>
<h1 id="heading-accessing-claims-in-asphttpaspnetnet-core-6">Accessing Claims in ASP<a target="_blank" href="http://ASP.NET">.</a>NET Core 6</h1>
<p>When it comes to accessing claims in <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core 6, I have several options depending on the context in which you need to utilize them. It comes down to tracking down where to access the <code>HttpContext</code> and use the <code>User</code> property. On the <code>User</code> property, I have access to the <code>Claims</code> property.</p>
<h2 id="heading-authentication-and-authorization-middleware">Authentication and Authorization Middleware</h2>
<p>In the authentication middleware and authorization middleware, I can access claims directly from the <code>HttpContext</code>, ensuring that the necessary authentication and authorization checks are in place before proceeding.</p>
<h3 id="heading-addjwtbearer-method">AddJwtBearer method</h3>
<p>I repeat the example used above but with a focus on where I can access the claims using the <code>HttpContext</code>. Read more about JwtBearerEvents <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbearerevents?view=aspnetcore-7.0">here</a>.</p>
<pre><code class="lang-csharp">services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =&gt;
        {
            <span class="hljs-comment">// Configure JWT Bearer options</span>
            <span class="hljs-comment">// ...</span>

            options.Events = <span class="hljs-keyword">new</span> JwtBearerEvents
            {
                OnAuthenticationFailed = <span class="hljs-keyword">async</span> context =&gt;
                {
                    <span class="hljs-keyword">var</span> httpContext = context.HttpContext;
                    <span class="hljs-comment">// Access HttpContext</span>
                    <span class="hljs-comment">// ...</span>

                    <span class="hljs-keyword">await</span> Task.CompletedTask;
                },
                OnTokenValidated = <span class="hljs-keyword">async</span> context =&gt;
                {
                    <span class="hljs-keyword">var</span> httpContext = context.HttpContext;
                    <span class="hljs-comment">// Access HttpContext</span>
                    <span class="hljs-comment">// ...</span>

                    <span class="hljs-keyword">await</span> Task.CompletedTask;
                }
            };
        });
</code></pre>
<h3 id="heading-addopenidconnect-method">AddOpenIdConnect method</h3>
<p>The same way of working with the <code>AddJwtBearer</code> method applies when working with the <code>AddOpenIdConnect</code> method.</p>
<pre><code class="lang-csharp">services.AddAuthentication(options =&gt;
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =&gt;
{
    <span class="hljs-comment">// Configure OpenID Connect options</span>
    <span class="hljs-comment">// ...</span>

    options.Events = <span class="hljs-keyword">new</span> OpenIdConnectEvents
    {
        OnRedirectToIdentityProvider = <span class="hljs-keyword">async</span> context =&gt;
        {
            <span class="hljs-keyword">var</span> httpContext = context.HttpContext;
            <span class="hljs-comment">// Access HttpContext</span>
            <span class="hljs-comment">// ...</span>

            <span class="hljs-keyword">await</span> Task.CompletedTask;
        },
        OnTokenValidated = <span class="hljs-keyword">async</span> context =&gt;
        {
            <span class="hljs-keyword">var</span> httpContext = context.HttpContext;
            <span class="hljs-comment">// Access HttpContext</span>
            <span class="hljs-comment">// ...</span>

            <span class="hljs-keyword">await</span> Task.CompletedTask;
        }
    };
});
</code></pre>
<h2 id="heading-controller">Controller</h2>
<p>When working in a controller action or service layer, it is as easy to access the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontext?view=aspnetcore-7.0">HttpContext</a>.User property.</p>
<p>Why is it easy? Let me copy and paste the following code from this <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimsprincipal?view=net-7.0">page</a> from Microsoft Learn.</p>
<pre><code class="lang-csharp">ClaimsPrincipal principal = HttpContext.User <span class="hljs-keyword">as</span> ClaimsPrincipal;  
<span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> != principal)  
{  
   <span class="hljs-keyword">foreach</span> (Claim claim <span class="hljs-keyword">in</span> principal.Claims)  
   {  
      Console.WriteLine(<span class="hljs-string">"CLAIM TYPE: "</span> + claim.Type + <span class="hljs-string">"; CLAIM VALUE: "</span> + claim.Value + <span class="hljs-string">"&lt;/br&gt;"</span>);  
   }  
}
</code></pre>
<p>How would I access it in a controller then? Below you find some code that shows the access to the claim, using the HttpContext.User property. Read <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-7.0">here</a> for more information.</p>
<pre><code class="lang-csharp">  [<span class="hljs-meta">ApiController</span>]
    [<span class="hljs-meta">Route(<span class="hljs-meta-string">"[controller]"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WeatherForecastController</span> : <span class="hljs-title">ControllerBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span>[] Summaries = <span class="hljs-keyword">new</span>[]
        {
            <span class="hljs-string">"Freezing"</span>, <span class="hljs-string">"Bracing"</span>, <span class="hljs-string">"Chilly"</span>, <span class="hljs-string">"Cool"</span>, <span class="hljs-string">"Mild"</span>, <span class="hljs-string">"Warm"</span>, <span class="hljs-string">"Balmy"</span>, <span class="hljs-string">"Hot"</span>, <span class="hljs-string">"Sweltering"</span>, <span class="hljs-string">"Scorching"</span>
        };

        [<span class="hljs-meta">HttpGet</span>]
        [<span class="hljs-meta">Authorize</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IEnumerable&lt;WeatherForecast&gt; <span class="hljs-title">Get</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">var</span> email = HttpContext.User.FindFirstValue(ClaimTypes.Email);

            <span class="hljs-keyword">if</span> (email == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"Email claim not found."</span>);
            }
</code></pre>
<p>I strongly recommend passing the claims as parameters or including them as part of a Data Transfer Object (DTO) when using a service in your controller. Do not use the <code>IHttpContextAccessor</code> in your domain or business logic layer. This ensures loose coupling between the service layer and the <code>HttpContext</code>. This allows for better testability and maintainability.</p>
<p>From my experience, all the tokens from the <code>access_token</code> and <code>id_token</code> are available. According to ChatGPT, the <code>id_token</code> should have precedence over the <code>access_token</code> when a claim is defined in both tokens but have a different value. I want to validate what it said, however, I do not find it in the sources on GitHub.</p>
<h1 id="heading-other-sources">Other sources</h1>
<p>I do like to mention the following sources that I may not explicitly mention in a link:</p>
<p><a target="_blank" href="https://damienbod.com/2019/11/01/user-claims-in-asp-net-core-using-openid-connect-authentication/">User claims in</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://damienbod.com/2019/11/01/user-claims-in-asp-net-core-using-openid-connect-authentication/">Core using OpenID Connect Authentication | Software Engineering (</a><a target="_blank" href="http://damienbod.com">damienbod.com</a><a target="_blank" href="https://damienbod.com/2019/11/01/user-claims-in-asp-net-core-using-openid-connect-authentication/">)</a></p>
<p><a target="_blank" href="https://kevinchalet.com/2022/02/25/introducing-the-openiddict-client/">Introducing the OpenIddict client | Kévin Chalet's blog (</a><a target="_blank" href="http://kevinchalet.com">kevinchalet.com</a><a target="_blank" href="https://kevinchalet.com/2022/02/25/introducing-the-openiddict-client/">)</a></p>
<p><a target="_blank" href="https://joonasw.net/view/adding-custom-claims-aspnet-core-2">Adding custom claims to a user during authentication with</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://joonasw.net/view/adding-custom-claims-aspnet-core-2">Core 2.0 - Joonas W's blog</a></p>
<p><a target="_blank" href="https://github.com/dotnet/aspnetcore/tree/main/src/Components">aspnetcore/src/Components at main · dotnet/aspnetcore · GitHub</a></p>
<h1 id="heading-outro">Outro</h1>
<p>Claims play a good role in an application's authentication and authorization process and make the whole token process abstract for a dot net developer. Claims encapsulate user-specific information and are stored and transferred through tokens.</p>
<p>By understanding the tokens and claims, navigating the middleware pipeline, customizing claims, and accessing them securely, I can unlock claims-based authentication and authorization.</p>
<p>Shame about my research on the <code>id_token</code> and <code>access_token</code>. But maybe that is something for a later post.</p>
<p>Let us connect! What did you find about this post? What would like to read more about or less?</p>
]]></content:encoded></item><item><title><![CDATA[Understanding the HttpClient: An Overview with code]]></title><description><![CDATA[Previously on...
Change is inevitable! I often find myself diving into new codebases and projects, each with its own set of challenges. Previously I explored the IConfiguration of DotNet with references to Net Framework. I will explore now a scenario...]]></description><link>https://dotnet.kriebbels.me/understanding-the-httpclient-an-overview-with-code</link><guid isPermaLink="true">https://dotnet.kriebbels.me/understanding-the-httpclient-an-overview-with-code</guid><category><![CDATA[httpclient]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[polly]]></category><category><![CDATA[connection pooling]]></category><category><![CDATA[dependency injection]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 02 Jul 2023 15:50:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688288425629/bc174b99-36ae-41ac-99f9-55de140d3f57.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>Change is inevitable! I often find myself diving into new codebases and projects, each with its own set of challenges. <a target="_blank" href="https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development">Previously I explored the IConfiguration of DotNet with references to Net Framework</a>. I will explore now a scenario that I am tasked with modernizing an application's <code>HttpClient</code> usage.</p>
<h1 id="heading-context">Context</h1>
<p>I arrive at the customer's site, ready to dive into the codebase. As I explore the application, I notice that the <code>HttpClient</code> usage is outdated and relies on manual and repetitive configuration. Each request is created and managed individually, with setting <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.baseaddress?view=net-7.0"><code>BaseUri</code></a>, <a target="_blank" href="https://www.oauth.com/oauth2-servers/making-authenticated-requests/"><code>OAuth2</code> Headers</a> and <a target="_blank" href="https://learn.microsoft.com/en-us/azure/api-management/api-management-subscriptions"><code>APIM</code> Subscription keys</a> and disposing of the <code>HttpClient</code>. That repetitiveness leads to code duplication. Manual disposing of the HTTP client can lead to performance issues.</p>
<p>However that the codebase is in DotNet 6, why are developers still using the same way of working as in .Net Framework?</p>
<p>There are numerous reasons. Some people are working with .NET Framework for a long time! While the syntax is the same, DotNet is built from the ground up. Working with the same syntax gives a false sense of familiarity.</p>
<p>Another possibility is that developers may not be fully aware of the benefits and advantages of using HttpClient how it is intended to use.</p>
<p>Code sometimes seems just to simple too, which can feel like a hassle for the untrained. For simple use cases where only a few HTTP requests are made, using HttpClient with a <code>using</code> statement just seems easy to do.</p>
<p>Migrating an entire codebase to adopt a new way of working, without coaching and guidance, can be a time-consuming and resource-intensive process. Developers might prioritize other tasks and will take shortcuts, wich will lead to technical dept in the future.</p>
<h2 id="heading-problems-with-dotnet-framework-httpclient">Problems with DotNet Framework HttpClient</h2>
<p>The .Net Framework <code>HttpClient</code> had its problems. The <code>HttpClient</code> had limited control over connection management. It did not handle socket exceptions or connection failures gracefully. That leads to issues when dealing with unreliable networks or high-traffic scenarios.</p>
<p>It also has limited timeout-handling capabilities. I had to rely on workarounds or custom code to implement timeouts for HTTP requests.</p>
<p>In the old days, the <code>HttpClient</code> was not designed with dependency injection in mind. This made it challenging to mock or replace <code>HttpClient</code> instances during unit testing. It required creating a wrapper or using complex techniques to inject a mock implementation. The tightly coupled nature of <code>HttpClient</code> made it difficult to isolate and mock its behaviour.</p>
<p>The <code>HttpClient</code> had limited flexibility in handling request and response content. It lacked built-in support for <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation">content negotiation</a>, deserialization, or handling different media types.</p>
<p><a target="_blank" href="https://www.reddit.com/r/dotnet/comments/pzce7d/whats_the_deal_with_httpclient/">Creating a new instance of HttpClient for each request</a> in the .NET Framework had performance implications. It resulted in the overhead: <a target="_blank" href="https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/">DNS resolution</a> and <a target="_blank" href="https://deaddesk.top/http-client-explained-with-netstat/">TCP connections</a></p>
<h1 id="heading-dotnet-httpclient">DotNet HttpClient</h1>
<p>The HttpClient has a lot of improvements:</p>
<ul>
<li><p>in making HTTP requests:</p>
<ul>
<li><p>performance,</p>
</li>
<li><p>efficiency</p>
</li>
<li><p>flexibility</p>
</li>
</ul>
</li>
<li><p>with features:</p>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-8.0#:%7E:text=You%20can%20set%20some%20additional%20timeouts%20if%20you%20pass%20in%20a%20SocketsHttpHandler%20instance%20when%20constructing%20the%20HttpClient%20object%3A">connection pooling</a>,</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.automaticdecompression?view=net-7.0">automatic decompression</a>,</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-8.0#:%7E:text=You%20can%20set%20some%20additional%20timeouts%20if%20you%20pass%20in%20a%20SocketsHttpHandler%20instance%20when%20constructing%20the%20HttpClient%20object%3A">timeout handling</a>,</p>
</li>
<li><p><a target="_blank" href="https://www.siakabaro.com/use-http-2-with-httpclient-in-net-6-0/">HTTP/2 support</a></p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-dotnet-andamp-framework">DotNet &amp; Framework</h2>
<p>In the .NET Framework, the <code>HttpClient</code> creates HTTP requests. Behind the scenes, <code>HttpClient</code> used the <code>HttpWebRequest</code> class to perform the actual network communication. This meant that each <strong>HttpClient instance created a new underlying HttpWebRequest</strong>.</p>
<p>Let us take a look at the sequence diagram:</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNqNUj1PwzAQ_SuWJ5DaoUUdyFAJlYGFpRlYsrj2a7GU2Ma-VEJV_zsXnJIKDOIGy_b7uPP5TlJ7A1nJhLceTuPRqkNUXeMER1CRrLZBORIPIbRWK7Le_QSfiMKmtXBUxl6w2w4JUgGvEY-Izeh6lWa-Xk--ldhEKIKwLpHiQi-CCE0iHnY3i_vFTCyXd7ysVrcZHGLyGA2nYgqmgwLO5M2f0hqcNx9EiD6An4T0L6EzF-VEnxgsyT0pUTMyL9huoWGPYHoK3iUUrb_19HfNWD3zr35kEFAf3RdfzmSH2ClreIROg7qR9IoOjax4a7BXfUuNbNyZqaonX787LSuKPWayD4abP06crPaqTXwLY8nH5zyWn9N5_gBhuOrz"><img src="https://mermaid.ink/img/pako:eNqNUj1PwzAQ_SuWJ5DaoUUdyFAJlYGFpRlYsrj2a7GU2Ma-VEJV_zsXnJIKDOIGy_b7uPP5TlJ7A1nJhLceTuPRqkNUXeMER1CRrLZBORIPIbRWK7Le_QSfiMKmtXBUxl6w2w4JUgGvEY-Izeh6lWa-Xk--ldhEKIKwLpHiQi-CCE0iHnY3i_vFTCyXd7ysVrcZHGLyGA2nYgqmgwLO5M2f0hqcNx9EiD6An4T0L6EzF-VEnxgsyT0pUTMyL9huoWGPYHoK3iUUrb_19HfNWD3zr35kEFAf3RdfzmSH2ClreIROg7qR9IoOjax4a7BXfUuNbNyZqaonX787LSuKPWayD4abP06crPaqTXwLY8nH5zyWn9N5_gBhuOrz?type=png" alt /></a></p>
<p>The HttpClient has been completely reworked to address the limitations. The new <code>HttpClient</code> is a <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.socketshttphandler?view=net-7.0">cross-platform</a> implementation. It uses the new <code>HttpMessageHandler</code>. That <code>HttpMessageHandler</code> provides an efficient and performant way to make HTTP requests.</p>
<p>Let's take a look at the updated sequence diagram to understand the changes.</p>
<p><a target="_blank" href="https://mermaid.live/edit#pako:eNqVkz1PwzAQhv-K5QmkdGhRBzIUoQKCoR0a2LIczjVYSpzgXApV1f_OhbhJW7cVeEgs-7l7z_exkapIUIayws8ajcIHDamFPDaCVwmWtNIlGBLTTCP_oBL3ZZlpBaQL42NPoKiw64Z7JipbK3fo0z1yaHCCBJNkaHfYDKsKUnSnPh6hXTHd4O02drG2_geTiYspFFOLQOiJN8uiImHT96vh7TAQo9ENf8bj650v54KduTh6Z_txoUmO-U78hdOpSK86k7sWhYzEvKCjyz6y89Jz_LqEd8oRcbrE43epuVqvOu-izSr8g2znZ4H1_wzOCvtpauvBTyvMUqe19avUlbO_CMVb5YN7nca06LIWsSy_gZu_2pGu0xqs7Z1TlGuwwYGzBSps0nCe3IvSg2UgORk56ITncdMYx5I-MMdYhrxNcAl1RrGMzZZRqKmI1kbJkGyNgazLhMvvxleGS-A6BhITzbmctTP-O-rbH47PUdw"><img src="https://mermaid.ink/img/pako:eNqVkz1PwzAQhv-K5QmkdGhRBzIUoQKCoR0a2LIczjVYSpzgXApV1f_OhbhJW7cVeEgs-7l7z_exkapIUIayws8ajcIHDamFPDaCVwmWtNIlGBLTTCP_oBL3ZZlpBaQL42NPoKiw64Z7JipbK3fo0z1yaHCCBJNkaHfYDKsKUnSnPh6hXTHd4O02drG2_geTiYspFFOLQOiJN8uiImHT96vh7TAQo9ENf8bj650v54KduTh6Z_txoUmO-U78hdOpSK86k7sWhYzEvKCjyz6y89Jz_LqEd8oRcbrE43epuVqvOu-izSr8g2znZ4H1_wzOCvtpauvBTyvMUqe19avUlbO_CMVb5YN7nca06LIWsSy_gZu_2pGu0xqs7Z1TlGuwwYGzBSps0nCe3IvSg2UgORk56ITncdMYx5I-MMdYhrxNcAl1RrGMzZZRqKmI1kbJkGyNgazLhMvvxleGS-A6BhITzbmctTP-O-rbH47PUdw?type=png" alt /></a></p>
<p>In the image above, the HttpClient does not rely on the class HttpWebRequest. I The sequencediagram shows that there is a difference between setting up the Httpclient and using the <code>HttpClient</code>. The <code>HttpClient</code> uses the <a target="_blank" href="https://github.com/dotnet/runtime/blob/release/7.0/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs">HttpMessageHandler</a> to handle the http requests. There is no more overhead of creating a new instance for each request. This results in improved performance!</p>
<h2 id="heading-dotnet-httpclient-features">DotNet HttpClient Features</h2>
<p>Now that I have explored the changes in HttpClient, let's take a closer look at some of the new features and improvements.</p>
<p>The new HttpClient introduces connection pooling. This allows multiple requests to reuse the same underlying TCP connection. This significantly improves performance by reducing the overhead of establishing new connections for each request. The HttpClient handles the decompression like <a target="_blank" href="https://en.wikipedia.org/wiki/Gzip"><code>gzip</code></a> or <a target="_blank" href="https://en.wikipedia.org/wiki/Deflate"><code>deflate</code></a>! Besides connection pooling and auto decompression, the HTTP client provides better control over request timeouts. I can now set individual timeouts for different stages of the request. Those stages are:</p>
<ul>
<li><p>establishing a connection,</p>
</li>
<li><p>sending the request,</p>
</li>
<li><p>and receiving the response.</p>
</li>
</ul>
<p>This will help my application handle timeouts and prevent bottlenecks.</p>
<p>To keep up with modern standards, the HttpClient supports HTTP/2. That is the latest version of the HTTP protocol. HTTP/2 offers improved performance by allowing multiple requests to be multiplexed over a single TCP connection. This results in faster web applications. Read more about it on <a target="_blank" href="https://www.cloudflare.com/en-gb/learning/performance/http2-vs-http1.1/">Cloudflare</a>.</p>
<h1 id="heading-how-to-use-it">How to use it?</h1>
<ul>
<li><p>Create your own HttpClient or... <strong>( do not please)</strong></p>
</li>
<li><p>Use the HttpExtension methods and thus use the <code>IHttpClientFactory</code></p>
</li>
</ul>
<p><a target="_blank" href="https://stackoverflow.com/questions/18976042/httpclientfactory-create-vs-new-httpclient">The HttpClientFactory is a feature introduced in .NET Core 2.1 and continued in .NET 5/6</a>. That provides a centralized and efficient way to create and manage HttpClient instances.</p>
<p>Microsoft does lever us <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines">official guidance</a> on what to use. <code>.AddHttpClient</code> and/or the <code>HttpClientFactory</code>.</p>
<blockquote>
<p><code>HttpClient</code> instances created by <code>IHttpClientFactory</code> are intended to be <strong>short-lived</strong>.</p>
<ul>
<li><p>Recycling and recreating <code>HttpMessageHandler</code>'s when their lifetime expires is essential for <code>IHttpClientFactory</code> to ensure the handlers react to DNS changes. <code>HttpClient</code> is tied to a specific handler instance upon its creation, so new <code>HttpClient</code> instances should be requested in a timely manner to ensure the client will get the updated handler.</p>
</li>
<li><p>Disposing of such <code>HttpClient</code> instances <strong>created by the factory</strong> will not lead to socket exhaustion, as its disposal <strong>will not</strong> trigger disposal of the <code>HttpMessageHandler</code>. <code>IHttpClientFactory</code> tracks and disposes of resources used to create <code>HttpClient</code> instances, specifically the <code>HttpMessageHandler</code> instances, as soon their lifetime expires and there's no <code>HttpClient</code> using them anymore.</p>
</li>
</ul>
</blockquote>
<h3 id="heading-approaches">Approaches</h3>
<p>There are multiple ways of working with the HTTP client. I made a summary from <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management">Use the IHttpClientFactory - .NET | Microsoft Learn</a> into an overview table.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Usage</td><td>How Registered in ServiceCollection</td><td>How Consumed in Code</td><td>When to Use</td><td>Pros</td><td>Cons</td><td>Important Notes</td><td>Who is Disposing the HttpClient?</td><td>Who is Disposing the Handler?</td></tr>
</thead>
<tbody>
<tr>
<td>Basic Usage</td><td><code>services.AddHttpClient()</code></td><td><code>IHttpClientFactory.CreateClient()</code>OR<code>constructor(HttpClient httpClient)</code></td><td>Refactoring an existing app that creates HttpClient instances.</td><td>Simple</td><td>No control over the lifetime of HttpClient instances.</td><td><strong>Automatic pooling</strong> and management of HttpClientMessageHandler instances.</td><td>Disposed by the factory</td><td>Disposed by the factory</td></tr>
<tr>
<td>Named Clients</td><td><code>services.AddHttpClient("Name", ...)</code></td><td><code>IHttpClientFactory.CreateClient("Name")</code></td><td>Multiple distinct uses of HttpClient with different configurations.</td><td>Easy configuration of different clients with specific headers, base URLs, etc.</td><td>Requires manual client retrieval using the client name each time a request is made.</td><td><strong>Automatic pooling</strong> and management of HttpClientMessageHandler instances, separate <strong>for</strong> each <strong><em>named</em> client</strong>.</td><td>Disposed by the factory</td><td>Disposed by the factory</td></tr>
<tr>
<td>Typed Clients</td><td><code>services.AddHttpClient&lt;T&gt;()</code></td><td><code>HttpClientFactory&lt;T&gt;.CreateClient(...)</code>OR <code>constructor(HttpClient httpClient)</code></td><td>When consuming a specific HttpClient with typed handlers.</td><td>Strong typing and improved IntelliSense support.</td><td>Requires creating and maintaining a separate class for each typed client.</td><td><strong>Automatic pooling</strong> and management of HttpClientMessageHandler instances, separate <strong>for</strong> each <strong><em>typed</em> client</strong>.</td><td>Disposed by the factory</td><td>Disposed by the factory</td></tr>
<tr>
<td>Generated Clients</td><td><code>services.AddRefitClient&lt;T&gt;()</code></td><td><code>IServiceProvider.GetRequiredService&lt;T&gt;()</code> OR <code>constructor(T refitClient)</code></td><td>When using third-party libraries like Refit for REST APIs.</td><td>Dynamic generation of HttpClient implementations for REST APIs.</td><td>Limited control over the generated client configuration.</td><td><strong>Automatic pooling</strong> and management of HttpClientMessageHandler instances, separate <strong>for</strong> each <strong><em>generated</em> client</strong>.</td><td>Disposed by the <strong>consumer</strong></td><td>Disposed by the <strong>consumer</strong></td></tr>
</tbody>
</table>
</div><p>Using direct <code>HttpClient</code> injection involves manually configuring an instance of HttpClient with the handlers into the services. <strong>Do not use this approach.</strong></p>
<p>The <code>IHttpClientFactory</code> provides a centralized way of managing and reusing <code>HttpClient</code> instances. This approach helps address issues related to long-lived <code>HttpClient</code> instances, including DNS changes, connection pooling, and proper resource disposal. By calling the <code>AddHttpClient</code> method on the service collection, there is a <code>HttpClient</code> is ready to be injected into the services.</p>
<p>This approach is suitable for smaller or simpler projects where direct injection is sufficient. <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#">To quote Microsoft</a>:</p>
<blockquote>
<p>Lifetime management of <code>HttpClient</code> instances created by <code>IHttpClientFactory</code> is completely different from instances created manually. The strategies are to use either <strong>short-lived</strong> clients created by <code>IHttpClientFactory</code> or <strong>long-lived</strong> clients with <code>PooledConnectionLifetime</code> set up. For more information, see the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management"><strong>HttpClient lifetime management</strong></a> section and <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines"><strong>Guidelines for using HTTP clients</strong></a>.</p>
</blockquote>
<p>I need to define multiple <code>HttpClient</code> configurations to access multiple endpoints. I have to use a key that uniquely identifies a HttpClient configuration. This is done by using <code>AddHttpClient("key")</code> on the service collection.</p>
<p>To use a specific configuration of the <code>HttpClient</code>, I inject the <code>IHttpClientFactory</code> and use the key that corresponds to that configuration. The <code>HttpClient</code> should be disposed of when using the IHttpClientFactory.</p>
<p>Instead of working with named <code>HttpClient</code>'s creations on the <code>IHttpClientFactory</code>, Typed clients are a convenient and type-safe way to work with. Register it with the dependency injection container using the <code>AddHttpClient&lt;IServiceInterface,MyHttpClientConsumerService&gt;</code> method. The service is registered in the container as <strong>transient</strong>! I do not need to register it again! Typed clients make HTTP calls more structured and maintainable. It is important that the <code>HttpClient</code> that is not injected into a singleton service! <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#avoid-typed-clients-in-singleton-services">I quote Microsoft on this one:</a></p>
<blockquote>
<p>Typed clients are expected to be <strong>short-lived</strong> in the same sense as <code>HttpClient</code> instances created by <code>IHttpClientFactory</code> (for more information, see <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management"><code>HttpClient</code> lifetime management</a>). As soon as a typed client instance is created, <code>IHttpClientFactory</code> has no control over it. If a typed client instance is captured in a singleton, it may prevent it from reacting to DNS changes, defeating one of the purposes of <code>IHttpClientFactory</code>.</p>
</blockquote>
<p>When using <strong>typed</strong> clients, I have two options for creating them. The default approach uses the <code>IHttpClientFactory</code> behind the scenes, using <code>.AddHttpClient&lt;,&gt;</code> method. The <code>HttpClient</code> will be created and managed by the DI container. It simplifies the creation of <code>HttpClient</code> instances.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Define the typed client interface</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IMyTypedClient</span>
{
    <span class="hljs-function">Task&lt;MyModel&gt; <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>)</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyTypedClient</span>
{
    HttpClient _httpClient...
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyTypedClient</span>(<span class="hljs-params">HttpClient httpClient</span>)</span>
    {
        _httpClient = httpClient;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;MyModel&gt; <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> _httpClient.GetAsync(...)
    }
}
<span class="hljs-comment">// Register the typed client with the default IHttpClientFactory</span>
services.AddHttpClient&lt;IMyTypedClient, MyTypedClient&gt;();

<span class="hljs-comment">// Inject the typed client into a class or controller</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IMyTypedClient _myTypedClient;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyClass</span>(<span class="hljs-params">IMyTypedClient myTypedClient</span>)</span>
{
    _myTypedClient = myTypedClient;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">await</span> _myTypedClient.GetData();
</code></pre>
<p>I also can use the <strong>Named</strong> <code>HttpClient</code> instances. Named clients are useful for more advanced scenarios where I need fine-grained control over <code>HttpClient</code> settings. However, I need to use the <code>IHttpClientFactory</code> to create my <strong>Named</strong> <code>HttpClient</code> instance.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Register a named HttpClient instance with additional configurations</span>
services.AddHttpClient(<span class="hljs-string">"MyNamedClient"</span>, client =&gt;
{
    client.BaseAddress = <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">"https://api.example.com"</span>);
    <span class="hljs-comment">// Other HttpClient configurations</span>
});

<span class="hljs-comment">// Inject the named client into a class or controller</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> HttpClient _myNamedClient;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyClass</span>(<span class="hljs-params">IHttpClientFactory httpClientFactory</span>)</span>
{
    _myNamedClient = httpClientFactory.Create(<span class="hljs-string">"MyNamedClient"</span>);
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">await</span> _myNamedClient.GetAsync(<span class="hljs-string">".../Data"</span>);
</code></pre>
<h1 id="heading-pollyhttpsgithubcomapp-vnextpolly-integrates"><a target="_blank" href="https://github.com/App-vNext/Polly">Polly</a> integrates!</h1>
<blockquote>
<p>Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, Rate-limiting and Fallback in a fluent and thread-safe manner.</p>
</blockquote>
<p>Polly can be used with the <code>IHttpClientFactory</code>. The integration allows me to apply policies to the <code>HttpClient</code> instances created by the <code>IHttpClientFactory</code>.</p>
<pre><code class="lang-csharp">services.AddHttpClient(<span class="hljs-string">"MyClient"</span>)
    .AddTransientHttpErrorPolicy(policy =&gt; policy.RetryAsync(<span class="hljs-number">3</span>))
    .AddTransientHttpErrorPolicy(policy =&gt; policy.CircuitBreakerAsync(<span class="hljs-number">5</span>, TimeSpan.FromSeconds(<span class="hljs-number">30</span>)));
</code></pre>
<p>In this example, two Polly policies are applied to the <code>HttpClient</code> with the name "MyClient":</p>
<ul>
<li><p><code>RetryAsync</code>: Retry failed requests up to 3 times.</p>
</li>
<li><p><code>CircuitBreakerAsync</code>: Break the circuit if 5 consecutive requests fail within a 30-second window.</p>
</li>
</ul>
<p>It is not needed to have try-catch scenarios in the code itself to react on e.g. HTTP status codes and invent the <a target="_blank" href="https://en.wikipedia.org/wiki/Exponential_backoff">backoff interval</a>.</p>
<p>Explore the Polly documentation for more advanced usage and customization options!</p>
<p>Remember to configure Polly policies according to your application's specific needs! There is a potential impact on the underlying services and resources being called. E.g. if a request is retried multiple times, it can result in duplicate data creation, unintended modifications, or unintended deletion of resources.</p>
<h1 id="heading-mocking-dotnet-httpclient">Mocking DotNet HttpClient</h1>
<p>Because the <code>HttpClient</code> is just a facade, I do not mock the <code>HttpClient</code>, but rather the <code>HttpMessageHandler</code> that the <code>HttpClient</code> uses. By using a mocked <code>HttpMessageHandler</code>, I can control the behaviour of the <code>HttpClient</code>. This allows me to test my code without making actual network requests.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Create a mocked HttpMessageHandler</span>
<span class="hljs-keyword">var</span> mockHandler = <span class="hljs-keyword">new</span> Mock&lt;HttpMessageHandler&gt;();
mockHandler
    .Protected()
    .Setup&lt;Task&lt;HttpResponseMessage&gt;&gt;(
        <span class="hljs-string">"SendAsync"</span>,
        ItExpr.IsAny&lt;HttpRequestMessage&gt;(),
        ItExpr.IsAny&lt;CancellationToken&gt;()
    )
    .ReturnsAsync(<span class="hljs-keyword">new</span> HttpResponseMessage(HttpStatusCode.OK));

<span class="hljs-keyword">var</span> httpClient = <span class="hljs-keyword">new</span> HttpClient(mockHandler.Object);

<span class="hljs-comment">// Use the HttpClient in your unit tests</span>
<span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> httpClient.GetAsync(<span class="hljs-string">"https://api.example.com/users"</span>);

<span class="hljs-comment">// Assert the expected behavior</span>
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
</code></pre>
<p>In the code above, I use a mocked <code>HttpMessageHandler</code>. Notice that I do not mock the <code>HttpClient</code>. The <code>HttpClient</code> is just a facade. The actual work happens with the <code>HttpMessageHandler</code><strong>s.</strong></p>
<p>When I want to test more integrated with multiple classes, I override my registrations in my service collection. This enables me to mock the <code>HttpClient</code> and control its behaviour in the grand scheme of things. The <code>HttpClient</code>'s <code>HttpMessageHandler</code> can be replaced with a mocked version without modifying the code under test.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Create a mocked HttpMessageHandler</span>
<span class="hljs-keyword">var</span> mockHandler = <span class="hljs-keyword">new</span> Mock&lt;HttpMessageHandler&gt;();
mockHandler
    .Protected()
    .Setup&lt;Task&lt;HttpResponseMessage&gt;&gt;(
        <span class="hljs-string">"SendAsync"</span>,
        ItExpr.IsAny&lt;HttpRequestMessage&gt;(),
        ItExpr.IsAny&lt;CancellationToken&gt;()
    )
    .ReturnsAsync(<span class="hljs-keyword">new</span> HttpResponseMessage(HttpStatusCode.OK));

<span class="hljs-comment">// Create a new ServiceCollection</span>
<span class="hljs-keyword">var</span> services = <span class="hljs-keyword">new</span> ServiceCollection();

<span class="hljs-comment">// Register the HttpClient with the mocked HttpMessageHandler</span>
services.AddHttpClient(<span class="hljs-string">"MyHttpClient"</span>)
    .ConfigurePrimaryHttpMessageHandler(() =&gt; mockHandler.Object);

<span class="hljs-comment">// Build the ServiceProvider</span>
<span class="hljs-keyword">var</span> serviceProvider = services.BuildServiceProvider();

<span class="hljs-comment">// Resolve the HttpClient from the ServiceProvider</span>
<span class="hljs-keyword">var</span> httpClient = serviceProvider.GetRequiredService&lt;IHttpClientFactory&gt;()
    .CreateClient(<span class="hljs-string">"MyHttpClient"</span>);

<span class="hljs-comment">// Use the HttpClient in your unit tests</span>
<span class="hljs-keyword">var</span> response = <span class="hljs-keyword">await</span> httpClient.GetAsync(<span class="hljs-string">"https://api.example.com/users"</span>);

<span class="hljs-comment">// Assert the expected behavior</span>
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
</code></pre>
<p>In the above example, I create a mocked <code>HttpMessageHandler</code> using <code>Moq</code>. The test is set up to return an HTTP 200 OK response for any request. I register the <code>HttpClient</code> with the mocked <code>HttpMessageHandler</code> in the ServiceCollection. I do that by using the <code>AddHttpClient</code> method and configure the primary <code>HttpMessageHandler</code>. Finally, I resolve the <code>HttpClient</code> from the <code>ServiceProvider</code> and use it in the unit test.</p>
<h1 id="heading-outro">Outro</h1>
<p>I did have some difficulties writing this post. There is enough documentation to find, but all the different ways of creating an HttpClient and the lifetime of the service and instances threw me off.</p>
<p>However, I think I managed to explain what the evolution of the HttpClient went trough and how to use the HttpClient in Dotnet 6.</p>
]]></content:encoded></item><item><title><![CDATA[How to Consume Dot Net 6 Configuration in Your Services Effectively]]></title><description><![CDATA[Previously on...
In my previous blog posts, I wrote about the modularity of the configuration that Dotnet 6 offers. About sources and sections and how to register them. I mentioned how to manually build the configuration object and how to use the def...]]></description><link>https://dotnet.kriebbels.me/how-to-consume-dot-net-6-configuration-in-your-services-effectively</link><guid isPermaLink="true">https://dotnet.kriebbels.me/how-to-consume-dot-net-6-configuration-in-your-services-effectively</guid><category><![CDATA[dotnet]]></category><category><![CDATA[configuration]]></category><category><![CDATA[injection]]></category><category><![CDATA[Validation]]></category><category><![CDATA[mermaid]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 25 Jun 2023 17:46:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/4Ennrbj1svk/upload/8e9b1cf306f0e1c5a37681bcb2e1b9aa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>In my previous blog posts, <a target="_blank" href="https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development">I wrote about the modularity of the configuration that Dotnet 6 offers. About sources and sections and how to register them.</a> <a target="_blank" href="https://dotnet.kriebbels.me/dive-into-code-unleashing-the-dotnet-6-configuration-management">I mentioned how to manually build the configuration object and how to use the default sources that Dotnet 6 offers. I also mentioned security-related information: using secrets.json, AppConfiguration Service and Azure key vault.</a></p>
<h1 id="heading-context">Context</h1>
<p>When coaching individuals, I've observed that when transitioning from the DotNet Framework to Dotnet Core, people tend to instinctively want to work by what they know. That is not strange at all. In the article <a target="_blank" href="https://hbr.org/2020/08/why-do-your-employees-resist-new-tech">Why Do Your Employees Resist New Tech? (</a><a target="_blank" href="http://hbr.org">hbr.org</a><a target="_blank" href="https://hbr.org/2020/08/why-do-your-employees-resist-new-tech">)</a>" are some reasons mentioned like lack of skills, costs, complexity, and infrastructure challenges. By writing these <a target="_blank" href="https://dotnet.kriebbels.me">blog posts</a>, I want to help inspire fellow developers to embrace the new way of working and actually... show how <em>cool</em> is the stuff that Microsoft has realised! <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles">Microsoft also promotes some good techniques on how to create architectures and code.</a></p>
<p>I notice that there is no little awareness about using the strongly typed classes that represent (part of) sections and how to validate the settings on the startup of an application. A big difference in design is the possibility to monitor changes and ensure that the application reacts to those changes, without the need to reboot the application.</p>
<p>In this post, I mention how to consume configuration, and the logic behind the different ways by showing sequence diagrams made in Mermaid Live. I also show how to debug a startup error on an Azure app service when a configuration setting does not validate.</p>
<h1 id="heading-consume-iconfiguration-in-programcs">Consume IConfiguration in Program.cs</h1>
<p>I will use this way of working when setting up my services or consuming settings in the <code>Program.cs</code>. However, I suggest binding sections to objects mentioned in my <a target="_blank" href="https://dotnet.kriebbels.me/dive-into-code-unleashing-the-dotnet-6-configuration-management">previous post.</a> This ensures type safety and not working with strings.</p>
<p>To read from <code>IConfiguration</code> or <code>ConfigurationManager</code> I can use the <code>GetValue</code> method and specify the configuration key, which can be composed of multiple sections separated by colons (<code>:</code>). That colon will be there when there is a hierarchy defined. In the case of the configuration key <code>--another--secret--value</code>, I need to read <code>another--secret--value</code>. This is explained in the section above named "Prefix Dashes".</p>
<pre><code class="lang-csharp"> _config[<span class="hljs-string">"my:secret:value"</span>]
 _config.GetValue&lt;<span class="hljs-keyword">bool</span>&gt;(<span class="hljs-string">"my:secret:value"</span>)
 _config[<span class="hljs-string">"another--secret--value"</span>]
 _config.GetValue&lt;<span class="hljs-keyword">bool</span>&gt;(<span class="hljs-string">"another--secret--value"</span>)
</code></pre>
<p>Another important thing to note is that when you use an <code>IConfiguration</code> object or custom binding to a class, the validation of settings will not be triggered. The validation specified by <code>ValidateOnStart</code> will be activated, as you might guess, at the start of the application. This means I cannot rely on validation because it will not be triggered before calling <code>app.Run()</code> , <code>app.Start()</code> or <code>app.StartAsync</code>. After all, I am using configuration to setup my application.</p>
<h1 id="heading-consume-ioptionsltgt-in-the-services">Consume <code>IOptions***&lt;&gt;</code> in the services</h1>
<p>I may use the <code>IConfiguration</code> and <code>ConfigurationManager</code> objects to configure my services. The idea is that I use the <code>IOptions&lt;MySettings&gt;</code> object in my services. DotNet will make the mapping between the sources and the <code>IOptions</code> objects for me. This just works nicely!</p>
<p><a target="_blank" href="https://jeff-wheeler.com/in-the-arena/"><img src="https://jeff-wheeler.com/wp-content/uploads/2021/03/gladiatormeme-300x300.jpg" alt class="image--center mx-auto" /></a></p>
<p>When you want to cringe again, at how we need to do it in Net Framework, go read this old documentation: <a target="_blank" href="https://learn.microsoft.com/en-us/previous-versions/aspnet/2tw134k3(v=vs.100)">How to: Create Custom Configuration Sections Using ConfigurationSection | Microsoft Learn</a></p>
<h3 id="heading-inject-in-a-service-ioptionsltgt-ioptionsmonitorltgt-or-ioptionssnapshot">Inject in a service <code>IOptions&lt;&gt;</code>, <code>IOptionsMonitor&lt;&gt;</code> or <code>IOptionsSnapshot</code></h3>
<p>Let me register <code>MySettings</code> object using the <code>.AddOptions</code> method.</p>
<pre><code class="lang-csharp">services.AddOptions&lt;MySettings&gt;(Configuration.GetSection(<span class="hljs-string">"MySettings"</span>));
</code></pre>
<p>In a service or any other class where I want to use the configuration, I can inject <code>IOptions&lt;MySettings&gt;</code> in the constructor:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyController</span> : <span class="hljs-title">Controller</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IOptions&lt;MySettings&gt; _mySettings;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyController</span>(<span class="hljs-params">IOptions&lt;MySettings&gt; mySettings</span>)</span>
    {
        _mySettings = mySettings;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Index</span>(<span class="hljs-params"></span>)</span>
    {

        <span class="hljs-keyword">return</span> View();
    }
}
</code></pre>
<p>That's it! Now I can use <code>MySettings</code> configuration object in my code without worrying about parsing or loading configuration data myself.</p>
<p><a target="_blank" href="https://steemit.com/fsharp/@marnee/cross-platform-development-with-net-core-and-f"><img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRms_FBBFbVwyZur20EQb01jdsM1e1EFPtBqYbiN9Uj1GhLwxhsx40gkx9krGfF65w2TCU&amp;usqp=CAU" alt="Cross-platform development with .NET Core and F# — Steemit" class="image--center mx-auto" /></a></p>
<h3 id="heading-difference-between-ioptions-ioptionssnapshot-and-ioptionsmonitor">Difference between <code>IOptions</code>, <code>IOptionsSnapshot</code> and <code>IOptionsMonitor</code></h3>
<p><code>IOptions</code> is the base interface for accessing configuration options and it is injected as a <strong>singleton service</strong> and <strong>cached for the lifetime of the application</strong>. It returns a single snapshot of the configured options at the time of its initialization.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Options;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IOptions&lt;MySettings&gt; _options;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyService</span>(<span class="hljs-params">IOptions&lt;MySettings&gt; options</span>)</span>
    {
        _options = options;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetOptionValue</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> _options.Value.MyOptionValue;
    }
}
</code></pre>
<p><code>IOptionsSnapshot</code>, on the other hand, is a variation of IOptions that <strong>updates its values dynamically as it listens for changes in the underlying configuration system</strong>. This makes it more suitable for use in <strong>long-lived scopes such as request-scope</strong> services.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Options;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IOptionsSnapshot&lt;MySettings&gt; _options;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyService</span>(<span class="hljs-params">IOptionsSnapshot&lt;MySettings&gt; options</span>)</span>
    {
        _options = options;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetOptionValue</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> _options.Value.MyOptionValue;
    }
}
</code></pre>
<p><code>IOptionsMonitor</code> is similar to <code>IOptionsSnapshot</code>, but with the <strong>added capability of allowing registration for change notifications</strong>. It is useful when I want to monitor changes to the configuration data and perform actions based on the changes.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.Extensions.Options;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span>: <span class="hljs-title">IDisposable</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IOptionsMonitor&lt;MySettings&gt; _options;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IDisposable _optionsChangeToken;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyService</span>(<span class="hljs-params">IOptionsMonitor&lt;MySettings&gt; options</span>)</span>
    {
        _options = options;
        _optionsChangeToken = _options.OnChange((newOptions) =&gt; {
            <span class="hljs-comment">// Perform actions based on the new options</span>
        });
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">GetOptionValue</span>(<span class="hljs-params"></span>)</span>
    {
        <span class="hljs-keyword">return</span> _options.CurrentValue.MyOptionValue;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Dispose</span>(<span class="hljs-params"></span>)</span>
    {
        _optionsChangeToken.Dispose();
    }
}
</code></pre>
<p>Let me illustrate the above using some real use cases.</p>
<p>Suppose I have an <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core application that uses <code>IOptions</code> to access configurations related to the database connection string, cache settings, and other application settings. Since <code>IOptions</code> is cached for the lifetime of the application, it is useful when I need to access these configuration settings multiple times throughout the lifetime of the application. The mermaid diagram below illustrates this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686924534990/fb6b851c-cb4f-4700-b314-2d56bdacf31a.png" alt class="image--center mx-auto" /></p>
<p>When I have a long-lived scoped service such as a request-scope service, I would need to use <code>IOptionsSnapshot</code>. For instance, suppose I have a request-scope service that provides caching for API responses, and I configure the cache duration using <code>IOptionsSnapshot</code>. In this case, <code>IOptionsSnapshot</code> ensures that the cache expiration time is updated in real-time as soon as the configuration value gets updated, making it more suitable for long-lived scoped services like request-scope services. The mermaid diagram below illustrates this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686925674504/b90c8421-8159-4935-b6ef-051ce4154ba8.png" alt class="image--center mx-auto" /></p>
<p>Suppose I have an application where I need to monitor changes to the configuration data and perform actions based on the changes. In this case, I would use <code>IOptionsMonitor</code>. For example, imagine that I have an email notification service in my application, and I have set the <code>MySettings</code> section in the Azure AppService AppSettings. If at some point I need to change the values of the <code>MySettings</code> section, it triggers change notifications, which the <code>IOptionsMonitor</code> listens to and subsequently performs necessary actions like reconnecting to the new server. The mermaid diagram below illustrates this and shows the difference with the IOptionSnapshot as well.</p>
<p><a target="_blank" href="https://mermaid.live/view#pako:eNq1VsFu2zAM_RXCpxZoDrsaRYCu3boATQrUaHfxRZGZRIMjeRKdISv675MtO3YsOV3bLZcY8tPjI59I-TniKsMojgz-LFFyvBFsrdk2lWB_BdMkuCiYJLgqCmCm_jv7BDNpiFn4uQ-8VnIl1hV25h5LzUgomUof-7k0QqIxd2oteIJ6JzhWO4PrZwlXBWZNyCHV7L6oophEsiLZKKoFDNYu5_sEiYRcm6kv5suWiXyhSKwErxX3BI2-O0ssW46k5HkowVbBXElBSvdFNUvHmhyDVISgdqircsdwo0giwfzpOlwYYWCpVEXRElQuTabTxovYbhN55vlRIRknsWM2nHvnKxjL_EjWaHmstIfHxWK2uPWZQ7kcsQZ2t4mNq5plOabD5MbgA1hI0QAycG-Y0-B1DIfj4ZDD8zB5JRn5Azm9cmbabhg1oYrhCXuoGt4QfFWq4eqY3qgyQZnZnmX6ieVlU7BcqQIeTbim8EvQxuvOLn7rcviEfCNqxTOtxQ5Nt9PzySf3zWoxNpN6wsRwudRT-C7yHJYIGrnaFiVZ2gyUBLR793a1ltDxBhPtl74L08o_NZ8u4E4YQgkrawDfMLnu5_nukKfsPozOyXjxh16fYukNoFvb0rw_fUA5dMiXdtNjkdmaG2iIISvROePKAULC1e9SY3Ve2uzrR1fCjrq5kibh0lyHdDXB390TbtGKb6yrxHJ__L5hSr3a4qcmdaK2SBtbFbiXTtu-Y83wX0n4_1PG2ZL1D-CHWvCj_aCRSi0DugLF9WeSg9nE2se_tqIHHL-1eqD2eh-RdLjOootoi9qGzuxH4XOFTyPa4BbTKLaPGa5YmVMapfLFQllJKtlLHsWkS7yIyroKzTekW3z5A7KhopM"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686928505792/6ffc29e8-d8c6-4fb3-80dd-9800e6cd3a4a.png" alt class="image--center mx-auto" /></a></p>
<h3 id="heading-ioptions-startupvalidation-checkup-in-azure-portal">IOptions StartupValidation Checkup in Azure Portal</h3>
<p>Remember the following line of code:</p>
<pre><code class="lang-csharp">serviceCollecton.AddOptions&lt;MyViewOnSettings&gt;(<span class="hljs-string">"mysettings"</span>).ValidateOnStart().ValdiateDataAnnotations();
</code></pre>
<p>When a service encounters validation errors during startup, it will return an HTTP 500(.xx) response. When developing locally, I can run in debug mode to identify issues. To gain insight into what's happening in the cloud, Azure provides access to the Application Event Log, where I can find startup errors caused by the validation of options.</p>
<p>In the Azure App Service page, select the Diagnose and solve problems tab, then click on the Diagnostic Tools option. Within the Diagnostic Tools tab, choose Application Event Logs to view the list of events.</p>
<p><a target="_blank" href="https://thebernardlim.com/azure-app-service-event-logs/"><img src="https://thebernardlim.com/img/posts/2022-07-03-azure-app-service-event-logs/soln1-step2.png" alt="Event Logs" /></a></p>
<p>Read more about this on the following page: <a target="_blank" href="https://thebernardlim.com/azure-app-service-event-logs/">How to view Azure App Service Event Logs? - Bernard Lim | Azure | .NET | SharePoint | M365 (</a><a target="_blank" href="http://thebernardlim.com">thebernardlim.com</a><a target="_blank" href="https://thebernardlim.com/azure-app-service-event-logs/">)</a></p>
<h1 id="heading-do-you-want-more">Do you want more?</h1>
<p>While creating this post, I accessed a lot of sources. A couple of posts stood out.</p>
<p><a target="_blank" href="https://makeameme.org/meme/give-credit-where-f897a5fa1f"><img src="https://media.makeameme.org/created/give-credit-where-f897a5fa1f.jpg" alt="Gladiator (Are You Not Entertained?) meme" class="image--center mx-auto" /></a></p>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0">Configuration in</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0">Core | Microsoft Learn</a></p>
</li>
<li><p><a target="_blank" href="https://kaylumah.nl/2021/11/29/validated-strongly-typed-ioptions.html">Validated Strongly Typed IOptions (</a><a target="_blank" href="http://kaylumah.nl">kaylumah.nl</a><a target="_blank" href="https://kaylumah.nl/2021/11/29/validated-strongly-typed-ioptions.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://andrewlock.net/tag/configuration/">Configuration (</a><a target="_blank" href="http://andrewlock.net">andrewlock.net</a><a target="_blank" href="https://andrewlock.net/tag/configuration/">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.code4it.dev/blog/ioptions-ioptionsmonitor-ioptionssnapshot/">Understanding IOptions, IOptionsMonitor, and IOptionsSnapshot in .NET 7 | Code4IT</a></p>
</li>
<li><p><a target="_blank" href="https://thebernardlim.com/azure-app-service-event-logs/">How to view Azure App Service Event Logs? - Bernard Lim | Azure | .NET | SharePoint | M365 (</a><a target="_blank" href="http://thebernardlim.com">thebernardlim.com</a><a target="_blank" href="https://thebernardlim.com/azure-app-service-event-logs/">)</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-7.0#ios">Options pattern in</a> <a target="_blank" href="http://ASP.NET">ASP.NET</a> <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-7.0#ios">Core | Microsoft Learn</a></p>
</li>
</ul>
<h1 id="heading-outro">Outro</h1>
<p>This concludes the theory about Configuration. I mentioned in my first post I will make a drawing. That is underway. I am trying out some doodling techniques on my tablet. I will post it, with a summary and links to all these blog posts, later this year. For now, it is time to write about different topics</p>
<p>Did you like this three-part series? What would you change? What information are you missing? Let us connect and engage!</p>
]]></content:encoded></item><item><title><![CDATA[Dive into Code: Unleashing the DotNet 6 Configuration Management]]></title><description><![CDATA[Previously on...
Previously, in my blog post, I discussed that Dotnet 6 Configuration allowes dynamic reloading of configuration data without application restarts and supported multiple sources such as environment variables, appsettings.json, user se...]]></description><link>https://dotnet.kriebbels.me/dive-into-code-unleashing-the-dotnet-6-configuration-management</link><guid isPermaLink="true">https://dotnet.kriebbels.me/dive-into-code-unleashing-the-dotnet-6-configuration-management</guid><category><![CDATA[dotnet]]></category><category><![CDATA[configuration]]></category><category><![CDATA[code]]></category><category><![CDATA[Azure Key Vault]]></category><category><![CDATA[configuration management]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 17 Jun 2023 13:48:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MxrkWAV6k7M/upload/060dddd166c864317113aca94ab30cfa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development">Previously, in my blog post,</a> I discussed that Dotnet 6 Configuration allowes dynamic reloading of configuration data without application restarts and supported multiple sources such as environment variables, appsettings.json, user secrets, Azure KeyVault, and command line arguments.</p>
<p>I emphasized the significance of proper configuration management and introduced concepts like layered configuration, sections, and different configuration sources like file-based storage, Azure Key Vault for sensitive data, and the Azure App Configuration service for centralized management.</p>
<p>I also mentioned the usage of the <code>secrets.json</code> file for sensitive values and gave a glimpse of upcoming topics such as configuration defaults, consuming configuration data, and debugging in Azure deployments.</p>
<h1 id="heading-context">Context</h1>
<p>By reading my previous post on Dotnet 6 Configuration, I can now tell how to map the theory on the practical side.</p>
<p>This time, the context of this post is rather short. You can read more on the how and the why in my previous post. I explained the IOptions Pattern multiple times and to help myself to give others a better understanding, I write this post.</p>
<p>To work with this code, I strongly suggest checking out a tool called <a target="_blank" href="https://www.linqpad.net/">LINQPad</a>. That is a paid tool, but it is useful to try out snippets of code, like the ones that I offer here in my posts. My go-to tool is the open-source variant of LINQPad called <a target="_blank" href="https://roslynpad.net/">RoslynPad</a>.</p>
<p>Let us dive into it.</p>
<h1 id="heading-creating-an-iconfiguration-object">Creating an <code>IConfiguration</code> object</h1>
<p>Before we continue to discuss what configurations are default loaded, it is interesting to see how I create an <code>IConfiguration</code> object.</p>
<p>The code below creates an instance of the <code>ConfigurationBuilder</code> class.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = <span class="hljs-keyword">new</span> ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile(<span class="hljs-string">"appsettings.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>)
    .AddJsonFile(<span class="hljs-string">$"appsettings.<span class="hljs-subst">{environment}</span>.json"</span>, optional: <span class="hljs-literal">true</span>, reloadOnChange: <span class="hljs-literal">true</span>)
    .AddEnvironmentVariables()
    .AddCommandLine(args);

<span class="hljs-keyword">var</span> configuration = builder.Build();
</code></pre>
<p>The <code>ConfigurationBuilder</code> instance loads an application configuration from various sources: <code>appsettings.json</code>, <code>appsettings.{environment}.json</code>, environment variables, and command-line arguments.</p>
<ul>
<li><p>The <code>SetBasePath</code> method sets the base path for configuration files to the current directory.</p>
</li>
<li><p>The <code>AddJsonFile</code> method loads the <code>appsettings.json</code> file, with the optional flag set to true (so it will not throw an exception if the file is missing), and reloadOnChange set to true (so the configuration values will be reloaded when the file changes).</p>
</li>
<li><p>The <code>AddJsonFile</code> method also loads an environment-specific <code>appsettings.{environment}.json</code> file, if it exists. The <code>{environment}</code> value is interpolated from the <code>ASPNETCORE_ENVIRONMENT</code> or <code>DOTNET_ENVIRONMENT</code> environment variable.</p>
</li>
<li><p>The <code>AddEnvironmentVariables</code> method loads any configuration values that are specified as environment variables.</p>
</li>
<li><p>The <code>AddCommandLine</code> method loads configuration values from command-line arguments.</p>
</li>
</ul>
<p>It's worth noting that the code I provide, sets up configuration manually using <code>ConfigurationBuilder</code>. However, both <code>HostBuilder</code> (for console apps) and <code>WebApplicationBuilder</code> (for <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core apps) automatically set up different configuration sources behind the scenes. I don't necessarily need to use <code>ConfigurationBuilder</code> directly in my code when using these builders.</p>
<p>Now we got a hands-on feeling of how I can do it manually, I am ready to explore what the HostBuilder already provides.</p>
<h2 id="heading-default-configuration-sources">Default configuration sources</h2>
<p>Only for a typical old-school Console Application, I still need to choose my configuration sources. When I build a web application or a backend service, Dotnet offers us predefined configuration sources and providers.</p>
<h3 id="heading-for-a-backend-service-hostbuilder">For a backend service: <code>HostBuilder</code></h3>
<p>The class <code>HostBuilder</code> automatically sets the environment to <code>Production</code>.This behaviour can be altered by setting the environment variable <code>DOTNET_ENVIRONMENT</code>. This is important to read environment-specific files e.g. <code>appsettings.&lt;dotnet_environment&gt;.json</code>.</p>
<p>The <code>HostBuilder</code> also sets the content root of the application to the base directory of the assembly.</p>
<p>The default configuration sources that the <code>HostBuilder</code> provides are in this order:</p>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0"><code>appsettings.json</code></a><code>,</code></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0"><code>appsettings.{Environment}.json</code></a>,</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-7.0">environment variables</a>.</p>
</li>
</ul>
<h3 id="heading-for-a-webapplication">For a WebApplication</h3>
<p>Like creating a backend service, when I create an <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core web application, the application is configured with preconfigured configuration sources.</p>
<p>This is achieved through the <code>WebApplicationBuilder</code>. That class extends the <code>HostBuilder</code> to provide additional web-specific features and configurations.</p>
<p>The <code>WebApplicationBuilder</code> provides a default configuration for the app in the following order, from highest to lowest priority:</p>
<ul>
<li><p>Command-line arguments,</p>
</li>
<li><p>Non-prefixed environment variables using the Non-prefixed environment variables configuration provider.</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-7.0&amp;tabs=windows">User secrets</a> when the app runs in the Development environment.</p>
</li>
<li><p><code>appsettings.{Aspnetcore_Environment}.json</code>. E.g.: <code>appsettings.Development.json</code>.</p>
</li>
<li><p><code>appsettings.json</code>.</p>
</li>
</ul>
<h3 id="heading-for-testing">For Testing</h3>
<p>Testing and files do not have a good relationship. I can work with different kinds of sources for testing purposes. There is an alternative: [the InMemoryCollection provider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.memoryconfigurationbuilderextensions.addinmemorycollection?view=dotnet-plat-ext-7.0#microsoft-extensions-configuration-memoryconfigurationbuilderextensions-addinmemorycollection(microsoft-extensions-configuration-iconfigurationbuilder-system-collections-generic-ienumerable((system-collections-generic-keyvaluepair((system-string-system-string)))))). By reusing the <code>configurationbuilder</code>, I can add one more configuration source. This allows me to add or override configuration values using the<code>:</code> syntax. Because the highest layer always wins, I can override the configuration for my (integration) tests.</p>
<p>Let us explore more on how the syntax works when consuming the configuration.</p>
<h2 id="heading-non-default-configuration-source">Non-default configuration source</h2>
<p>By default, the Azure KeyVault and the Azure AppConfiguration Service are not available. Microsoft has Nuget packages and tutorials on how to add those. More on that later.</p>
<h3 id="heading-adding-a-keyvault">Adding a Keyvault</h3>
<p>The code shows the addition of the Azure Key vault as a source to a backend service when the <code>DOTNET_ENVIRONMENT</code> environment variable equals the value <code>Production</code>. Values specified in the <code>appsettings.json</code>, <code>appsettings.Production.json</code>, and environment variables will be overwritten by the values provided by the Azure Keyvault instance.</p>
<pre><code class="lang-csharp">            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, configBuilder) =&gt;
            {
            <span class="hljs-keyword">if</span> (context.HostingEnvironment.IsProduction())
                {
                    <span class="hljs-keyword">var</span> builtConfig = configBuilder.Build();
                    <span class="hljs-keyword">var</span> vaultName = builtConfig[<span class="hljs-string">"KeyVault:Name"</span>];
                    <span class="hljs-keyword">var</span> clientId = builtConfig[<span class="hljs-string">"KeyVault:ClientId"</span>];
                    <span class="hljs-keyword">var</span> clientSecret = builtConfig[<span class="hljs-string">"KeyVault:ClientSecret"</span>];

                    configBuilder.AddAzureKeyVault(
                        <span class="hljs-string">$"https://<span class="hljs-subst">{vaultName}</span>.vault.azure.net/"</span>,
                        clientId,
                        clientSecret);
                }
            })
</code></pre>
<h3 id="heading-adding-an-app-configuration-service">Adding an App Configuration Service</h3>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/enable-dynamic-configuration-aspnet-core?tabs=core6x">In this tutorial</a>, Microsoft will provide a comprehensive guide for implementing dynamic configuration updates in an <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core app using the App Configuration provider library. The guide emphasizes the importance of setting up the app to respond to changes in the App Configuration store and provides step-by-step instructions to achieve this. From adding a sentinel key for configuration consistency to reloading data and implementing request-driven configuration refresh,they cover all the essential aspects.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> builder = WebApplication.CreateBuilder(args);

<span class="hljs-comment">// Load configuration from Azure App Configuration</span>
builder.Configuration.AddAzureAppConfiguration(options =&gt;
{
    options.Connect(connectionString)
           .Select(<span class="hljs-string">"WebApp:MySettings:*"</span>, LabelFilter.Null)
           .ConfigureRefresh(refreshOptions =&gt;
                refreshOptions.Register(<span class="hljs-string">"WebApp:AzureAppConfiguration:Sentinel"</span>, refreshAll: <span class="hljs-literal">true</span>));
});

<span class="hljs-keyword">var</span> app = builder.Build();

<span class="hljs-comment">// Use Azure App Configuration middleware for dynamic configuration refresh.</span>
app.UseAzureAppConfiguration();
</code></pre>
<h2 id="heading-iconfiguration-vs-configurationmanager">IConfiguration vs ConfigurationManager</h2>
<p>Let me show the example with the Azure KeyVault. Before DotNet 6, when configuring the Azure Key Vault provider, it is necessary to have the URL to the key vault. That is typically something I store in the app settings. However, to use the value to connect to the key vault, I have to have access to the <code>IConfiguration</code> object. Note that the application is still configured, so it can be that configuration of the application is not yet complete.</p>
<p>I recommend watching the complete example <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-5.0#use-application-id-and-x509-certificate-for-non-azure-hosted-apps">on this link</a>. Below I show the needed statements that illustrate the problem.</p>
<pre><code class="lang-csharp">    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =&gt;
        {
                <span class="hljs-keyword">var</span> builtConfig = config.Build();

                config.AddAzureKeyVault(<span class="hljs-keyword">new</span> ... builtConfig[<span class="hljs-string">"AzureKeyVault:Url"</span>] ...
            }
        })
</code></pre>
<p>To access the setting <code>AzureKeyVault:Url</code>, I need to build the partial configuration result by calling <a target="_blank" href="http://IConfigurationBuilder.Build"><code>IConfigurationBuilder.Build</code></a>. From there, the required configuration values can be retrieved and used to add the remaining configuration sources.</p>
<p>When the application is finished setting up and ready to start, the framework will call the <a target="_blank" href="http://IConfigurationBuilder.Build"><code>IConfigurationBuilder.Build</code></a> implicitly to generate the final <code>IConfigurationRoot</code> and using that for the final app configuration.</p>
<p>However, the downside of this approach is that <code>Build()</code> has to be called twice - once to build the <code>IConfigurationRoot</code> uses the first sources and then again to build the <code>IConfigurationRoot</code> uses all the sources, including the Azure Key Vault source. This can result in messiness.</p>
<p>.Net 6 solved this by introducing the <code>ConfigurationManager</code>, which acts as a <code>ConfigurationBuilder</code> and implements the IConfiguration interface. Using the <code>ConfigurationManager</code> <strong>comes at a cost tough</strong>. Use it when needed, otherwise, use the built <code>IConfiguration</code> object in the program.cs</p>
<p>Andrew Look wrote a good post on this: <a target="_blank" href="https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/">Looking inside ConfigurationManager in .NET 6 (</a><a target="_blank" href="http://andrewlock.net">andrewlock.net</a><a target="_blank" href="https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/">)</a></p>
<h1 id="heading-register-the-configuration">Register the configuration</h1>
<p>I will explain how to register the settings using the <code>AddIOptions</code> and the <code>PostConfigure&lt;&gt;</code> methods. Off course, I mention how to validate your settings using <code>DataAnnotations</code>.</p>
<p>The difference between the <code>AddIOptions</code> and the <code>Configure&lt;&gt;</code> method will be covered as well.</p>
<h2 id="heading-dependency-injection">Dependency Injection</h2>
<p>Dotnet 6 has support from the ground up to work with Dependency Inversion. To ensure that is enforced, Dotnet enforces you to work with a dependency container. I need to register all my settings and services in the IServiceCollection. When the application is run, I can inject the services that are registered into the container.</p>
<p>In my previous blog, I wrote that configuration is split into sections for easier management of the applications modules. Using the IServiceCollection and sections, I am inspired to group my configuration sections functional.</p>
<p>Below you will read how I can access those separate sections.</p>
<h2 id="heading-segregate-the-configuration-into-sections">Segregate the configuration into sections</h2>
<p>Below I show a configuration section called <code>MySettings</code> in the <code>appsettings.json</code> file.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"MySettings"</span>: {
    <span class="hljs-attr">"Username"</span>: <span class="hljs-string">"myuser"</span>,
    <span class="hljs-attr">"Password"</span>: <span class="hljs-string">"mypassword"</span>,
    <span class="hljs-attr">"MaxConnections"</span>: <span class="hljs-number">10</span>
  }
}
</code></pre>
<p>Create a sealed record to hold the configuration data. The record properties must match the names of the configuration keys.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MySettings</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Password { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> MaxConnections { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>In the code below, I use the <code>IConfiguration.GetSection()</code> method to get a reference to the configuration section, and then use the <code>Bind()</code> method to bind the configuration data to an instance of the <code>MySettings</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> section = Configuration.GetSection(<span class="hljs-string">"MySettings"</span>);
<span class="hljs-keyword">var</span> mySettings = <span class="hljs-keyword">new</span> MySettings();
section.Bind(mySettings);
</code></pre>
<p>After this code executes, the <code>mySettings</code> object will contain the values from the <code>"MySettings"</code> configuration section.</p>
<p>The <code>Bind()</code> method recursively binds nested configuration subsections to nested object classes.</p>
<p>To access that object in a class, I can opt to register it in the dependency container. However, I rather use the IOptions-pattern.</p>
<h3 id="heading-configure-a-section-with-addoptionsltgt">Configure a section with <code>.AddOptions&lt;&gt;()</code></h3>
<p>The <code>.AddOptions&lt;&gt;()</code> method combined with the <code>IOptions&lt;T&gt;</code> interface provides flexibility and features. <code>AddOptions</code> is an extension method on the <code>IServiceCollection</code> interface.</p>
<p>The <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-7.0">IOptions-patterns</a> allow me to configure individual options independently:</p>
<ul>
<li>I can register multiple options classes for the same section and combine them as needed. While I can do this, I do not have a valid use case at the moment of writing.</li>
</ul>
<pre><code class="lang-csharp">serviceCollecton.AddOptions&lt;MyViewOnSettings&gt;(<span class="hljs-string">"mysettings"</span>);
serviceCollecton.AddOptions&lt;AnotherView&gt;(<span class="hljs-string">"mysettings"</span>);
</code></pre>
<ul>
<li>Validation rules and defining default values for options are also a possibility. I use the validation to ensure that my application is started in a valid state on <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.optionsbuilderextensions.validateonstart?view=dotnet-plat-ext-7.0">startup</a>. I can achieve this by adding validation to my class by using the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.optionsbuilderdataannotationsextensions?view=dotnet-plat-ext-7.0"><code>DataAnnotations</code></a> namespace and adding validation attributes to the properties of my class.</li>
</ul>
<pre><code class="lang-csharp">serviceCollecton.AddOptions&lt;MyViewOnSettings&gt;(<span class="hljs-string">"mysettings"</span>).ValidateOnStart().ValdiateDataAnnotations();

<span class="hljs-keyword">internal</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">record</span> <span class="hljs-title">MyViewOnSettings</span>
{
    [<span class="hljs-meta">Required</span>] 
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Something {<span class="hljs-keyword">get</span>;<span class="hljs-keyword">set</span>;}
}
</code></pre>
<h3 id="heading-override-your-setting-using-postconfigureltgt">Override your setting using <code>.PostConfigure&lt;&gt;</code></h3>
<ul>
<li>I can execute post-configuration actions on the options object. That enables me dynamic modifications or custom logic based on the configured options. <a target="_blank" href="https://github.com/kriebb/MockOpenIdConnectIdpAspnetcore/blob/main/src/WeatherApp.Tests/Controllers/WeatherForecastServerSetupFixture.cs">I use this in my Integration Tests.</a> I noticed that people are putting their Validations inside the PostConfigure method. That has to be from the era before the IOptions pattern existed. Use the DataAnnotations or Use Validation-method with a custom delegate handler.</li>
</ul>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">sealed</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WeatherForecastServerSetupFixture</span> : <span class="hljs-title">WebApplicationFactory</span>&lt;<span class="hljs-title">Program</span>&gt;
{
    <span class="hljs-keyword">private</span> Func&lt;ITestOutputHelper?&gt; _testoutputhelper = () =&gt; <span class="hljs-literal">null</span>;

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureWebHost</span>(<span class="hljs-params">IWebHostBuilder builder</span>)</span>
    {
        builder.ConfigureTestServices(services =&gt;
            {

                services.PostConfigure&lt;JwtBearerOptions&gt;(JwtBearerDefaults.AuthenticationScheme,
                    options =&gt;
                    {
</code></pre>
<h2 id="heading-difference-between-configureltgt-and-addoptionsltgt">Difference between <code>.Configure&lt;&gt;</code> and <code>.AddOptions&lt;&gt;</code></h2>
<p>Behind the scenes, both <code>Configure&lt;TOptions&gt;()</code> and <code>OptionsBuilder&lt;TOptions&gt;.Configure()</code> methods end up doing the same thing by registering an instance of <code>ConfigureNamedOptions&lt;TOptions&gt;</code>.</p>
<p>The <code>OptionsBuilder&lt;TOptions&gt;.Bind()</code> method is equivalent to the <code>Configure&lt;TOptions&gt;(IConfiguration config)</code> method. While registering multiple implementations for the same service type provides a single instance of the latest registered dependency for that type, the options framework can work with an <code>IEnumerable&lt;IConfigureOptions&lt;TOptions&gt;&gt;</code> to provide all registered implementations.</p>
<p>The <code>Configure&lt;&gt;</code> method was available in an earlier version of DotNet Core. The <code>AddOptions&lt;&gt;</code> way of working came in a later version of DotNet. The <code>AddOptions&lt;&gt;</code>-method offers additional methods using the builder pattern, like <code>ValidateOnStart()</code> and <code>ValidateDataAnnotations()</code></p>
<p>Read here for more information: <a target="_blank" href="https://github.com/dotnet/extensions/issues/514">Question: AddOptions&lt;T&gt;() vs. Multiple Configure&lt;T&gt;(…) · Issue #514 · dotnet/extensions (</a><a target="_blank" href="http://github.com">github.com</a><a target="_blank" href="https://github.com/dotnet/extensions/issues/514">)</a></p>
<h1 id="heading-whats-next">What`s next?</h1>
<p>In one of my upcoming posts, I will discuss how to consume the registered configuration from the dependency container.</p>
<h1 id="heading-outro">Outro</h1>
<p>As I made progress at the beginning of my journey with .NET Core 2.1, I came to appreciate the importance of <code>IConfigurationBuilder</code>. Through this, I was able to learn how to register and inject configurations into my services, allowing seamless access to settings throughout my application. I naturally divided settings into sections and found it quite effortless to configure them using <code>.AddOptions&lt;&gt;</code>. Additionally, I discovered that <code>.PostConfigure&lt;&gt;</code> enables me to override settings as needed, making my application flexible and adaptable for my tests!</p>
<p>However, I encountered my fair share of challenges along the way. The differences between <code>.Configure&lt;&gt;</code> and <code>.AddOptions&lt;&gt;</code> took some time to understand, and I had to understand when to use the DotNet 6 <code>ConfigurationManager</code> to embrace the power of instant access to settings instead of usage of <code>IConfiguration</code> that needs to be built first...</p>
<p>I performed the all-important <code>IOptions</code> startup validation checkup, ensuring the integrity of my configurations! This checkup gave me peace of mind, protecting my application against potential misconfigurations.</p>
]]></content:encoded></item><item><title><![CDATA[Safeguard Your Private Data, Programmers: Discover Secret Scanning]]></title><description><![CDATA[Previously on...
In my previous blogs, you may have noticed my growing interest in security and privacy topics. Of course, there is my already existing passion for DevOps. However, in my latest blog post, I outlined how DotNet 6 offers possibilities ...]]></description><link>https://dotnet.kriebbels.me/safeguard-your-private-data-programmers-discover-secret-scanning</link><guid isPermaLink="true">https://dotnet.kriebbels.me/safeguard-your-private-data-programmers-discover-secret-scanning</guid><category><![CDATA[secrets]]></category><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[GitGuardian]]></category><category><![CDATA[gitleaks]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 10 Jun 2023 16:33:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/InHfUJK8GQk/upload/ccd36fb7899c4be7878110d5ac1f97ec.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>In my previous blogs, you may have noticed my growing interest in <a target="_blank" href="https://dotnet.kriebbels.me/series/security">security</a> and <a target="_blank" href="https://dotnet.kriebbels.me/series/privacy">privacy</a> topics. Of course, there is my already existing passion for <a target="_blank" href="https://dotnet.kriebbels.me/series/devops">DevOps</a>. However, in my latest blog post, I outlined how <a target="_blank" href="https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development">DotNet 6 offers possibilities to store sensitive data outside the committable configuration</a>: e.g. <code>appsettings.json</code>. In this post, I will combine all three topics and discuss possibilities for cleaning the Git history of sensitive information.</p>
<h1 id="heading-context">Context</h1>
<p><a target="_blank" href="https://blog.gitguardian.com/secrets-credentials-api-git/">Let me summarize what I read on the blogpost of GitGuardian and the storage of credentials in the git repository:</a></p>
<p>Secrets may be stored intentionally for convenience, but they can also be hidden in text files, <a target="_blank" href="https://slack.com/">Slack</a> messages, and debug application logs, or may simply be forgotten. <a target="_blank" href="https://git-scm.com/about">Git's design promotes the free distribution of code</a> and that <a target="_blank" href="https://www.csoonline.com/article/3634784/how-corporate-data-and-secrets-leak-from-github-repositories.html">makes it easy for secrets to be leaked.</a></p>
<p>Attackers can exploit those leaks to gain access to sensitive information. By this personal services can be targeted. Code reviews will not detect secrets buried in Git's history.</p>
<p>I want to give a real-world scenario where storing a token leads to data leakage, discussed in the following article: <a target="_blank" href="https://www.ekransystem.com/en/blog/real-life-examples-insider-threat-caused-breaches">7 Real-Life Data Breaches Caused by Insider Threats | Ekran System</a>. Let me take the case of <a target="_blank" href="https://slack.com/">Slack</a>.</p>
<p>In December 2022, Slack's security team detected suspicious activity on the company's GitHub account, revealing that a malicious actor had gained unauthorized access to the company's resources by stealing Slack employees' tokens.</p>
<p>The investigation of this cybersecurity incident showed the perpetrators stole Slack's private code repositories which often contain sensitive information. <a target="_blank" href="https://slack.com/intl/en-gb/blog/news/slack-security-update">Slack did not disclose the type of information stolen</a> or disclosed further information on who the vendor was or what services or products they provided. This decision may be due to several factors, such as preserving the integrity of ongoing investigations, preventing additional harm, or maintaining the confidentiality of affected parties. Publicly revealing certain details could inadvertently aid the perpetrators or heighten the risk of subsequent attacks.</p>
<h1 id="heading-protect-the-remote-git-repository">Protect the remote GIT repository</h1>
<p>These days a lot of tooling exists to help you protect your GIT repositories from containing sensitive data. I mention Windows Defender for Azure DevOps, GitLeaks for AWS/Azure and Advanced Security on Github.</p>
<h2 id="heading-windows-defender-for-azure-devops">Windows Defender for Azure DevOps</h2>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-devops-introduction">Microsoft has a product called Windows defender that offers a plugin for Azure Devops</a></p>
<p>Defender for DevOps empowers developers prioritize critical code fixes with Pull Request annotations and assign developer ownership by triggering custom workflows.</p>
<p>Enabling it is quite easy. Look at the following page to know more.</p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/defender-for-cloud/azure-devops-extension">Configure the Microsoft Security DevOps Azure DevOps extension | Microsoft Learn</a></p>
<h2 id="heading-gitleaks">GitLeaks</h2>
<p>I will not discuss the AWS part. I am Azure focussed, so that is what I discuss in this post.</p>
<p>Here you find a summary of the video</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=D3XWjOn87fs">https://www.youtube.com/watch?v=D3XWjOn87fs</a></div>
<p> </p>
<p>As a developer, I do not always have the rights or the power to change the environment to leverage an enterprise tool like Windows Defender.</p>
<p>However, there is a public repository available on GitHub called <a target="_blank" href="https://github.com/gitleaks/gitleaks">GitLeaks</a>. Let me copy and paste their definitions:</p>
<blockquote>
<p>Gitleaks is a SAST tool for <strong>detecting</strong> and <strong>preventing</strong> hardcoded secrets like passwords, api keys, and tokens in git repos. Gitleaks is an <strong>easy-to-use, all-in-one solution</strong> for detecting secrets, past or present, in your code.</p>
</blockquote>
<p><a target="_blank" href="https://dotnet.kriebbels.me/enable-developers-to-generate-safe-and-secure-code">I encourage you to read my blog post where I position SAST in the development lifecycle</a>.</p>
<p>The following blog is a good read as a <a target="_blank" href="https://www.jit.io/blog/the-developers-guide-to-using-gitleaks-to-detect-hardcoded-secrets">Developer's Guide to Using Gitleaks to Detect Hardcoded Secrets</a>.</p>
<p>That blog will discuss Gitleaks. The blog explains that the tool is <a target="_blank" href="https://www.iso.org/standard/27001">ISO-27001</a> compliant and works on public, private, remote, or local repositories.</p>
<p>Gitleaks has two main commands: detect and protect:</p>
<ul>
<li><p>The detect command scans the repository for potential vulnerabilities and generates a report with a list of potential vulnerabilities.</p>
</li>
<li><p>The protect command creates a hook to prevent commits that introduce security vulnerabilities.</p>
</li>
</ul>
<h3 id="heading-in-a-development-environment">In a development environment</h3>
<p>I can set up GitLeaks on my developer computer using <code>Docker</code>, <code>Go</code> or use <code>Make</code> to create my build. The beauty of GitLeaks is that I can set it up as a <code>precommit</code>-hook.</p>
<p><a target="_blank" href="https://dotnet.kriebbels.me/branching-etiquette">In one of my previous blog posts, I wrote about Branch Hygiene to ensure I use a good naming strategy.</a></p>
<p>After configuring my pre-commit hook, I can try to commit a client secret and the following will be the result.</p>
<pre><code class="lang-plaintext">➜ git commit -m "this commit contains a secret"
Detect hardcoded secrets.................................................Failed
</code></pre>
<h3 id="heading-in-an-azure-pipeline">In an Azure Pipeline</h3>
<p>By using GitLeaks with Azure DevOps, regularly scanning code using GitLeaks and integrating it into the development pipeline can prevent code merges with potential vulnerabilities and prevent them from moving into production, protecting organizations' valuable data, and reputations.</p>
<p>I can use <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=Foxholenl.Gitleaks">Gitleaks as a plugin on Visual Studio Marketplace</a>. When reading that page, I noticed that the author <a class="user-mention" href="https://hashnode.com/@https://github.com/JoostVoskuil/azure-devops-gitleaks/commits?author=JoostVoskuil">JoostVoskuil</a> gives credit to a colleague of mine: <a target="_blank" href="https://xpirit.com/team/jesse-houwing/">Jesse Houwing - Xebia | Xpirit</a>.</p>
<p><a target="_blank" href="https://markpatton.cloud/2020/09/26/secret-scanning-protecting-your-code-in-azure-devops/">Mark Patton gives a good view on how to use GitLeaks in Azure DevOps.</a></p>
<p>The post provides instructions for adding the task and configuration with the appropriate parameters, including the path to the repository, report output location, and thresholds for failing a build.</p>
<p>This is a good demonstration of this matter:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=aSYEHUGHRxE">https://www.youtube.com/watch?v=aSYEHUGHRxE</a></div>
<p> </p>
<h2 id="heading-github-advanced-security-secret-scanning">GitHub Advanced Security: Secret Scanning</h2>
<p>GitHub offers what they call <a target="_blank" href="https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security">Advanced security</a>. One of those features is called "<em>Secret Scanning</em>": GitHub scans every public repository for known types of secrets to avoid any misuse of accidentally committed secrets. Secret scanning searches through all Git history on all branches present in your GitHub repository for secrets. Any strings that match patterns provided by secret scanning partners, other service providers, or defined by organizations or users are reported as alerts in the Security tab of repositories.</p>
<p>The secret scanning feature offers alerts for partners that run automatically on public repositories and public <code>npm</code> packages to alert service providers about leaked secrets on <a target="_blank" href="http://GitHub.com">GitHub.com</a>. Another part of this feature is the encryption of the identified secrets using symmetric encryption during transmission and rest.</p>
<p>Secret scanning alerts for users are available for free on all public repositories. Organizations using GitHub Enterprise Cloud can enable secret scanning alerts for users on their private as well as internal repositories and public repositories for free with a license for GitHub Advanced Security. An alert is also sent to contributors who committed the secret if they haven't ignored the repository.</p>
<p>When you want to know more about GitHub AdvancedSecurity, Go visit this <a target="_blank" href="https://devopsjournal.io/blog/2023/05/23/GitHub-Advanced-Security-Azure-DevOps">blogpost</a> about Advanced Security. It is written by my <a target="_blank" href="https://xpirit.com">Xebia | Xpirit</a> college Rob Bos and he is known as an authority when it comes to Github.</p>
<h1 id="heading-how-to-manually-undo-my-mistake">How to manually undo my mistake</h1>
<p>There are multiple strategies to undo a mistake after doing a <code>git push</code>. I can opt for removing the file history or replacing text. I listed <code>filter-branch</code>, <code>filter-repo</code> and <code>BFG</code> as possible options. <a target="_blank" href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository">GitHub offers a page about what to do when you committed a secret and you want to remove it.</a></p>
<h2 id="heading-first-thing-first-retract-your-secret">First thing first: Retract your secret</h2>
<p>If I have leaked a secret and pushed it to a remote repository like GitHub or Azure DevOps, it is imperative that I consider it leaked. I should revoke it immediately.</p>
<p><a target="_blank" href="https://blog.gitguardian.com/leaking-secrets-on-github-what-to-do/">GitGuardian has a blog post on this matter</a>. <a target="_blank" href="https://www.linkedin.com/feed/update/urn:li:activity:7073337423643955200?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A7073337423643955200%2C7073382633379909632%29&amp;dashCommentUrn=urn%3Ali%3Afsd_comment%3A%287073382633379909632%2Curn%3Ali%3Aactivity%3A7073337423643955200%29">I want to give credit to Rob to bring this to my attention.</a></p>
<p>If I remove the secret from GIT's history, it may still be accessible by bad actors who may have obtained it earlier. The window of abuse should be as small as possible! I can still rewrite the history and do the cleanup, but security-wise, I need to revoke it first. GitGuardian offers a GitHub page (<a target="_blank" href="https://github.com/GitGuardian/APISecurityBestPractices/blob/master/Leak%20Mitigation%20Checklist.md?ref=blog.gitguardian.com#2-advice-specific-to-a-key">link)</a> where I can a good overview of where and what I can do to revoke a secret.  </p>
<p>Gihub offers a functionality called: "<a target="_blank" href="https://github.com/settings/security_analysis">push protection</a>". GitHub will not accept the content and will thus not leak it. <a target="_blank" href="https://learn.microsoft.com/en-us/azure/devops/repos/security/configure-github-advanced-security-features?view=azure-devops&amp;tabs=yaml">This functionality will be available on Azure DevOps as well</a>. <a target="_blank" href="https://github.com/settings/security_analysis">I can enable push protection on GitHub for your public repos for free</a>.</p>
<h2 id="heading-remove-file-history">Remove file history</h2>
<p>If I have accidentally committed and pushed an <code>appsettings.json</code> file containing a <code>ClientSecret</code> to a Git repository, it is essential to remove or revoke the <code>ClientSecret</code> immediately.</p>
<ol>
<li><p>First, remove the <code>ClientSecret</code> from the <code>appsettings.json</code> file of the local repository.</p>
</li>
<li><p>Commit the changes and push the changes to the remote Git Repository</p>
</li>
</ol>
<pre><code class="lang-csharp">git <span class="hljs-keyword">add</span> .
git commit -m <span class="hljs-string">"Removed ClientSecret from appsettings"</span>
git push
</code></pre>
<p>However, the <code>ClientSecret</code> still exists in the repository history, and it is accessible through Git commands like <a target="_blank" href="https://marketsplash.com/tutorials/git/git-log/"><code>git log</code></a> or <code>git checkout</code>.</p>
<p>To remove the <code>ClientSecret</code> from the Git repository history:</p>
<ol>
<li><p>Identify the hash of the Git commit that added the <code>appsettings.json</code> file with the <code>ClientSecret</code>. I can do this by running the <code>git log</code> command and finding the commit that added the file.</p>
</li>
<li><p>Run the following command to remove the file from the commit history:</p>
</li>
</ol>
<pre><code class="lang-csharp">git filter-branch --tree-filter <span class="hljs-string">'rm -f appsettings.json'</span> --prune-empty HEAD
</code></pre>
<p>This command will remove the file from the commit history for all branches.</p>
<ol>
<li><code>push --force</code> will overwrite the remote repository's history</li>
</ol>
<pre><code class="lang-csharp">git push --force
</code></pre>
<p>The command overwrites the existing commit history for that file. This can lead to loss of data and confusion for other team members.</p>
<h2 id="heading-replace-text">Replace text</h2>
<p>Luckily, there are other options available, such as replacing text. Read it on the site of <a target="_blank" href="https://blog.gitguardian.com/rewriting-git-history-cheatsheet/">GitGuardian</a> or read the following summary</p>
<ol>
<li><p>Download and install <code>git-filter-repo</code></p>
</li>
<li><p>Create <code>replacements.txt</code> with on the left of <code>==&gt;</code> , what I want to replace and on the right side of <code>==&gt;</code> the text that I want to replace with: <code>toreplace==&gt;replacewidth.</code> With a concrete example: <code>'123abc'==&gt;ENV[‘AUTH_TOKEN’].</code></p>
<pre><code class="lang-plaintext"> ‘eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c’==&gt;ENV[‘AUTH_TOKEN’]
</code></pre>
</li>
<li><p>Use <code>git filter-repo --replace-text ../replacements.txt --force</code> to remove selected lines of code containing sensitive information</p>
</li>
<li><p>Force Push:</p>
<ol>
<li>Use <code>git push --all --tags --force</code> for remote repositories</li>
</ol>
</li>
</ol>
<h2 id="heading-bfg-repo-cleaner">BFG Repo Cleaner</h2>
<p>There is an alternative for the <code>filter-branch</code> and <code>filter-repo</code> commands that seems quite popular.</p>
<p>The <code>BFG</code> is a simpler and faster alternative to <code>git-filter-branch</code> for cleansing unwanted data from your Git repository history, such as removing large files or sensitive information like passwords and credentials. While <code>git-filter-branch</code> is a powerful tool with capabilities beyond what <code>BFG</code> can offer. <code>BFG</code> excels in the tasks due to its speed, and simplicity.</p>
<p>The following post <a target="_blank" href="https://dev.to/toureholder/removing-sensitive-data-from-your-git-history-with-bfg-4ni4">Removing sensitive data from your Git history with BFG - DEV Community</a></p>
<p>I will give a summary on how to clean sensitive information using the BFG.</p>
<p>Use <code>--replace-text</code> to clean strings from your repo history. Each string will be rewritten as <code>"***REMOVED***"</code> by default. This is a two-step process.</p>
<ol>
<li>Create a file <code>passwords.txt</code>. Add a line for each secret that needs to be removed.</li>
</ol>
<pre><code class="lang-bash">fooPassword1
barPassword2
ey...
</code></pre>
<ol>
<li>Execute <code>bfg --replace-text</code></li>
</ol>
<p>Execute the command with a reference to passwords.txt and the repository in question, here called <code>foobar.git</code></p>
<pre><code class="lang-bash">$ bfg --replace-text passwords.txt foobar.git
</code></pre>
<h1 id="heading-outro">Outro</h1>
<p>I had initially used <code>filter-branch</code> for my <a target="_blank" href="https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development">Dotnet 6 Configuration post</a> to erase sensitive info from my history. But, the more I delved into the topic, the more I realised there's a lot more to it than meets the eye. My next move is to put my research to the test and show what commands I used by attaching some before and after screenshots to illustrate the effects.</p>
]]></content:encoded></item><item><title><![CDATA[Configuration: The Tangle of Layers, Sections and sources in .NET 6 Development]]></title><description><![CDATA[Previously on...
In my previous post, I described how I regained focus on my blogging. This time, let us focus on how we can configure our settings in the DotNet "core" world.
Context
It's not uncommon to come across projects with poorly managed conf...]]></description><link>https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development</link><guid isPermaLink="true">https://dotnet.kriebbels.me/configuration-the-tangle-of-layers-sections-and-sources-in-net-6-development</guid><category><![CDATA[configuration]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[secrets]]></category><category><![CDATA[Azure Key Vault]]></category><category><![CDATA[appsettings]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 03 Jun 2023 14:15:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685798924185/06b01a06-72ce-4d8e-96a2-903fd50282f3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/once-az-204-is-done-re-engaging-with-my-goals">In my previous post, I described how I regained focus on my blogging.</a> This time, let us focus on how we can configure our settings in the DotNet "core" world.</p>
<h1 id="heading-context">Context</h1>
<p>It's not uncommon to come across projects with poorly managed configurations. When I first started building .NET Framework applications, the configuration process seems easy. However, over time, the <code>&lt;appsettings&gt;</code> section became more chaotic. <a target="_blank" href="https://ardalis.com/custom-configuration-section-handlers/">There is a possibility to cut this up into multiple sections, but that was writing a lot of boilerplate.</a> Storing secrets in your configuration was not safe at all. <a target="_blank" href="https://matthewregis.dev/posts/encrypting-application-settings-within-app-config">While there is a way to encrypt your settings</a>, I do not know a lot of people of embracing this way of working. Developing microservices and managing all settings in multiple <code>web.config</code> ensures losing the will to live.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685799410036/1974031a-1253-4afe-8dd2-a7811b699bb1.jpeg" alt class="image--center mx-auto" /></p>
<p>The .NET Core configuration is the new cool kid around the block. It provides a more flexible, efficient, and extensible way of handling application configuration.</p>
<p>The new configuration system in .NET Core replaces the <code>app.config</code> and <code>web.config</code> files used in previous versions of DotNET. That makes it easier to configure applications across multiple environments and platforms.</p>
<p>In .NET Framework web applications, making changes to the <code>web.config</code> file would trigger the recycling of the application pool, which would cause all sessions to be lost and all user connections to be dropped. The .NET Core configuration has support for reloading configuration data dynamically without restarting the application, which is a huge benefit for applications running in production that need to be updated or configured on the fly.</p>
<p>Finally, The .NET Core Configuration Framework comes with several providers that support a wide range of sources. The system is designed to be extensible. Developers can create custom configuration providers, handlers, and parsers to support their configuration formats or sources. Because of the extensibility the framework offers, adding secure sources for the storage of sensitive data is just a breeze using the Azure KeyVault!</p>
<p>Despite how much better configuration management has gotten in .NET, I can't help but notice that many developers are still working with outdated and painful techniques. That's why I'm writing this blog post - to talk about the importance of and benefits of properly managing configuration settings in .NET applications. I want to share my knowledge about the capabilities and show my fellow developers colleagues around the world, that it's never too late to start doing things the right way.</p>
<p>In this post, I will explore the layered configuration, grouping of configuration settings and different sources.</p>
<p>Let's discuss some theoretical concepts.</p>
<h1 id="heading-layered-configuration">Layered configuration</h1>
<p>Before we try to define a configuration object in code, I want to have an understanding of how settings are defined. A common way to define my settings is to put them in the <code>appsettings.json</code> and use the Azure Keyvault. These days, on top of using the <code>appsettings.json</code>, there is an option to use the Azure <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/overview">App Configuration service</a> as well.</p>
<p>When I have multiple sources, creating a configuration object is based on the combination of those sources. Some sources could be:</p>
<ul>
<li><p>environment variables,</p>
</li>
<li><p><code>appsettings.json</code> file</p>
</li>
<li><p><code>appsettings.{env}.json</code> file</p>
</li>
<li><p>user secrets,</p>
</li>
<li><p>app configuration service</p>
</li>
<li><p>key vault,</p>
</li>
<li><p>command line arguments</p>
</li>
</ul>
<p>A configuration object can be built by a lot of sources. When asking for a configuration value, the system uses the newest value for the asked configuration key. First, it checks environment variables, then app settings, ..., and finally, command line arguments.</p>
<p><a target="_blank" href="https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/"><img src="https://andrewlock.net/content/images/2021/config_collapse.png" alt /></a></p>
<p>The above image comes from the <a target="_blank" href="https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/">site of Andrew Lock</a>.</p>
<p>When a key name already exists in other sources, the value will be overridden. I cannot remove a key's value by adding another layer. However, I can override it and set it to <code>null</code>.</p>
<p>With that understanding, let's delve into the sections.</p>
<h1 id="heading-sections">Sections</h1>
<p>In .NET Framework, configuration data is stored in the <code>App.config</code> file for console/Windows applications and in the <code>Web.config</code> file for web applications. The configuration data is stored as XML and contains settings for the application, such as database connection strings, app settings, and more.</p>
<p>While <code>App.config</code> and <code>Web.config</code> worked well in the past in that period, but it had limitations to be used now.</p>
<p>In .NET 6, sections provide a much more flexible and organized way to work with configuration data:</p>
<ul>
<li><p>Organize configuration data into <strong>logical groups</strong> instead of grouping it by type of configuration like ConnectionStrings, AppSettings,... <strong>without having to write boilerplate code.</strong></p>
</li>
<li><p>Selectively <strong>override or replace specific configuration</strong> values</p>
</li>
<li><p>Useful for large projects with <strong>different environments</strong></p>
</li>
<li><p>Add, remove, and modify configuration sections <strong>without affecting other sections</strong></p>
</li>
<li><p>Define strongly typed classes and validation <strong><em>with ease</em></strong></p>
</li>
</ul>
<h1 id="heading-sources">Sources</h1>
<p>Having covered the way configuration is layered and grouped, we can now examine the sources</p>
<h3 id="heading-store-settings-in-a-file-not-code">Store settings in a file, not code!</h3>
<p>There are a lot of different default configuration providers. The one that is used most is the <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.json.jsonconfigurationprovider?view=dotnet-plat-ext-7.0">JSON provider</a>. It loads configuration settings from e.g. <code>appsettings.json</code>. There are possibilities to use different formats like <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#ini-configuration-provider">INI</a> or <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#xml-configuration-provider">XML</a>. There are possibilities to use different types of sources: databases and REST-APIs,... T<a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/core/extensions/custom-configuration-provider">here is an option to write a custom configuration source and provider</a>, which can be useful during migration from .NET Framework to .NET 6. Another use case that I can think of is, are needed transformations to be done before consuming the values.</p>
<h3 id="heading-store-sensitive-data-in-a-vault">Store sensitive data in a vault</h3>
<p><a target="_blank" href="https://azure.microsoft.com/en-us/products/key-vault/">Azure Key Vault</a> is a critical component for securing sensitive data in cloud-based applications. It provides a centralized, highly secure storage environment for managing cryptographic keys, secrets, and certificates. Key Vault helps prevent unauthorized access, offers key management functionalities, and ensures compliance with regulations. Its integration with Azure services simplifies secure secret retrieval, making it an essential tool for protecting valuable information in the cloud.</p>
<p><strong>Dashing</strong></p>
<p>To store a setting in the key vault, use double dashes (<code>--</code>) before the value. This ensures that the value is treated as a single entity instead of being split into separate key-value pairs, as double dashes are used to separate these pairs in the configuration.</p>
<p>For example, if I had a secret that had the value <code>my--secret--value</code>, and I tried to store it without using double dashes, it would be split into three separate key-value pairs: <code>my</code>, <code>secret</code>, and <code>value</code>.</p>
<p>If we were to store this secret in a configuration file using double dashes, it would look like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"my"</span>: {
    <span class="hljs-attr">"secret"</span>: {
      <span class="hljs-attr">"value"</span>: <span class="hljs-literal">true</span>
    }
  }
}
</code></pre>
<p><strong>Prefix Dashes</strong></p>
<p>When we add double dashes before the value <code>--another--secret--value</code>, it will be saved as a single value.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"another--secret--value"</span>: <span class="hljs-literal">true</span>
}
</code></pre>
<p>This is important because it ensures that our key-value pairs are correctly interpreted and that the value we are trying to save is treated as a single value and not as a separate key-value pair.</p>
<p>Let us explore the centralization of settings of multiple services that belong logically together, to make life just a lot easier.</p>
<h2 id="heading-store-on-the-fly-needed-settings-using-a-central-service">Store on-the-fly-needed settings using a central service!</h2>
<p>The following video was helpful as it provided insight into the Azure App Configuration service. However, I will give a summary as well for the comfort of the reader.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=t6m13DxUJMc">https://www.youtube.com/watch?v=t6m13DxUJMc</a></div>
<p> </p>
<p>Azure App Configuration service makes it possible to keep the application configurations in a single location. I will be able to store settings for different environments like development, testing, and production. I can change on the fly my configuration without redeploying it.</p>
<p>To top it off, the Azure App Configuration service allows applications to retrieve configuration data from Azure Key Vault. The application does not need to have any connection anymore with the Azure Key Vault.</p>
<p>Having the configuration read by the application is as easy as adding a package. Next is to configure an additional source to the configuration. It is possible to read configuration values from Azure App Configuration before falling back to <code>appsettings.json</code>.</p>
<p>Visit the following link: <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-app-configuration-create?tabs=azure-portal">Quickstart: Create an Azure App Configuration store | Microsoft Learn</a>.</p>
<h2 id="heading-do-not-commit-sensitive-data-secretsjson">Do not commit sensitive data: <code>secrets.json</code></h2>
<p>The <code>secrets.json</code> file is used to store sensitive values. Those values could be ClientSecrets, Passwords, API keys,... <a target="_blank" href="https://www.polar.security/post/sensitive-data-exposure">That kind of information should not be committed to my code repository</a>.</p>
<p>I can manage the user secrets in Visual Studio by right-clicking on a project</p>
<p><a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-7.0&amp;tabs=windows"><img src="https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets/_static/usvs.png?view=aspnetcore-7.0" alt="Safe storage of app secrets in development in ASP.NET Core | Microsoft Learn" /></a></p>
<p><a target="_blank" href="https://www.jetbrains.com/rider/">JetBrains Rider</a> does not offer a user interface. <a target="_blank" href="https://plugins.jetbrains.com/plugin/10183--net-core-user-secrets">I need to download and install a plugin for that.</a></p>
<p>However, I like to manage it myself. The <code>secrets.json</code> is stored at the following location: <code>%APPDATA%\Microsoft\UserSecrets\&lt;user_secrets_id&gt;\secrets.json.</code> In the preceding file path, the <code>&lt;user_secrets_id&gt;</code> is mentioned. When configured, I can look into my <code>.csproj</code> file and look for the the <code>UserSecretsId</code> value. The following is an example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">TargetFramework</span>&gt;</span>net6<span class="hljs-tag">&lt;/<span class="hljs-name">TargetFramework</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">UserSecretsId</span>&gt;</span>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed<span class="hljs-tag">&lt;/<span class="hljs-name">UserSecretsId</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>
</code></pre>
<p>The content of a secrets.json looks like following json.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"my:secret:value"</span>: <span class="hljs-string">"foobar"</span>
}
</code></pre>
<p>For a web application, this will be automatically loaded and override or add the value for</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"my"</span>: {
    <span class="hljs-attr">"secret"</span>: {
      <span class="hljs-attr">"value"</span>: <span class="hljs-literal">true</span>
    }
  }
}
</code></pre>
<h1 id="heading-whats-next">What`s next?</h1>
<p>In one of my upcoming posts, I will first do a small recap with a drawing. Then I discuss the configuration defaults the <code>HostBuilder</code> class and <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core provide. I will explain how to consume configuration data in <code>Program.cs</code> using the <code>IConfiguration</code> interface and how it differs from <code>ConfigurationManager</code>. Plus, I will explore sections in my configuration using the <code>.AddOptions&lt;&gt;</code> method. Furthermore, I will demystify the difference between <code>.Configure&lt;&gt;</code> and <code>.AddOptions&lt;&gt;</code> and the difference between <code>IOptions&lt;&gt;</code>, <code>IOptionsMonitor&lt;&gt;</code>, or <code>IOptionsSnapshot&lt;&gt;</code>. Finally, I will give an insight moment on how I debug the startup validation of my configuration when deployed my service is deployed in Azure.</p>
<h1 id="heading-outro">Outro</h1>
<p>This is a new format that I am playing with. I am in doubt if I want to have multiple posts that tackle a section or use the format that I am used to when writing an article for Xprt <a target="_blank" href="https://xpirit.com/download/">Magazine</a>. <a target="_blank" href="https://www.wyliecomm.com/2022/06/blog-post-length/">I aim for a reading time of between four and thirteen minutes.</a></p>
<p>I am always happy to get feedback. Let`s engage!</p>
]]></content:encoded></item><item><title><![CDATA[Once AZ-204 is Done: Re-engaging with My Goals]]></title><description><![CDATA[Previously on...
In my previous post, I shared my journey towards obtaining the AZ-204 Azure Developer Associate certification. I discussed the challenges I faced and shared my learning strategies.
Context
After obtaining my AZ-204 certification, I d...]]></description><link>https://dotnet.kriebbels.me/once-az-204-is-done-re-engaging-with-my-goals</link><guid isPermaLink="true">https://dotnet.kriebbels.me/once-az-204-is-done-re-engaging-with-my-goals</guid><category><![CDATA[AtomicHabits]]></category><category><![CDATA[self-care]]></category><category><![CDATA[TransactionalAnalysis]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sat, 27 May 2023 18:38:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685211715231/4d5f1fce-ff70-4c16-b0fa-1075c5de1157.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>In <a target="_blank" href="https://dotnet.kriebbels.me/advancing-towards-the-az-204-certification-victories-and-hurdles">my previous post</a>, I shared my journey towards obtaining the AZ-204 Azure Developer Associate certification. I discussed the challenges I faced and shared my learning strategies.</p>
<h1 id="heading-context">Context</h1>
<p>After obtaining my AZ-204 certification, I decided to take a week-long break from blogging. Discovering the right learning strategy had been difficult for me, as trying to learn facts without what seems any context or doubt about what the questions will be like, made me anxious.</p>
<p>Taking a break meant interrupting a habit, and not resuming it after a short pause could lead to the formation of a new habit. I noticed that after a week of not blogging, I made another decision to stop blogging for another week. That process was repeated four times.</p>
<p>I felt conflicted. I had promised myself to continue blogging this year, but the process of learning and pushing myself towards the certification had reignited an old struggle. Everything seemed dull, and getting back into blogging felt challenging. My motivation had disappeared.</p>
<p>Fortunately, I had a scheduled appointment with my coach. During that session, we used <a target="_blank" href="https://www.simplypsychology.org/transactional-analysis-eric-berne.html">Transactional Analysis</a> to address the disruption I was experiencing. We found that the active state was not the <a target="_blank" href="https://www.careershodh.com/transactional-analysis-meaning-ego-states-child-ego-parent-ego-adult-ego/#2Adult_Ego_State">adult ego state</a>, but rather the <a target="_blank" href="https://www.careershodh.com/transactional-analysis-meaning-ego-states-child-ego-parent-ego-adult-ego/#D_Rebellious_Child_RC">rebellious child's ego state</a>.</p>
<p>Identifying the root cause is one thing, but altering one's state of mind requires more than just realization. <a target="_blank" href="https://dotnet.kriebbels.me/advancing-towards-the-az-204-certification-victories-and-hurdles">I devised plans to ensure that I would study for my next certification using the approach I described in my previous post</a>. I committed to refining the learning process I had employed and vowed to continue refining it. After making this promise, my state of mind shifted back to the adult ego state.</p>
<h1 id="heading-transactional-analysis">Transactional Analysis</h1>
<p>Let's start by taking a closer look at the concept of Transactional Analysis. According to <a target="_blank" href="https://en.wikipedia.org/wiki/Eric_Berne">Eric Berne</a>, the founder of Transactional Analysis, we all have a Child, Parent, and Adult ego state.</p>
<p>The Child's ego state is emotional, impulsive, and creative. The Parent ego state is nurturing, caring, and controlling. The Adult ego state is rational, analytical, and problem-solving. These ego states work together in different situations.</p>
<p><a target="_blank" href="https://intactacademy.com/back-to-basics-executive-coaching-series-the-function-of-ego-states-how-to-communicate-effectively/#!form/Email"><img src="https://teamagility.com/wp-content/uploads/2019/11/functional-ego-states.png" alt /></a></p>
<p>For me, Transactional Analysis was a useful tool to help me connect with my rebellious child. It helped me explore what the problem was.</p>
<p>When I neglect my emotions and blog only on pure willpower, then it will eventually hurt me. I will get a bad feeling. When I do that for too long, I will associate blogging with a bad feeling.</p>
<p>I encourage you to read the following article, <a target="_blank" href="https://www.forbes.com/sites/forbescoachescouncil/2023/03/09/how-to-use-transactional-analysis-to-discover-your-authentic-self/">written on the site of Forbes</a> about how to use Transactional Analysis to discover your authentic self.</p>
<h1 id="heading-atomic-habits">Atomic Habits</h1>
<p>At the start of the year 2023, I started setting small, achievable goals for my writing and made sure to stick to them consistently. Stolen from my habit of making software design decisions, is making the implicit explicit. <a target="_blank" href="https://ardalis.com/make-implicit-explicit/">By making them explicit</a>, telling my intentions is helping me enforce my new habit.</p>
<p>James Clear, the author of Atomic Habits, wrote: "<a target="_blank" href="https://www.goodreads.com/quotes/9868917-missing-once-is-an-accident-missing-twice-is-the-start">When you do something once, it's not a habit. When you miss it twice, it's not a habit either. But when you do something twice in a row easily, you start to create a new habit</a>".</p>
<p>However, it is still up to me, to protect my state of mind and health, and to ensure I have the will and energy to follow through with creating new habits.</p>
<h1 id="heading-self-care-or-self-sabotage">Self-care or self-sabotage?</h1>
<p>When we are under stress, it is common to enter the critical child state, where we view the world from a negative and self-punishing perspective. In this state, it is easy to cancel and not pursue my goals. Is that self-care then? In that emotional state, my main goal is to feel safe and secure and to ensure to keep away from the chaos.</p>
<p>Self-care is essential during stressful times. Self-care does not mean stopping. It's about finding a balance between taking care of yourself and taking action to achieve your goals.</p>
<p>Self-care can include a range of activities and practices that help you feel renewed, refreshed, and restored. Exercise, healthy eating, and rest, as well as emotional practices like mindfulness, meditation, and seeking support, are things that are working for me best.</p>
<p>I am glad that I have a new tool to practise to support my further endeavours.</p>
<h1 id="heading-outro">Outro</h1>
<p>Transactional Analysis is an important tool that I highly recommend mastering. I find it essential for staying true to myself, my vision, and my values. This has been a significant discovery and can be quite intimidating: making decisions based not only on what I feel and think is best but most importantly, aligning them with my mission and values: I want to stay focused on the road towards fulfilment.</p>
<p>Learning and growing is a journey, and it's okay to go at my own pace and make mistakes along the way. I will keep searching for the path that works best for me.</p>
]]></content:encoded></item><item><title><![CDATA[Advancing Towards the AZ-204 Certification: Victories and Hurdles]]></title><description><![CDATA[Previously on...
At the beginning of the year, I challenged myself to pass a tech exam called AZ-204. In this blog post, I'll talk about my experience that leads up to taking the exam and share my process of studying for it.
Context
As a consultant, ...]]></description><link>https://dotnet.kriebbels.me/advancing-towards-the-az-204-certification-victories-and-hurdles</link><guid isPermaLink="true">https://dotnet.kriebbels.me/advancing-towards-the-az-204-certification-victories-and-hurdles</guid><category><![CDATA[Azure]]></category><category><![CDATA[Certification]]></category><category><![CDATA[az204]]></category><category><![CDATA[failure]]></category><category><![CDATA[journey]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 21 May 2023 04:25:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684606304003/8a61dde2-a1aa-41b5-a8dc-cdb3d98dac82.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>At the beginning of the year, <a target="_blank" href="https://dotnet.kriebbels.me/devretro2022-my-adventure-in-consultancy">I challenged myself</a> to pass a tech exam called <a target="_blank" href="https://learn.microsoft.com/en-us/certifications/exams/az-204/">AZ-204</a>. In this blog post, I'll talk about my experience that leads up to taking the exam and share my process of studying for it.</p>
<h1 id="heading-context">Context</h1>
<p>As a consultant, obtaining certifications demonstrates to potential customers that I have gone beyond the minimum expectations, giving them more confidence when working with me. However, it's crucial to remember that while certification may show a certain level of knowledge, it doesn't necessarily reflect a complete understanding of the subject.</p>
<p>After I began working for <a target="_blank" href="http://xpirit.com">Xebia | Xpirit</a>, one of my tasks was to earn Azure certifications such as the AZ-900 (Azure Fundamentals) and AZ-204 (Azure Developer Associate). I decided to start on the AZ-204 because I was advised to wait on the AZ-900 until Microsoft offered a free course with a seat for taking the exam. I eventually attended one of these free sessions. Those sessions are called <a target="_blank" href="https://www.microsoft.com/en-us/trainingdays/azure">Virtual Training Days.</a> During that session the moderator informed us that there was no free way to attempt the certification.</p>
<p>With this in mind, I was curious about the process of earning certifications. After all, it's Microsoft - they must have excellent learning material and documentation of <a target="_blank" href="http://docs.microsoft.com">Microsoft</a>, as well as <a target="_blank" href="https://learn.microsoft.com/en-us/training/">learning paths on Azure</a> and <a target="_blank" href="https://www.pluralsight.com/paths/developing-solutions-for-microsoft-azure-az-204">Pluralsight</a>. Pluralsight even provides a practice exam. I thought I was prepared... so, how challenging could earning a certification be?</p>
<h1 id="heading-move-heaven-and-earth-to-get-myself-started">Move heaven and earth to get myself started</h1>
<p>Getting started with something can be quite difficult. I know what I want to achieve. Most of the time I have that epic vision in my head that represents the result. If I want to do something new, it requires a lot of will- and mental power to get started on that. Once I am invested, I can dial back and work on a path towards that goal. The next difficult step is being consistent towards achieving that goal.</p>
<p>I make it easier to achieve my goals by breaking them down into smaller, achievable steps that allow me to take gradual progress towards the final objective. This may lead me to work more than just focusing on the end goal alone. However, if getting started seems like a challenge, I take the initial smaller steps to invest myself in the larger goal.</p>
<p><a target="_blank" href="https://twitter.com/AlexOsterwalder/status/1480616819996213249"><img src="https://pbs.twimg.com/media/FIw1JlsXEAAH8mn?format=jpg&amp;name=small" alt="Image" /></a></p>
<h1 id="heading-getting-a-certificate-is-challenging">Getting a certificate is challenging.</h1>
<p>When I began studying for the AZ-204 exam, I assumed it would be similar to studying in high school or university. To begin, I focused on theoretical knowledge and started with a Pluralsight video, followed by reading and note-taking on the Microsoft learning path. To evaluate my understanding, I took a free test exam provided by Cybervista and Pluralsight.</p>
<p>Unfortunately, I scored only 22%, indicating my strategy had failed. I felt lost and disillusioned, but I realized I had gained more knowledge on Azure and its ecosystem. Despite my efforts, I still had a long way to go and struggled to pass the first module after investing 16 hours in studying.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Four_stages_of_competence">There are 4 steps to master something</a>. Below I have an image, borrowed from <a target="_blank" href="http://www.zen-tools.net">a website called "ZenTools"</a> that shows the different kinds of learning stages.</p>
<p><a target="_blank" href="https://www.zen-tools.net/stages-of-learning.html"><img src="https://www.zen-tools.net/images/the_4_stages_of_learning.jpg" alt="The 4 Stages Of Learning. How to move from “I don’t know what I DON’T know” to “I don’t know what I DO know!" /></a></p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Four_stages_of_competence">According to Wikipedia</a>, the process of learning a new skill can be divided into four stages. Let me assess my situation using this learning model.</p>
<ul>
<li><p><strong>Unconscious incompetence</strong>: An individual may not understand or know how to do something and may not recognize their deficit.</p>
<ul>
<li>I was not at this stage.</li>
</ul>
</li>
<li><p><strong>Conscious incompetence</strong>: That individual becomes conscious of their incompetence and recognizes the value of the new skill.</p>
<ul>
<li>According to the test, I was definitely in that stage. I became consicious of my flaws.</li>
</ul>
</li>
<li><p>In the <strong>conscious competence</strong> stage, the individual comes to understand how to perform the skill but still requires concentration to execute.</p>
<ul>
<li>According to that first test, I had no competence. However, I work daily with a subset of Azure Services. It is difficult for me to admit that according to this test, then, I was not consciously competent.</li>
</ul>
</li>
<li><p>In the <strong>unconscious competence stage</strong>, the skill has been practised so much that it can be performed easily and second nature. The individual may even be able to teach it to others.</p>
<ul>
<li>Just not applicable at that point.</li>
</ul>
</li>
</ul>
<p>One of the first steps to learning something is: <strong>Know what to do.</strong> The test on CyberVista confirmed that I did not know what to do. At this point, I reached out to <a target="_blank" href="https://azurecodingarchitect.com/">Bas van de Sande</a>. <a target="_blank" href="https://www.credly.com/users/bas-van-de-sande/badges">I think he knows a thing or two about getting a certification...</a> He recommend that I learned each day for one hour. For sources, he recommended me <a target="_blank" href="https://www.examtopics.com/exams/microsoft/az-204/">ExamTopics</a> and <a target="_blank" href="https://learn.microsoft.com/en-us/certifications/exams/az-204/">the learning path that Microsoft provided</a>.</p>
<p>ExamTopics offers me to learn question by question. When learning a subject that is represented by a question, I should use the discussion that is there in the answer section. When the discussion is not clear on a subject, I should visit the given links for that question. By reading the given links, I should know the answer.</p>
<h1 id="heading-seek-out-a-learning-strategy">Seek out a learning strategy.</h1>
<p>I wanted that achievement as soon as possible. However, I want to brute force my way through. I did not want to wait and have a long process. I wanted instant gratification. I threw out the advice about studying each day for one hour. I did follow up on the advice about studying with the questions provided by ExamTopics.</p>
<p>I have to say I had my brighter moments because I felt horrible. One of the upsides that ExamTopics has, is that I can extract a PDF of the questions provided. So I started the export to PDF. That was over 800 pages with discussions included.</p>
<p>Starting to go through the questions, I noticed that there is a lot of doubt. There is a provided answer and I have the community's answer as well! With that, I have a lot of discussions and source references. This was hell for me. I "just" want to learn and have clear answers, put on a platter. After some retries and brute forcing, I noticed that it gave me a lot of negative energy.</p>
<p>After some extra brute forcing myself into this, I decided to do it differently. I will learn each day for one hour as Bas suggested. <a target="_blank" href="https://xpirit.com/team/kristof-van-hees/">Kristof Van Hees</a> has a method that is similar to that of Bas. He recommends me Whizlabs. Whizlabs offers a lot of questions. Whizlabs does not work with PDF but offers an interactive way of working. I got direct feedback if I get it right or wrong. There is a reason why the answer I picked was good or wrong. For each question, Whizlabs provides a source as well. In this phase, I just tried out the questions and my focus was on getting good answers. I verified why I picked the good answer. This way of learning was a better fit for me, but I did not get a feeling I deepened my knowledge of the subjects. I redid the questionnaires multiple times.</p>
<p>I talked to my coach <a target="_blank" href="https://www.mypersonalcoach.be/">Kristien</a> about this topic. I wanted to postpone my deadline, however, she urged me to try the exam. When I take an exam, I can have a free do-over. What have I got to lose then? At this point, I have accumulated 60 hours worth of studying.</p>
<h1 id="heading-lets-go-setting-a-deadline">Let`s go! Setting a deadline...</h1>
<p><img src="https://cdn.leonardo.ai/users/6e2846cb-1932-40e6-be53-4dcca360cea9/generations/84db06d5-a190-4dec-9b70-1d33a6468be4/DreamShaper_v5_Generate_an_image_that_visually_represents_a_de_1.jpg" alt="Generate an image that visually represents a deadline without any text on it." /></p>
<p>With a lot of self-doubts, I bought a seat to take an exam at home. Microsoft offered me to buy access to the MeasureUp test exam as well. I can recommend everybody to do this. Those test exams are more difficult than the ones on Whizlabs. I just took the test exam and score 55%. To pass the Microsoft exams I need 70%. MeasureUp works in the same way as Whizlabs. The difference is that Whizlabs offers more videos and education around the topic. MeasureUp explains why an answer is good and why it is bad. I visited the links they provide for each answer. I started doing that because I did not understand some answers and felt insecure about some topics. Then it hits me, I think I figured out how to study for the exam.</p>
<h1 id="heading-how-to-study-for-the-exam">How to study for the exam.</h1>
<p>Remember Bas, that good guy that told me how to study for the exam? Well, it was only ExamTopics that was not working for me. Understand that I will go through a process that is different from the one I know. Expect to fail... hard.</p>
<p>After I understand what kind of sources I got at my disposal, I figured out the following process:</p>
<ul>
<li><p>Ensure that I go through the learning path that Microsoft presents. This is important to understand the concepts and the dependency between all the subjects presented. It is very important for me, to get a good understanding of how all those concepts are linked. Without that, question-based studying offers me no reference points. During the process of finding out what works for me to study, I thought this was not needed. But looking back, I can say that it is not wasted time.</p>
</li>
<li><p>Go watch the videos as a summary.</p>
</li>
<li><p>Go and find my source for questions. I will use Whizlabs again.</p>
</li>
<li><p>For each question:</p>
<ul>
<li><p>Understand the question, do a guess, understand the answers, and visit the source.</p>
</li>
<li><p>Read the whole page and then go to the next question.</p>
</li>
</ul>
</li>
<li><p>Do this every day for several questions if I want to quantify my progress or work for some time. I will start with ten questions or one hour. I can adjust accordingly after witnessing my progression.</p>
</li>
<li><p>Once I get 70% on the test exams, order my seat to take the exam use MeasureUp and take the exam with confidence. Remember, I got a free do-over.</p>
</li>
</ul>
<h1 id="heading-summary-certification-preparation">Summary certification preparation</h1>
<p>Below I have made a list of sources:</p>
<ul>
<li><p><a target="_blank" href="https://www.reddit.com/r/AzureCertification/search/?q=az%20204&amp;restrict_sr=1&amp;sr_nsfw=">Reddit: r/AzureCertificiaton: az 204</a>: I used this source to understand that I am not alone in this.</p>
</li>
<li><p><a target="_blank" href="https://www.thomasmaurer.ch/2020/03/az-204-study-guide-developing-solutions-for-microsoft-azure/">Thomas Maurer (MVP): AZ-204 Study Guide: Developing Solutions for Microsoft Azure</a>: A recommended source on certifications. Read it before I start. I wish I knew this before I got my certification.</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/certifications/exams/az-204/">Microsoft Learn: Exam AZ-204: Developing Solutions for Microsoft Azure - Certifications</a>. useful to buy my seat for the exam and to buy my access to the MeasureUp test exams.</p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=jZx8PMQjobk&amp;t=6199s">Exampro: Az 204 full video</a>: A good explanation of the concepts given with taken the examination in mind.</p>
</li>
<li><p><a target="_blank" href="https://www.pluralsight.com/paths/developing-solutions-for-microsoft-azure-az-204">Pluralsight: Developing Solutions for Microsoft Azure (AZ-204) Learning Path</a>: The videos are good, structured and to the point. However, it feels like there is missing some information at the time of writing. The access to CyberVista is useful as well for having another set of questions to learn from.</p>
</li>
</ul>
<h1 id="heading-show-off-your-hard-work">Show off your hard work</h1>
<p>I recommend adding your certifications to your LinkedIn profile. It's a great way to showcase your skills and achievements to potential employers or potential customers.</p>
<p>Don't be afraid to let others know that you're certified and proud of your accomplishments.</p>
<p>Sometimes people might feel hesitant to share their certifications. Some people fear it might come across as bragging. Others might feel like they don't want to be perceived as arrogant.</p>
<p>However, as long as you are humble and gracious in the way you share your achievements, there's nothing wrong with letting others know about your certifications.</p>
<p>If you want to check out how that is visualised, check mine out here: <a target="_blank" href="https://www.credly.com/badges/9b96f7aa-a384-4268-ad53-2bc6e5bf0be4/linked_in_profile">Microsoft Certified: Azure Developer Associate - Credly</a></p>
<h1 id="heading-outro">Outro</h1>
<p>Initially, I had a lot of different points of view when writing this post. Should I just write about how to achieve the Az-204? Should I write about my journey in achieving that certificate? Should I write about the aftereffects of obtaining that certificate? I ended up with a mixture of telling where I failed, what my pitfalls were and how I am going to study for other certifications. I can only hope this can help others as well.</p>
<p>At <a target="_blank" href="https://techorama.be/">Techorama</a> 2023, I was surprised when some people asked me when I was going to write a new blog post. I like that people are holding me accountable. At the start of my blogging journey, I set a goal for myself, which was to have a weekly blog post in 2023 to build out my authority. I am humbled by this and feel inspired to write more.</p>
<p>In my next post, I will talk about why I stopped blogging for a bit and what helped me regain focus again.</p>
<p>Furthermore, I am still on the path of protecting my privacy. <a target="_blank" href="https://dotnet.kriebbels.me/how-to-know-if-your-data-is-leaked">I listed what I want to blog about</a> and I intend to keep that promise.</p>
]]></content:encoded></item><item><title><![CDATA[Enable developers to generate safe and secure code]]></title><description><![CDATA[Previously on...
In my previous blog post, I wrote about JSON RCE attacks. The possibility of such an attack exists, was brought to my attention in a report by CheckMarx. I heard about SAST scans from the product team that I worked with. Our team was...]]></description><link>https://dotnet.kriebbels.me/enable-developers-to-generate-safe-and-secure-code</link><guid isPermaLink="true">https://dotnet.kriebbels.me/enable-developers-to-generate-safe-and-secure-code</guid><category><![CDATA[Application Security]]></category><category><![CDATA[DAST]]></category><category><![CDATA[SAST]]></category><category><![CDATA[iast]]></category><category><![CDATA[rasp]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 16 Apr 2023 05:30:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681328300093/ce0d080d-207e-42e8-8313-dfcf92d6a0dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced">In my previous blog post</a>, I wrote about JSON RCE attacks. The possibility of such an attack exists, was brought to my attention in a report by <a target="_blank" href="https://checkmarx.com/cxsast-source-code-scanning/">CheckMarx</a>. I heard about SAST scans from the product team that I worked with. Our team was also briefed about application security by <a target="_blank" href="https://hashnode.com/@wcabus">Wesley Cabus</a> on a knowledge-sharing moment at a <a target="_blank" href="https://pages.xebia.com/knowledge-base-times-social-distancing">Xebia | Xpirit Tuesday</a>.</p>
<h1 id="heading-context">Context</h1>
<p>I am trying to gain a better understanding of how I can code with a security mindset. Although I have heard of <a target="_blank" href="https://checkmarx.com/cxsast-source-code-scanning/">Checkmarx</a>, I did not got any insight into the process how security reports came to be. I still have many questions about the process. For example, why does it take two days before results are available? Why is this information only available at the end of the process? Additionally, I am confused as to why security is only available at the end of the development lifecycle. What about the packages that are used in the project? <a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced">In a previous post</a>, I wrote about the RCE (Remote Code Execution) that could be done with version 11 of Newtonsoft, but in the project, versions 12 and 13 were used. However, the SAST still flagged it.</p>
<p>Recently, I came across a company called <a target="_blank" href="https://www.contrastsecurity.com/">Contrast Security</a> on <a target="_blank" href="https://www.linkedin.com/company/contrast-security">LinkedIn</a>. I was able to schedule a meeting with them. During this meeting, I received an introduction to application security. Next followed was a demo of their <a target="_blank" href="https://www.contrastsecurity.com/contrast-assess">product Contrast Assess</a>. They stressed that they offered a <a target="_blank" href="https://www.contrastsecurity.com/contrast-community-edition">community edition</a>. The community edition is free to play with. I want to stress that I am not affiliated, but I cannot hide that I am an enthusiast. I still need to play with the community edition.</p>
<p>Before I can show off how their community edition works, I believe it is important to understand application security. As developers, it is important to know what to use and when.</p>
<p>Contrast Security mentioned that other colleagues of mine at Xebia, have taken interest in their products: <a target="_blank" href="https://www.linkedin.com/in/carloklerk">Carlo Klerk</a> and <a target="_blank" href="https://www.linkedin.com/in/maartenplat/">Maarten Plat</a> from the Xebia Security team. Funny how small the world is. Xebia is off course a big company, it is hard to know all my colleagues.</p>
<p>Maarten Plat is busy with a 5-part blog series about this subject. <a target="_blank" href="https://xebia.com/blog/how-to-make-your-web-application-more-secure-by-using-static-application-security-testing-part-1-of-5-in-application-security-testing-series/">Part one tackles the subject SAST</a>. <a target="_blank" href="https://xebia.com/blog/how-to-make-your-web-application-more-secure-by-using-dynamic-application-security-testing-dast-part-2-of-application-security-testing-series/">Part two tackles the part DAST</a>. Other blog posts will tackle IAST and SCA. The last part will be about integrating those tools into a Continuous Integration (CI) pipeline. Maarten also made a tutorial about one of the products of Contrast Security, so be sure to follow him! Let us read below what all those abbreviations mean...</p>
<h1 id="heading-application-security">Application Security</h1>
<p>It is crucial to understand what tools are used during the development and product lifecycle. Writing secure code is essential. When you add a package with vulnerabilities or use an insecure way of working, you want to be notified as soon as possible. The same mindset applies to writing unit tests, automate your deployment to allow (automated) integration testing. This allows a better understanding of business, infrastructure and security requirements.</p>
<h2 id="heading-at-the-beginning-of-a-lifecycle">At the beginning of a lifecycle</h2>
<p>Even before you have runnable code, your work can already be insecure. The longer you wait to adjust this, the harder it is going to be. Read more about <a target="_blank" href="https://www.securecodewarrior.com/article/mitigating-technical-debt">Mitigating technical debt with developer-driven security (</a><a target="_blank" href="http://securecodewarrior.com">securecodewarrior.com</a><a target="_blank" href="https://www.securecodewarrior.com/article/mitigating-technical-debt">)</a></p>
<p><a target="_blank" href="https://www.contrastsecurity.com/developer/learn#Contrast-Secure-Code-Lessons">On the website of contrast security, you can learn how to code securely.</a></p>
<h3 id="heading-static-code-scanning">Static Code Scanning</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Static_program_analysis">Static Application Security Testing (SAST)</a> is a process that analyzes the source code to find security vulnerabilities. Some popular SAST tools are Checkmarx, SonarQube, and Fortify. SAST is very useful at the beginning of a greenfield development project. There are no real deliverables yet. <a target="_blank" href="https://salesforce.stackexchange.com/questions/158186/why-is-checkmarx-taking-so-long-to-complete">It can take a lot of time to scan the entire repository</a>.</p>
<p>However, there seem to be SAST tools out there that can also integrate into the CI pipeline. The downside of using the SAST tool is that you as a developer need to investigate false positives and negative negatives.</p>
<p>A great comparison of SAST tools is defined in the following <a target="_blank" href="https://www.mend.io/resources/blog/best-sast-tools/">blog post</a>. There you can read that an effective SAST tool should support the shift-left philosophy. That means it allows security testing to be done earlier in the software development lifecycle. It should scan entire repositories, integrate seamlessly with the CI/CD pipeline, and offer fast scanning speeds. A SAST tool should minimize false positives and promote developer productivity by providing useful suggestions and resources for code fixes and library updates. <a target="_blank" href="https://owasp.org/www-community/Source_Code_Analysis_Tools">The OWASP Foundation also states this. They also specify a list of vendors of SAST tools...</a></p>
<p>As a developer, I want to have great feedback with not much of false positives or negative negatives. My experience is that CheckMarx will choke itself when a developer writes loosely coupled code, using dependency injection. Because my colleague did not write its code loosely, he got a bunch of reported problems and I did not. However, there are cases mentioned in his report that I should apply as well.</p>
<p>As mentioned before, these tools will scan your repositories and make an in-memory model of your code. This way, they can try to see where possible problems exist. If you add code that is not used, the tool will know that and give you remarks on it. Even if that codepath is not used. But we all delete our dead code, right?</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=pNlxH07iRZY">https://www.youtube.com/watch?v=pNlxH07iRZY</a></div>
<p> </p>
<h3 id="heading-software-composition-analysis">Software Composition Analysis</h3>
<p>Software Composition Analysis (SCA) is done by tools that manage the packages you use in your application. You want to make sure you use safe packages. <a target="_blank" href="https://jfrog.com/">JFrog</a>, <a target="_blank" href="https://www.mend.io/">Mend</a>, <a target="_blank" href="https://snyk.io/">Snyk</a>, <a target="_blank" href="https://www.contrastsecurity.com/contrast-sca">Contrast SCA</a>, and <a target="_blank" href="https://jeremylong.github.io/DependencyCheck/">Dependency-Check</a> are some tools that are used for that.</p>
<p><a target="_blank" href="https://jfrog.com/blog/a-year-of-supply-chain-attacks-how-to-protect-your-sdlc/">JFrog has a good blog post that tells you about the dangers of using third-party packages.</a> I created a summary of how they suggest you can protect yourself from an attack like that. JFrog recommends:</p>
<ul>
<li><p>establishing a <a target="_blank" href="https://supplychaingamechanger.com/what-is-the-best-supplier-vetting-process/">vetting process for your supply chain</a>,</p>
</li>
<li><p>shift security left in the <a target="_blank" href="https://en.wikipedia.org/wiki/Systems_development_life_cycle">SDLC</a>,</p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Code_integrity">verify binary code integrity</a>,</p>
</li>
<li><p>require an <a target="_blank" href="https://en.wikipedia.org/wiki/Software_supply_chain">SBOM</a> for all software,</p>
</li>
<li><p>protect your SDLC with multi-factor authentication,</p>
</li>
<li><p>avoid <a target="_blank" href="https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610">dependency confusion</a></p>
</li>
<li><p>avoid <a target="_blank" href="https://en.wikipedia.org/wiki/Typosquatting">typosquatting</a> attacks,</p>
</li>
<li><p>and <a target="_blank" href="https://the-guild.dev/blog/how-should-you-pin-dependencies-and-why">use version pinning</a> for packages.</p>
</li>
</ul>
<p>A lot of these recommendations need an investigation that goes beyond the scope of this blog post... I linked corresponding definitions and other blog posts that are worth reading.</p>
<p>Below you find an example of the JFrog Artifactory.</p>
<p><a target="_blank" href="https://www.jfrog.com/confluence/display/RTF?preview=/46107472/47874380/Artifactory4Main.jpg"><img src="https://www.jfrog.com/confluence/download/attachments/46107472/Artifactory4Main.jpg?version=1&amp;modificationDate=1442390573000&amp;api=v2" alt="Artifactory4Main.jpg" /></a></p>
<p>I loved the way that Contrast Security presented their SCA tool to me: <a target="_blank" href="https://www.contrastsecurity.com/contrast-sca">Contrast SCA | Software Supply Chain Security and Risk Management | Contrast Security</a>. Contrast Security does not only list the packages with known vulnerabilities but also identifies what code the developer uses from the package. E.g. when there is a vulnerable unused package in your repository, Contrast shows you are not using that package, thus you should not care about it. Another use case would be identifying where a vulnerable package is used in the organisation: <a target="_blank" href="https://www.reddit.com/r/msp/comments/rdba36/critical_rce_vulnerability_is_affecting_java/">remember Log4J</a>, a lot of companies needed to identify manually if they were using that vulnerable package.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681394643451/6aed2ce5-1c92-485a-9622-cd5e7f9a99d0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681394655156/1ea04e62-4a7f-4085-9736-3f34a08783e6.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-during-the-cycle-of-development-and-testing">During the cycle of development and testing</h2>
<p>Interactive Application Security Testing (IAST) is more dynamic and interactive than SAST. From what I understand is that IAST is useful for integration tests or local tests where you get direct feedback.</p>
<p>When I did my research for this blog post, <a target="_blank" href="https://www.contrastsecurity.com/hubfs/DocumentsPDF/Contrast-Scan-Modern-Application-Security-Scanning_Solution%20Brief_Final.pdf?hsLang=en">I noticed that Contrast Security has a vision of what to use in the CI/CD pipeline</a>. In summary, they find that traditional scanning tools are slow, compute-intensive, and expensive, hindering development pipelines and CI/CD processes. Their product uses instrumentation technology to attach to an application and observe how it handles requests during runtime. Instrumentation is also used by e.g. <a target="_blank" href="https://newrelic.com/">New Relic</a> and <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview?tabs=net">Azure Application Insights</a>.</p>
<p>Visit the blog site <a target="_blank" href="https://www.mytechramblings.com/posts/getting-started-with-opentelemetry-metrics-and-dotnet-part-2/">mytechramblings</a>. There you find a real-life example of how to instrument code. Explaining instrumentation is not part of the scope of this blog post.</p>
<p>In the images below, you can find an example request, where the email address <code>kristof@xebia.com</code> is not properly handled by the application.</p>
<p>Their tool observes that</p>
<ul>
<li><p>there isn’t sufficient validation and sanitization of the user input in this request. That is a confirmation that there is an SQL injection flaw.</p>
</li>
<li><p>the unsanitized input, which is the email address, ends up being used directly in the SQL Query. That is displayed in red in the image below.</p>
</li>
</ul>
<p>Contrast tries to help the developer by giving a similar overview in the form of a stack trace. That overview shows the problem, where to fix that problem and gives guidance on how to remediate it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681478748081/ff51f589-fd39-43fa-a6eb-1f75f5b2bfe7.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681394736769/f916e521-890f-44ab-8d8a-05f319061d55.png" alt class="image--center mx-auto" /></p>
<p>The following video that I found gives a demo about Contrast Security. However, that one is 4 years old. Although the UI is outdated, you can get a good grasp on how such a tool can work.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=XiLc8piqJQY">https://www.youtube.com/watch?v=XiLc8piqJQY</a></div>
<p> </p>
<h2 id="heading-when-you-have-a-deliverable-before-production">When you have a deliverable, before production</h2>
<p>Dynamic Application Security Testing (DAST) is a process that analyzes the application in its running state to find security vulnerabilities. Examples of DAST tools are OWASP <a target="_blank" href="https://www.zaproxy.org/">ZAP</a>, <a target="_blank" href="https://portswigger.net/burp">Burp Suite</a>, and <a target="_blank" href="https://www.acunetix.com/">Acunetix</a>. I already downloaded <a target="_blank" href="https://github.com/pwntester/ysoserial.net">YSOSerial.Net</a> for <a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced">my previous blog post</a>. However, when I cloned that repository, compiled that project and ran that, Windows Defender did not let me start that executable... You can find a great example of the usage of YSOSerial.Net in the following video.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=eDfGpu3iE4Q">https://www.youtube.com/watch?v=eDfGpu3iE4Q</a></div>
<p> </p>
<p>Another popular tool is <a target="_blank" href="https://portswigger.net/burp">Burp Suite</a>. I recommend watching the next video on it.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=IWWYNDiwYOA">https://www.youtube.com/watch?v=IWWYNDiwYOA</a></div>
<p> </p>
<p>DAST is useful to test your application before you go into production. It is more difficult to find and understand errors. Unlike SAST, DAST is using your application as a black box. DAST does not know a thing about the application under test. Such a tool allows you to see if any known attacks are going to work on your application. My <a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced">blog post about JSON RCE Attack was a way of DAST</a>.</p>
<h2 id="heading-after-deployment">After deployment</h2>
<p>Also after deployment, there is a need for protection. I will discuss RASP (Runtime Application Self-Protection) and WAF (Web Application Firewalls).</p>
<p>Runtime Application Self-Protection (RASP) tools help you detect errors in real-time. Some popular RASP tools are <a target="_blank" href="https://www.sqreen.com/">Sqreen</a>, <a target="_blank" href="https://avd.aquasec.com/misconfig/aws/waf/">Aqua</a>, and <a target="_blank" href="https://www.wallarm.com/">Wallarm</a>. <a target="_blank" href="https://www.contrastsecurity.com/contrast-protect">Contrast Security also has a tool that does this</a>.</p>
<p>Web Application Firewalls or WAFs can be configured with specific rules to identify and block known attack patterns such as <a target="_blank" href="https://www.stackhawk.com/blog/net-sql-injection-guide-examples-and-prevention/">SQL injection</a> and <a target="_blank" href="https://websitesecuritystore.com/blog/real-world-cross-site-scripting-examples/">cross-site scripting (XSS)</a> based on signatures.</p>
<p><a target="_blank" href="https://geekflare.com/rasp-tools/">The difference with Runtime Application Self-Protection, or RASP</a>, is a security technology deployed within the application itself. RASP provides real-time protection against attacks by monitoring the application's behaviour. It responds to threats as they arise. RASP is also capable of detecting and blocking attacks that were not previously known by looking at the behaviour. E.g. When a user tries to use a SQL injection attack, the tool will be able to detect that and throws an exception that results in an Internal Server Error. To see it in action, <a target="_blank" href="https://www.contrastsecurity.com/security-influencers/contrast-vs-the-log4j2-cve-a-demonstration?wvideo=80y2qkb6aq">Contrast has a video</a> to show how their product defends against the Log4J exploit.</p>
<h1 id="heading-outro">Outro</h1>
<p>I did my best to not let this post be a Contrast Security advertisement. I want to give them credit because they did take the time to explain to me the basics of application security. With that demo and the information is given, I did my research and learned a lot. I hope I can sparkle your interest in Application Security as well, so we can all code with a security mindset.</p>
<p>I want to test out the community edition that Contrast Security offers. I will share my experiences as well. That can be something to play with on an innovation day that is organized at Xpirit | Xebia. I do not know at this point where to find the time... But I promise I will add this to my to-do list.</p>
]]></content:encoded></item><item><title><![CDATA[An Egg-citing Approach to Email Privacy]]></title><description><![CDATA[Previously on...
In the previous blog post in this series, I discuss the evolution of email identities. I state the history of using creative and unique nicknames in the early days of the internet to the increasing need for real names to establish cr...]]></description><link>https://dotnet.kriebbels.me/an-egg-citing-approach-to-email-privacy</link><guid isPermaLink="true">https://dotnet.kriebbels.me/an-egg-citing-approach-to-email-privacy</guid><category><![CDATA[email]]></category><category><![CDATA[Bitwarden]]></category><category><![CDATA[privacy]]></category><category><![CDATA[smtp]]></category><category><![CDATA[simplelogin]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 09 Apr 2023 15:57:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680983681313/62b20d91-0247-4671-abb1-499622cfe9a1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>In the previous blog post in this series, I discuss the evolution of email identities. I state the history of using creative and unique nicknames in the early days of the internet to the increasing need for real names to establish credibility and trust. I explored various solutions to establish trust in email communication: SPF, DKIM, DMARC, and sub-addressing.</p>
<p>In this series, I am hoping to regain control of my data. I hop into the world of unique credentials for each website. I will use email forwarding service SimpleLogin.io to protect privacy and reduce spam.</p>
<h1 id="heading-context">Context</h1>
<p>I'm writing this because I'm fed up with spam and the constant mistrust in companies' security measures. Let me give an example of why it is important to protect your data and even using a unique login is not a luxury anymore...</p>
<p><a target="_blank" href="https://openai.com/blog/march-20-chatgpt-outage">OpenAI announced that ChatGPT has been breached and data is leaked</a>. The vulnerability is known as <a target="_blank" href="https://github.com/advisories/GHSA-24wv-mv5m-xv4h">CVE-2023-28859</a>. In a later blog post, I will write about how this could potentially be solved. I appreciate how OpenAI addresses this issue. They demonstrate a high level of transparency regarding the events that transpired, the information that was exposed, and their efforts to resolve the matter. As time progresses, it will become evident whether this was simply an unfortunate incident or if their organizational structure is conducive to managing such unforeseen challenges.</p>
<p>I want to stress that as long as humans are involved, things will go wrong eventually. We need to find a decent balance between security, privacy and convenience.</p>
<p>Security <a target="_blank" href="https://www.politico.com/news/2023/04/07/leaked-military-documents-on-ukraine-battlefield-operations-circulated-as-early-as-march-00091073">is difficult. Look at the US Department of Defense... Documents about e.g. the war in Ukraine are found on social media. The American Congress seems pretty mad about it...</a></p>
<h1 id="heading-unscrambling-the-email-privacy-process">Unscrambling the Email Privacy Process</h1>
<p>Let me explain how the system works by breaking it down into smaller, manageable pieces.</p>
<h2 id="heading-gather-all-the-eggs">Gather all the eggs</h2>
<p>What simple login does, is create relationships between an alias and your email inbox. SimpleLogin.io is not a place to read your mail, nor is it an SMTP server. SimpleLogin.io uses the word 'mailbox' which I found confusing in the beginning. I expected to read my emails in a 'mailbox'. However, it is just a concept to let the user know to what mailbox the alias will be linked. A mailbox is e.g. john.doe@gmail.com.</p>
<p>As a user, you can have multiple mailboxes. When you first signup, a <a target="_blank" href="https://simplelogin.io/docs/mailbox/add-mailbox/">mailbox</a> will be created. That will also be your default mailbox. I do not have multiple ones at the time of writing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681045599951/bec1fc2d-584d-4525-bfc7-5cfe3bbf5611.png" alt class="image--center mx-auto" /></p>
<p>When you want to use aliases on an e.g. commercial website, you can create subdomains for your alias. It can look like 'commercialwebsite.1234@johndoe.simplelogin.com'. The part 'commercialwebsite.1234' can be whatever you want it can be!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681045423730/0682ed95-f9bb-48aa-a732-ad5d5ba2c42c.png" alt class="image--center mx-auto" /></p>
<p>The use of a subdomain is essential because it allows the entire system to identify the default mailbox designated to receive emails. However, I opted to have my custom domain name. To get started, you do not need to spend money to get started with SimpleLogin.io.</p>
<h2 id="heading-receiving-emails-in-your-basket">Receiving Emails in Your Basket</h2>
<p>Once you have your forwarding email setup you can provide any alias email directly to the commercial website. The alias does not need to exist. SimpleLogin will create one, link it to you default mailbox and will forward you the mailbox. It replaces the sender with the alias.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681046201366/2cd6435d-94e0-4507-a5e1-e4692aab5e64.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-bunny-approved-email-deliveries">Bunny-Approved Email Deliveries</h2>
<p>I had difficulties understanding how to send an email using the alias from SimpleLogin.</p>
<p>However, it is really that simple. Before you can send an email, create a contact on SimpleLogin. Navigate to SimpleLogin website.</p>
<p>Press on Create Custom Alias</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681053897030/6f7daae0-83e6-4a43-a3c0-1e167e38e006.png" alt class="image--center mx-auto" /></p>
<p>I create an alias with the name: test.perjurer933@simplelogin.com</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681053677176/db2d1734-4828-49bb-a9fd-70829f8c077b.png" alt class="image--center mx-auto" /></p>
<p>Now you need to define where that SimpleLogin needs to forward the email. Click on contacts and fill in the name of your contact: info@commercialcompany.com.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681053823499/be7b5985-e444-4050-a7fc-4c9462d79982.png" alt class="image--center mx-auto" /></p>
<p>To get an overview, this is what you need to do.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681054089185/974ac643-43f3-4a4b-a35e-2861506e9222.png" alt class="image--center mx-auto" /></p>
<p>In your email, you can now send a mail to: test.perjurer933.simplelogin.com. Everything will be done for you.</p>
<h2 id="heading-hunting-for-missing-functionality">Hunting for Missing Functionality</h2>
<p><a target="_blank" href="https://www.reddit.com/r/Simplelogin/comments/k9vpeq/smtp_relay/">The current setup lacks an SMTP server</a>. I just want to set up a mail server that does the SimpleLogin magic instead of working with alias in my to/from. That would be an error-proof experience. Using rules to autogenerate alias and throwing errors when the alias is not defined. This would stop human error of forgetting to create an alias if needed.</p>
<p>It is on their <a target="_blank" href="https://trello.com/c/mnSYC4AF">roadmap</a>. If you cannot wait, somebody already created a <a target="_blank" href="https://github.com/leoleoasd/simple-login-smtp-relay">SimpleLogin SMTP relay</a> server. However, do you really want to go down that road?</p>
<h1 id="heading-my-egg-sperience-implementing-it">My Egg-sperience Implementing It</h1>
<p>Below I will go more in-depth on how I implemented SimpleLogin.</p>
<h2 id="heading-prepping-the-system">Prepping the System</h2>
<p>I set this up using an existing domain and a subdomain. I needed to make the following steps:</p>
<ol>
<li><p><strong>Domain Ownership Verification</strong>: Prove you own the domain by adding a special code (TXT record) given to you.</p>
</li>
<li><p><strong>MX Record</strong>: Add two mailbox (MX) records to help emails go to the right place.</p>
</li>
<li><p><strong>SPF (Optional)</strong>: Add a special note (TXT record) to let others know your emails are real and not spam.</p>
</li>
<li><p><strong>DKIM (Optional)</strong>: Add some name labels (CNAME records) to make your emails more secure and trusted.</p>
</li>
<li><p><strong>DMARC (Optional)</strong>: Add a rule (TXT record) to tell others what to do if your email doesn't pass security checks.</p>
</li>
</ol>
<p>When you are not familiar with DNS settings, this can overwhelm you. I love the functionality that SimpleLogin offers to easily verify each step that you undertake.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681051145441/e1c518bc-4945-47d7-ac56-a0cebf5a3c24.png" alt class="image--center mx-auto" /></p>
<p>I do not own johndoe.com, so I cannot verify this step.</p>
<h3 id="heading-custom-domain-configuration">Custom Domain Configuration</h3>
<p>Configure the DNS records and check out the SimpleLogin page for a smooth experience.</p>
<p>Once you follow the Custom Domain configuration, your dns records looks like the following.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681051541634/535ba786-419e-4d9f-a174-838735923166.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-bitwarden-integration">Bitwarden Integration</h3>
<p>I'll show you how to integrate Bitwarden.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681051631831/1bc04e26-ad9b-4f14-b8cb-ff08a123c74b.png" alt class="image--center mx-auto" /></p>
<p>It was difficult to find the functionality of API Key's. However, a simple Google search lead me to the <a target="_blank" href="https://forum.simplelogin.io/t/api-key-create-copy/120">forum of SimpleLogin.</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681051856450/d9509923-05eb-4a8f-87fd-ec8405233baf.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-defining-a-naming-strategy">Defining a naming strategy</h3>
<p>I already discussed this in a <a target="_blank" href="https://dotnet.kriebbels.me/the-importance-of-unique-emails-enhancing-your-security#heading-the-catch-all-menace">previous blog post</a>. But it is important to have a naming strategy. A consistent naming strategy helps you easily identify the purpose of each alias and the service it is associated with. This makes it easier to manage your aliases and keep your inbox organized. A structured naming strategy makes it easier to set up filters and rules in your email client. That allows you to automatically sort incoming emails based on their alias.</p>
<p>Here are some naming strategies:</p>
<ol>
<li><p><strong>Name + Random Number</strong>: use your name followed by a random number, e.g., <a target="_blank" href="mailto:john.12345@domain.com"><strong>john.12345@domain.com</strong></a>.</p>
</li>
<li><p><strong>Name + Date</strong>: Combine your name with the current date, e.g., <a target="_blank" href="mailto:john.20230409@domain.com"><strong>john.20230409@domain.com</strong></a>.</p>
</li>
<li><p><strong>Name + Service</strong>: Use your name and the name of the service the alias is for, e.g., <a target="_blank" href="mailto:john.netflix@domain.com"><strong>john.netflix@domain.com</strong></a>.</p>
</li>
<li><p><strong>Random Characters</strong>: Create an alias using completely random characters, e.g., <a target="_blank" href="mailto:x4tYz1@domain.com"><strong>x4tYz1@domain.com</strong></a>.</p>
</li>
<li><p><strong>Acronyms + Numbers</strong>: Use acronyms or abbreviations related to the service or your interests, followed by numbers, e.g., <a target="_blank" href="mailto:moviebuff2023@domain.com"><strong>moviebuff2023@domain.com</strong></a>.</p>
</li>
<li><p><strong>Name + Purpose</strong>: Combine your name with the purpose of the alias, e.g., <a target="_blank" href="mailto:john.shopping@domain.com"><strong>john.shopping@domain.com</strong></a>.</p>
</li>
</ol>
<p>I am opting for the way that Bitwarden suggests a name. You can ask Bitwarden to generate an alias and it will generate the alias for you on the site SimpleLogin</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681052639438/0c7fd559-d5e5-415e-aac8-21b75995ffb2.png" alt class="image--center mx-auto" /></p>
<p>When the generation occurs, I added the name of the commercial website in the prefix as well.</p>
<p>In this case, that would be <code>commercialwebsite.scramblermurmering087@domain.com</code></p>
<h3 id="heading-catch-all-strategy-conundrum">Catch-all Strategy Conundrum</h3>
<p>Is it wise to enable catch-all functionality indefinitely? What about the potential for recurring spam and automatic alias creation? <a target="_blank" href="https://en.wikipedia.org/wiki/Bounce_message#Classification">Wikipedia is quite sure that this can be abused</a>.</p>
<p>SimpleLogin provides an option to turn off the catch-all functionality. It then works with a regex rule system. I will quote them.</p>
<p><code>For a greater control than a simple catch-all, you can define a set of rules to auto create aliases. A rule is based on a regular expression (regex): if an alias fully matches the expression, it'll be automatically created.</code></p>
<p>The following image is a print screen of the existing system. You can define a regex prefix rule. That regex rule is coupled with a mailbox. There is a debug zone as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681054688993/06e6038e-973c-4e3d-b670-7131f313f88d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-into-the-easter-bunnys-burrow">Into the Easter Bunny's Burrow</h2>
<p>It is difficult to work with structure. So sometimes... you just need to do. The more you go down the burrow, the more knowledge you gather.</p>
<h3 id="heading-updating-egg-isting-accounts">Updating Egg-isting Accounts</h3>
<p>With the existing setup, I can already start updating my emails. I do not need to specify naming strategies. I want to get a feeling of how this work in practice. I need to update my emails. The problem is, this can take a while. So where do I start?</p>
<p>I have a premium Bitwarden account. <a target="_blank" href="https://bitwarden.com/blog/how-to-use-the-data-breach-report-in-bitwarden/">That allows me to get reporting on what login is leaked and what passwords have leaked. There is an entire post about it. I will not repeat it here.</a> That helped me to get started with those accounts first.</p>
<h3 id="heading-receiving-an-email">Receiving an Email</h3>
<p>Discover how an alias email is forwarded to your mailbox. The following is a censored and anonymised extract of an email header.</p>
<pre><code class="lang-plaintext">Delivered-To: john.doe@gmail.com
Received: Sat, 8 Apr 2023 22:48:25 -0700 (PDT)
...
header.from=simplelogin.co
Return-Path: &lt;s1.lmycyibrge3abcdefheydglbagy3dombwhboq.zos4xr6@simplelogin.co&gt;
Received: from mail-2061.simplelogin.co (mail-2061.simplelogin.co. [***])
...
        for &lt;john.doe@gmail.com&gt;
...
Received-SPF: pass (google.com: domain of s1.lmycyibrge3abcdefheydglbagy3dombwhboq.zos4xr6@simplelogin.co designates **** as permitted sender) client-ip=***;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@simplelogin.co header.s=dkim header.b=XronwIgb;
       spf=pass***
       dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=simplelogin.co
DKIM-Signature: ***;
Subject: Waiting on confirmation
X-SimpleLogin-Type: Forward
X-SimpleLogin-Envelope-To: commercialwebsite.1234.dummy007@simplelogin.com
From: "CommercialWebsite - info at commercialwebsite.com" &lt;info_at_commercialwebsite_com_ypnadtx@simplelogin.co&gt;
To: commercialwebsite.1234.dummy007@simplelogin.com
...
</code></pre>
<p>It will tell you that the email journey starts from the Commercial Website, passes through SimpleLogin, and finally is delivered to John Doe's Gmail account. Security checks (DKIM, SPF, DMARC) are performed by SimpleLogin and Gmail during the process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681048366216/1e0af32d-f984-449c-98af-f439e19576d8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-sending-an-email">Sending an email</h3>
<p>Let us forget that we received the email from the commercial website. We do not have any aliases yet defined for this website. I'll explain how I initiated an email and how the reply system works, using a SimpleLogin example.</p>
<p>In this example, I wanted my account deleted. I could not initiate the delete sequence on the website. I needed to send an email to that company. I did not want that the company knows what my original email address is.</p>
<p>I went over to my simplelogin.com account. (note that there are browser extensions as well).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681047824528/76dce7d2-b948-4a46-a0ef-e0cd8f64bb25.png" alt class="image--center mx-auto" /></p>
<p>I pressed the New Custom Alias button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681048016160/4e0955fc-4892-41af-9e3e-6646a1e95599.png" alt class="image--center mx-auto" /></p>
<p>First, create an alias prefix. I would use commercialwebsite.1234.override311@aleeas.com</p>
<p>You select your mailbox, in this story, it would be john.doe@gmail.com.</p>
<p>After I send the email, I can look at the headers. This is what it looks like.</p>
<pre><code class="lang-plaintext">Date: Sat, 8 Apr 2023 09:55:42 +0200
Subject: Delete my account
From: John Doe &lt;john.doe@gmail.com&gt;
To: "Commercial Company | info at commercialcompany.com" &lt;info_at_commercialcompany_com_yblraaaaa@simplelogin.com&gt;
</code></pre>
<p>I got a reply and that looks the same as the receiving email. Let us take a look.</p>
<pre><code class="lang-plaintext">Delivered-To: john.doe@gmail.com
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@simplelogin.co header.s=dkim header.b=Qay02Ky8;
       spf=pass 
       dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=simplelogin.co
Return-Path: &lt;s1.lmycyibraalbagy3dkojshboq.mtf6b4aaaneq@simplelogin.co&gt;
Received: from mail-200*.simplelogin.co (mail-*.simplelogin.co. [*.*.*.*])
Received-SPF: pass;
Authentication-Results: mx.google.com;
       dkim=pass header.i=@simplelogin.co header.s=dkim header.b=Qay**Ky8;
       spf=pass 
       dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=simplelogin.co
Subject: Re: Delete my account
Date: Sat, 08 Apr 2023 10:48:09 +0000 (UTC)
X-SimpleLogin-Type: Forward
X-SimpleLogin-EmailLog-ID: ***
X-SimpleLogin-Envelope-To: info_at_commercialcompany_com_yblraaaaa@simplelogin.com 
From: "Company Website - info at companywebsite.com" &lt;info_at_companywebsite_com_yblrlaaa@simplelogin.co&gt;
To: John D &lt;info_at_commercialcompany_com_yblraaaaa@simplelogin.com&gt;
X-SimpleLogin-Want-Signing: yes
</code></pre>
<p>You can see that sending and receiving an email works flawlessly.</p>
<h1 id="heading-undiscussed-functionalities">Undiscussed functionalities.</h1>
<p>There is so much more to investigate. I will list the functionalities here for your convenience. I was missing an <a target="_blank" href="https://simplelogin.io/">easy overview</a>, so let me give that to you.</p>
<ol>
<li><p>Secure your account with Two-Factor Authentication (2FA) and FIDO-supported security keys.</p>
</li>
<li><p>Receive updates on new features via newsletters.</p>
</li>
<li><p>Use custom domains and suffix generators for your aliases.</p>
</li>
<li><p>Transform sender email addresses into different formats to protect your privacy.</p>
</li>
<li><p>Enable reverse-alias replacement to hide your contact email when replying.</p>
</li>
<li><p>Choose sender address inclusion options for reverse-aliases.</p>
</li>
<li><p>Automatically expand alias info and include website addresses in aliases created via browser extensions.</p>
</li>
<li><p>Set one-click unsubscribe preferences, quarantine and bounce management.</p>
</li>
<li><p>Decide how disabled aliases and blocked contacts should be handled.</p>
</li>
<li><p>Include original sender information in email headers.</p>
</li>
<li><p>Import and export aliases from other platforms or in CSV format.</p>
</li>
<li><p>Request a copy of your data according to GDPR regulations.</p>
</li>
<li><p>Delete your account if you no longer want to use the service.</p>
</li>
</ol>
<h1 id="heading-outro">Outro</h1>
<p>I want to reflect on my experiences and the challenges faced. Some websites do not offer account deletion and allow email changes. Sometimes I just want to delete my account and that is not always possible. I also notice that not everyone answers my requests to delete my data or change my email. I will find out if GDPR is useful for me as a person. I am curious if I can execute my rights. How that will go when I file a complaint, will be another story I suppose.</p>
<p>I was surprised by the number of password and username leaks uncovered through Bitwarden reports. Bitwarden and SimpleLogin come at a cost, but it's worth it. I'm still using Gmail but first things first. I am working on decoupling from known websites.</p>
<p>I do want to have a better workflow to create an alias for contact when I need to initiate the email tough. The first time is overwhelming, but now it is okay. I will look into the extensions for the browsers I use.</p>
<p>I need to search for a better way of defining my naming strategy. But at this moment, I have used the catch-all strategy. This means that anybody can mail at that subdomain and it will be delivered that the default mailbox. Off course, by the time this is published, I have disabled that catch-all way of working.</p>
<p>Have a happy easter all!</p>
]]></content:encoded></item><item><title><![CDATA[The Importance of Unique Emails: Enhancing Your Security]]></title><description><![CDATA[Previously on...
As mentioned in the initial article of this series, I've grown increasingly frustrated with phishing emails and fraudulent text messages. My objective is to regain control of my data, and writing these blog posts serves as a commitme...]]></description><link>https://dotnet.kriebbels.me/the-importance-of-unique-emails-enhancing-your-security</link><guid isPermaLink="true">https://dotnet.kriebbels.me/the-importance-of-unique-emails-enhancing-your-security</guid><category><![CDATA[privacy]]></category><category><![CDATA[Bitwarden]]></category><category><![CDATA[Security]]></category><category><![CDATA[email]]></category><category><![CDATA[simplylogin]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 02 Apr 2023 09:22:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/D2TZ-ashGzc/upload/72e28fb2ad5d28159a434a45ff03173b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/how-to-know-if-your-data-is-leaked">As mentioned in the initial article of this series</a>, I've grown increasingly frustrated with phishing emails and fraudulent text messages. My objective is to regain control of my data, and writing these blog posts serves as a commitment to taking action. I will share my past experiences, current efforts, and the knowledge I acquire along the way.</p>
<p><a target="_blank" href="https://dotnet.kriebbels.me/protect-your-digital-life-a-password-manager-really">In the previous blog post in this series</a>, we discussed the importance of password managers, specifically KeePass and Bitwarden, and how they can help keep your online accounts secure.</p>
<h1 id="heading-context">Context</h1>
<p>So far, we've determined that it's crucial to safeguard oneself against cybercriminals who exploit leaked data. <a target="_blank" href="https://dotnet.kriebbels.me/when-two-factor-authentication-is-useless">Your information is out there on the internet, but by implementing two-factor authentication (2FA) and using unique passwords, you can protect your accounts on various websites from conventional unauthorized access methods.</a></p>
<p>Managing unique login names for each website isn't too challenging, and it makes the combination harder to guess. <a target="_blank" href="https://dotnet.kriebbels.me/protect-your-digital-life-a-password-manager-really">This is a relatively simple task when using a password manager</a>. However, the issue I want to tackle goes beyond that—I want to avoid phishing emails and scams. To achieve this, I need a unique email address for logins and registrations, or even better, a separate email address for each website I sign up for.</p>
<p>The concept of using a unique email address allows you to pinpoint the source of data leaks or sales. Additionally, you can switch the email address you provided to a different one and disregard any messages sent to the original account.</p>
<h1 id="heading-the-phantom-nickname-evolution-of-email-identities">The Phantom Nickname: Evolution of Email Identities.</h1>
<p>In the early days of the internet, email addresses often featured nicknames or pseudonyms. Creative and unique nicknames allowed us to express ourselves. For me, it was a reference to the Kilrathi: A race of evolved cats in space. However, it became increasingly difficult to be able to register those popular nicknames. Many people used those nicknames in forums, chat rooms and online communities. It was natural for users to continue using these nicknames for their email addresses as well.</p>
<p>Over time, the need for using real names in email addresses emerged. We (Gen X / Millenials) became adults. Thus we needed an email address with real names. It was essential to use real names to establish credibility, trust, and professionalism.</p>
<p>Using your real name can help verify the other party the legitimacy of an email, reducing the risk of phishing and other scams.</p>
<h1 id="heading-order-66-establishing-trust-in-the-email-wars">Order 66? Establishing Trust in the Email Wars.</h1>
<p>In the early days of the internet, home computers and poorly secured email servers were vulnerable to exploitation by botnets and cyber criminals. The systems were compromised and used to send out large volumes of spam or fake emails. The origin of the email seemed genuine because of the true origin of the message. This led to a significant decrease in trust and reliability of email communications, as well as an increased risk of cyber threats like phishing and malware distribution. I<a target="_blank" href="https://superuser.com/questions/1219829/outbound-port-25-blocked">SPs started blocking outbound connections on Port 25</a> for residential customers to prevent their computers from being used as spam relays by botnets or cyber criminals. This action forced users to rely on their ISP's mail server or use an alternative, <a target="_blank" href="https://www.mailgun.com/blog/email/which-smtp-port-understanding-ports-25-465-587/">authenticated SMTP port (such as 587)</a> provided by their email service.</p>
<p>The issue with using nicknames or arbitrary names in email addresses is that it can undermine the social and visible trust between parties. A solution is needed to ensure the recipient can verify the email's legitimacy. Fortunately, some ingenious technical solutions have been developed:</p>
<ul>
<li><p><a target="_blank" href="https://nl.wikipedia.org/wiki/Sender_Policy_Framework">SPF (Sender Policy Framework)</a>: This protocol helps defend against email spoofing and phishing attacks by allowing recipient mail servers to confirm that an email claiming to be from a particular domain was indeed sent from an authorized server.</p>
</li>
<li><p><a target="_blank" href="https://nl.wikipedia.org/wiki/DomainKeys_Identified_Mail">DKIM (DomainKeys Identified Mail)</a>: This method helps guarantee that the email hasn't been tampered with and verifies the sender's identity.</p>
</li>
<li><p><a target="_blank" href="https://nl.wikipedia.org/wiki/DMARC">DMARC (Domain-based Message Authentication, Reporting, and Conformance)</a>: This approach enables domain owners to dictate how receiving mail servers should manage emails failing SPF or DKIM checks. It also allows domain owners to oversee email delivery and possible misuse of their domain.</p>
</li>
</ul>
<p>The issue with the solutions mentioned earlier is that they don't consider the average person's understanding of email technology. Many of us are unaware of the processes that occur when an email is sent. Most of us understand <a target="_blank" href="https://edu.gcfglobal.org/en/email101/introduction-to-email/1/">the basics.</a></p>
<p><a target="_blank" href="https://www.cmu.edu/iso/news/2020/email-spoofing.html">But, these methods don't appear to be very effective, because spammers and phishers can make new inboxes with custom origins way quicker than email providers can figure out they're not legit.</a></p>
<h1 id="heading-exploring-the-alias-a-new-hope">Exploring the alias: A New Hope.</h1>
<p>People are starting to experiment again with their email names. Some tested strategies are used by creating a unique email address for each site. When the alias is too obvious, others can guess your "master" email or other aliases. So you will need a random string in that email address as well. <a target="_blank" href="https://www.makeuseof.com/tag/create-strong-password-forget/">Does it ring a bell to password creation?</a></p>
<p>On the following <a target="_blank" href="https://www.reddit.com/r/PrivacyGuides/comments/q8vct2/catch_all_email_vs_aliases/">Reddit</a> forum, you can find discussions about the consequences of using random prefixes in an email address when registering on a website. This <a target="_blank" href="https://krebsonsecurity.com/2022/08/the-security-pros-and-cons-of-using-email-aliases/comment-page-1/">website</a> also discusses the uses of an alias. Others are discussing other <a target="_blank" href="https://www.reddit.com/r/PrivacyGuides/comments/q0ee09/custom_domain_email_alias_solution_to_avoid/">strategies</a> to avoid as well. <a target="_blank" href="https://hackernoon.com/what-is-an-email-alias-and-why-you-should-stop-using-your-real-email-address">I am not alone in this. Others have blogged about this as well.</a></p>
<p><a target="_blank" href="https://law.stackexchange.com/questions/32980/use-of-trademark-in-personal-email-alias">Some companies may even struggle to understand when an email address is created specifically for their organization, leading them to believe that the origin is being falsified</a>.</p>
<p><a target="_blank" href="https://law.stackexchange.com/questions/32980/use-of-trademark-in-personal-email-alias">Not everyone has a technical background, so misunderstandings can arise. Tools can also misidentify your legit random alias as a fake email.</a></p>
<p>I have not chosen why a strategy that I will implement. That I need to do. I do however explore multiple options that I could implement.</p>
<h2 id="heading-the-catch-all-menace">The Catch-All Menace</h2>
<p>The <a target="_blank" href="https://www.mailercheck.com/articles/catch-all-email">catch-all inbox</a> approach is suitable if you have a personal domain for creating your email addresses.</p>
<p>The way it functions is by activating an option that allows all emails sent to any address ending with your domain to be received in a "catch-all" inbox. Congratulations, you can now use an alias on a website. However, there are some downsides to utilizing this method.</p>
<ol>
<li><p>Catch-all inboxes can receive more spam as they accept emails sent to any address using your domain suffix, even if the address doesn't exist.</p>
</li>
<li><p>Managing and organizing emails in a catch-all inbox can be more challenging, as emails from various aliases are combined in a single location.</p>
</li>
</ol>
<p>To hide your true inbox, this seems a valid option for me. Easy to set up and use. I need to think about the naming strategy I would use.</p>
<p>However, the downsides outweigh the benefits. The biggest one for me is I can't reply without revealing my true email address.</p>
<h2 id="heading-divide-to-rule-the-galaxy">Divide to Rule the Galaxy</h2>
<p>In the spirit of the hit and run and divide and conquer tactic, consider creating a limited number of real email addresses that you designate for non-important matters and can close whenever you want. Managing too many at once would be overwhelming, so it's best to keep the count reasonable.</p>
<p>Alongside these disposable addresses, maintain a couple of email accounts for official communications. It's also a good idea to switch up your official email address from time to time for added security.</p>
<p>However, there is a serious downside to using this. It is time-consuming, you have a potential loss of information, and it gets complex very fast. Not to forget you get a reputation risk. Some service providers may view frequently changing email addresses as a sign of suspicious activity, potentially leading to account restrictions or limitations.</p>
<p>I won't pursue this option: I do not want to be seen as a criminal and most of all, it just takes too much time and management.</p>
<h2 id="heading-force-amplified-enhancing-powers-with-a-galactic-plus">Force Amplified: Enhancing Powers with a Galactic Plus</h2>
<p>For your convenience, I quote Wikipedia on this one:</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Email_address#Subaddressing"><code>Some mail services support a tag included in the local-part, such that the address is an alias to a prefix of the local part. For example, the address joeuser+tag@example.com denotes the same delivery address as joeuser@example.com. RFC 5233,&lt;sup&gt;[15]&lt;/sup&gt; refers to this convention as subaddressing, but it is also known as plus addressing, tagged addressing or mail extensions.</code></a></p>
<p>So how can you use this?</p>
<ul>
<li><p>For <a target="_blank" href="https://support.google.com/mail/answer/22370?hl=nl#zippy=%2Cfilteren-met-je-gmail-alias">Gmail</a>, <a target="_blank" href="https://www.ghacks.net/2013/09/17/can-now-use-email-aliases-outlook-com/">Hotmail, Outlook,</a> this is supported!</p>
</li>
<li><p>For your company, when using <a target="_blank" href="https://learn.microsoft.com/en-us/exchange/recipients-in-exchange-online/plus-addressing-in-exchange-online">Exchange</a>, you can use it as well. e.g. <code>john.doe+1234@company.com</code></p>
</li>
</ul>
<p>Great, you can now leave a valid personal email address at that company! While this is a great feature to help you filter your email inbox, not all companies are keen on this.</p>
<p>Email addresses with a plus sign are sometimes mistakenly deemed invalid. A company might quietly remove the part after the plus sign and use your actual email address instead. It's not surprising at all. When companies offer promotions like "Sign up and get a 5% discount when subscribing to our newsletter," they might want to verify whether the provided email address is associated with an existing customer. This allows them to better track and understand their customer base, as well as tailor their marketing efforts to target the right audience.</p>
<p>The act of "sub-addressing an email" will not help you when your data is leaked as well. A malicious actor could extract your real email address and use it for spam/phishing campaigns or link it to other data breaches. <a target="_blank" href="https://regex101.com/r/cHRjt9/1">The regex is fairly easy.</a></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">string</span> pattern = <span class="hljs-string">@"^([\w\.\-]+)(?:\+[\w\.\-]+)?(@\w+(?:\.[\w\-]+)+)$"</span>;
<span class="hljs-keyword">string</span> substitution = <span class="hljs-string">@"$1$2"</span>;
<span class="hljs-keyword">string</span> input = <span class="hljs-string">@"john.doe+1234@company.be"</span>;
RegexOptions options = RegexOptions.Multiline;
Regex regex = <span class="hljs-keyword">new</span> Regex(pattern, options);
<span class="hljs-keyword">string</span> result = regex.Replace(input, substitution);
</code></pre>
<p>Officially, you won't be able to reply from the subaddress. When you respond to an email sent to <a target="_blank" href="mailto:name+newsletter@gmail.com"><strong>name+newsletter@company.com</strong></a>, the reply will be sent from your main email address, <a target="_blank" href="mailto:name@gmail.com"><strong>name@company.com</strong></a>. However, some email providers like Gmail have an unsupported work-a-round. <a target="_blank" href="https://webapps.stackexchange.com/questions/3598/is-there-any-way-to-send-an-email-from-a-gmail-plus-address">Read here for more information</a>. The downside of this is that you need to do a manual action for each subaddress you want to send from.</p>
<p>Because it is fairly easy for criminals to still reach me when my data is leaked, I do not want to pursue this option. However, it is a good start.</p>
<h2 id="heading-harnessing-the-power-of-temporary-email">Harnessing the Power of Temporary Email</h2>
<p>Disposable email addresses are temporary, short-lived email accounts that provide a convenient solution for situations where you need a temporary or throwaway email address. These addresses are particularly useful for signing up for newsletters, online services, or websites that require email verification but may result in unwanted email traffic or spam.</p>
<p>They offer a quick and easy way to create a temporary email address with a short lifespan, ranging from a few minutes to several hours. Once the designated time has passed, the email address is automatically deleted, along with any emails that were received.</p>
<p>How does it work? Fairly easy, you surf to a provider like <a target="_blank" href="https://temp-mail.org/">temp-mail.org</a> and you got an inbox. You have an email assigned to you.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680424869342/6628b30d-0843-49a0-baf7-ab9f3f7e72a0.png" alt class="image--center mx-auto" /></p>
<p>There are apps as well to use on your smartphones. How that can come into play, I do not know yet.</p>
<p>Some websites and services may block disposable email addresses, as they are often associated with spam or fraudulent activities as well. <a target="_blank" href="https://temp-mail.org/blog/temporary-email-with-private-domains-guide-2021/">Temp-mail.org has a solution tough to help you create short-lived email addresses using your domain name.</a></p>
<p>However, due to verification that can be happening to through what hoops the mail has been sent, you do not want your good own personal domain to be blacklisted by others. But this can give you an insight into how criminals do this tough.</p>
<p>I will not pursue this option completely for important activities.</p>
<h2 id="heading-the-galactic-relay-mastering-alias-email-forwarding">The Galactic Relay: Mastering Alias Email Forwarding</h2>
<p>Some services aim to protect users' email privacy by masking their real email addresses. This is done by giving an alias.</p>
<p>I will mention two services: SimplyLogin and Apple's "Hide My Email". These services offer privacy-focused features designed to protect users' email addresses and reduce spam.</p>
<ol>
<li><p><a target="_blank" href="https://simplelogin.io/docs/">SimplyLogin</a>: I quote their site: <code>SimpleLogin is an</code> <a target="_blank" href="https://github.com/simple-login"><code>open source</code></a> <code>email aliasing service that allows you to receive and send emails anonymously. Based in France, SimpleLogin has helped 50,000+ people protect their mailboxes against spams, phishing and data breaches.</code></p>
</li>
<li><p><a target="_blank" href="https://support.apple.com/en-gb/guide/mac-help/mchle62f7f45/mac#:~:text=On%20your%20Mac%2C%20choose%20Apple,ID%20or%20to%20create%20one.&amp;text=Click%20iCloud%20on%20the%20right,may%20need%20to%20scroll%20down.">Hide My Email by Apple</a>): I quote their site: <code>With Hide My Email, you can generate unique, random email addresses that forward to your personal email account, so you don’t have to share your real email address when filling out a form on the web or signing up for a newsletter. You can choose to forward emails to your iCloud Mail address or any email address associated with your</code> <a target="_blank" href="https://support.apple.com/en-gb/guide/mac-help/aside/glosbdc8e694/13.0/mac/13.0"><code>Apple ID</code></a><code>.</code></p>
</li>
</ol>
<p>For the customers of Apple: you have a built-in way. I am not using that ecosystem.</p>
<p>There are other services as well, like <a target="_blank" href="https://relay.firefox.com/">Firefox relay</a>.</p>
<p>SimplyLogin integrates with Gmail, Outlook and others... while Firefox Relay, on the other hand, is a standalone service that requires a separate browser extension to use. The upside is that Firefox Relay is completely free to use. SimplyLogin has a free plan, but does not seem to fit my needs. For me, the most important integration at this time is that Bitwarden also integrates with SimplyLogin for generating email aliases.</p>
<p>What I do like about the features that SimplyLogin offers is custom domain support, catch-all inboxes, and email forwarding. Firefox Relay seem to focus primarily on the core functionality of generating aliases.</p>
<p>SimplyLogin offers mobile apps for both Android and iOS. Firefox Relay currently only supports desktop browsers.</p>
<p>Both Firefox and SimplyLogin have a great reputation when it comes down to privacy and security because <a target="_blank" href="https://foundation.mozilla.org/en/privacynotincluded/">Firefox is created by Mozilla</a> and SimplyLogin is bought by <a target="_blank" href="https://proton.me/blog/privacy-news">Proton AG</a>.</p>
<h1 id="heading-outro">Outro</h1>
<p>If you want to read more about Email Privacy, I encourage you to read <a target="_blank" href="https://www.reddit.com/r/emailprivacy/wiki/index/#wiki_no_pre-registration_required">EmailPrivacy on Reddit</a>.</p>
<p>In my upcoming blog post, I'll be sharing my journey with SimplyLogin and a custom domain. The quest for online privacy can be overwhelming, and sometimes it feels like we're battling against an empire of companies. But like a Jedi, we must never give up our search for the right tools to protect ourselves. With SimplyLogin, I hope to have found a way to strike a blow against the dark side of data collection and have a quieter life in the digital galaxy.</p>
]]></content:encoded></item><item><title><![CDATA[The hidden dangers of JSONs: Hunger silenced]]></title><description><![CDATA[Previously on...
In my previous blog post, I wrote about deserialization attacks and how to prevent them. I ended the post with a section called Hunger. There I stated I still doubted the link between JSON inside a string property and when the valida...]]></description><link>https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced</link><guid isPermaLink="true">https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced</guid><category><![CDATA[json]]></category><category><![CDATA[Security]]></category><category><![CDATA[SAST]]></category><category><![CDATA[Validation]]></category><category><![CDATA[pentesting]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 26 Mar 2023 08:20:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/L4cXljG4f-g/upload/97f46315ee363be897264a31f8eccf3f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-json">In my previous blog post</a>, I wrote about deserialization attacks and how to prevent them. I ended the post with a section called Hunger. There I stated I still doubted the link between JSON inside a string property and when the validation attributes are triggered.</p>
<h1 id="heading-context">Context</h1>
<p>The SAST (Static Application Security Testing)-squad informed us that the problem was not resolved. The property validation using data annotations didn't silence the SAST scan. The software informed us that the property still flowed from one end to the other without any sanitization occurring. Both my colleague and I were genuinely frustrated. We added the data validation attributes...</p>
<p>The security team gave us the <a target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp">OWASP's cheat sheet</a>. Our code followed everything it mentioned, except for <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to?pivots=dotnet-6-0">whitelisting objects before conversion</a>. I was flabbergasted. I hadn't done this in the other projects, so what was the distinction?</p>
<p>We went on to implement a custom JSON converter using System.Text.Json, which first checks if the model to be deserialized is known.</p>
<p>Since the tool kept complaining about the property flow, we opted for AutoMapper instead of some code that maps one object to another. Additionally, we employed dependency injection to inject validators and utilized data annotations on the model. This approach aligned more closely with the existing code of the other projects</p>
<p>In all honesty, I believe the static tool scan just can't handle validation attributes, an AutoMapper and dependency injection.</p>
<p>The security team planned to examine our whitelisting usage and close the issue.</p>
<p>Naturally, being me, I couldn't just be content and let it be. I felt compelled to share my findings in this post.</p>
<h1 id="heading-did-you-know">Did you know...</h1>
<ul>
<li><p>The word "<a target="_blank" href="https://www.etymonline.com/word/serial?ref=etymonline_crossreference">serialization</a>" originated from the Latin word "seriēs," which means "a sequence or succession." It is used in computer science to refer to the process of converting an object into a sequence of bytes or characters so that it can be stored, transmitted or reconstructed later. The term "<a target="_blank" href="https://en.wikipedia.org/wiki/Serialization">serialization</a>" is used because the process involves converting an object's internal state into a serial sequence of data that can be read or written in sequence.</p>
</li>
<li><p>The term "deserialization" is a logical extension of "serialization," which refers to the process of converting a programming object or structure into a format that can be transmitted over a network or stored in a file</p>
</li>
<li><p>SAST stands for Static Application Security Testing. It is a security testing methodology used to analyze the source code, bytecode, or binary code of an application to identify potential security vulnerabilities. SAST tools scan the code without executing the application, providing an efficient way to detect issues early in the development process.</p>
</li>
</ul>
<h1 id="heading-the-attack-of-the-jsons">The attack of the JSONs.</h1>
<p>While conducting my research, I felt compelled to test out this kind of attack on a personal web API project I had created for demonstration purposes.</p>
<p>I stumbled upon the following sources as I delved into researching deserialization attacks targeting both the body and the authorization header.</p>
<ul>
<li><p><a target="_blank" href="https://www.reddit.com/r/dotnet/comments/6q1p99/friday_the_13th_json_attacks_remote_code/">Reddit - Dive into anything</a>: In this source, you'll find a link to a presentation by hackers, where they discuss how they discovered the vulnerabilities.</p>
</li>
<li><p><a target="_blank" href="https://blog.pentesteracademy.com/hacking-jwt-tokens-bruteforcing-weak-signing-key-jwt-cracker-5d49d34c44">Hacking JWT Tokens: Bruteforcing Weak Signing Key (JWT-Cracker) | by Shivam Bathla | Pentester Academy Blog</a>: An excellent read that demonstrates the importance of employing an RSA method for validating your tokens.</p>
</li>
<li><p><a target="_blank" href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/">Critical vulnerabilities in JSON Web Token libraries (</a><a target="_blank" href="http://auth0.com">auth0.com</a>: A valuable read from Auth0, covering various vulnerabilities associated with JSON Web Tokens.</p>
</li>
</ul>
<h1 id="heading-the-head-and-body-by-a-mermaid">The head and body by a Mermaid.</h1>
<p>In the section titled "AuthorizationHeader," you'll discover a brief overview highlighting the significance of signature validation. Meanwhile, in the "Body" section, you'll learn about the process after JSON has been deserialized, and how data annotations won't be of assistance in that scenario.</p>
<h2 id="heading-authorizationheader">AuthorizationHeader</h2>
<p>Since JWT is also in JSON format, it's crucial to ensure that your configuration is set up correctly. If not, the same attack could be applied to a JWT. Having a robust method for signing your token is of paramount importance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679770576278/0583e8b2-3dd7-4a8a-a990-29904ccec901.png" alt class="image--center mx-auto" /></p>
<p>If you permit an embedded certificate or certificate location, use a weak symmetric key, or have no key at all, you must exercise caution, as attackers can exploit these vulnerabilities. Attackers may impersonate another identity, or, if an outdated serializer is active, they could even carry out an RCE (Remote Code Execution) attack.</p>
<p>Keep in mind that once the signature is verified, the payload can be considered trustworthy.</p>
<h2 id="heading-from-body">From Body</h2>
<p>After conducting some research, I struggled to find a reliable source that explains the process of transitioning from an HTTP request to an HTTP response. However, by setting breakpoints, I managed to create the following sequence diagram to illustrate the process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679774990486/b9de11b3-e4a5-4b37-bb43-937e7ec93d5f.png" alt class="image--center mx-auto" /></p>
<p>When you create a custom validation attribute and examine the stack trace, you'll see the validation context upon opening it. You'll notice that an object instance is already present. This serves as clear evidence that attribute validation takes place on the object model. That means that the deserialization process takes place first.</p>
<p>To safeguard your server from a JSON attack, this point in the process is too late.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679772690773/84a9f958-6ef5-4a9e-a228-db04e19930a9.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-whitelist-your-models">Whitelist your models</h3>
<p>To protect yourself from unexpected models, whitelist your models in a custom json serialser.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
...   
 builder.Services.AddControllers()
        .AddMvcOptions(options =&gt;
        {
          <span class="hljs-comment">//Only allowd types for the input can be allowed</span>
            <span class="hljs-keyword">var</span> jsonInputFormatter =
                (SystemTextJsonInputFormatter)options.InputFormatters.First(f =&gt;
                    f.GetType() == <span class="hljs-keyword">typeof</span>(SystemTextJsonInputFormatter));
            options.InputFormatters.Clear();
            options.InputFormatters.Add(jsonInputFormatter);

            jsonInputFormatter.SerializerOptions.Converters.Add(
                <span class="hljs-keyword">new</span> WhitelistJsonConverter(AllowedTypesForDeserialisation.AllowedTypes));
        });
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> System;
<span class="hljs-keyword">using</span> System.Linq;
<span class="hljs-keyword">using</span> System.Text.Json;
<span class="hljs-keyword">using</span> System.Text.Json.Serialization;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WhitelistJsonConverter</span> : <span class="hljs-title">JsonConverterFactory</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Type[] _allowedTypes;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WhitelistJsonConverter</span>(<span class="hljs-params"><span class="hljs-keyword">params</span> Type[] allowedTypes</span>)</span>{
        _allowedTypes = allowedTypes;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">CanConvert</span>(<span class="hljs-params">Type typeToConvert</span>)</span> {
        <span class="hljs-keyword">return</span> Array.Exists(_allowedTypes, type =&gt; type == typeToConvert);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> JsonConverter <span class="hljs-title">CreateConverter</span>(<span class="hljs-params">Type typeToConvert, JsonSerializerOptions originalOptions</span>)</span>
    {
        <span class="hljs-keyword">var</span> optionsWithoutThisConverter = <span class="hljs-keyword">new</span> JsonSerializerOptions(originalOptions);
        optionsWithoutThisConverter.Converters.Remove(<span class="hljs-keyword">this</span>);

        <span class="hljs-keyword">var</span> converterType = <span class="hljs-keyword">typeof</span>(WhitelistJsonConverterInner&lt;&gt;).MakeGenericType(typeToConvert);
        <span class="hljs-keyword">return</span> (JsonConverter)Activator.CreateInstance(converterType, <span class="hljs-keyword">new</span> <span class="hljs-keyword">object</span>[] { optionsWithoutThisConverter });
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WhitelistJsonConverterInner</span>&lt;<span class="hljs-title">T</span>&gt; : <span class="hljs-title">JsonConverter</span>&lt;<span class="hljs-title">T</span>&gt;{
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> JsonSerializerOptions _options;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WhitelistJsonConverterInner</span>(<span class="hljs-params">JsonSerializerOptions originalOptions</span>)</span>{
            _options = <span class="hljs-keyword">new</span> JsonSerializerOptions(originalOptions);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> T <span class="hljs-title">Read</span>(<span class="hljs-params"><span class="hljs-keyword">ref</span> Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options</span>)</span>{
            <span class="hljs-keyword">return</span> JsonSerializer.Deserialize&lt;T&gt;(<span class="hljs-keyword">ref</span> reader, _options);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Write</span>(<span class="hljs-params">Utf8JsonWriter writer, T <span class="hljs-keyword">value</span>, JsonSerializerOptions options</span>)</span>{
            JsonSerializer.Serialize(writer, <span class="hljs-keyword">value</span>, _options);
        }
    }
}
</code></pre>
<p>However, just whitelisting your models for the <code>JsonSerialiser</code> is not enough. Sanitizing input in your REST API can protect it from some attacks. That may not be enough. A string property containing a malicious JSON object could be passed to another module or server in the chain, resulting in bad things happening downstream. This is similar to a SQL injection attack, which doesn't happen on the API, but on the database. It's important to always sanitize your input to prevent attacks at any point in the chain.</p>
<h1 id="heading-do-or-do-not-there-is-no-try">Do or do not. There is no try...</h1>
<p>I experimented with three different approaches in a custom project, but none seemed to work. I'll outline the JSONs I used. The <code>System.Text.Json</code> package doesn't offer a feature like <code>Newtonsoft.Json</code>, which uses the <code>$type</code> property to inform the code about the object that should be constructed. This is why I used Newtonsoft.Json in my attempt.</p>
<h2 id="heading-authorization-header">Authorization Header</h2>
<p>The following JSONs show a possibility of how an attacker can try to execute a remote process. I converted this to a signed JWT.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"sub"</span>: <span class="hljs-string">"1234567890"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
  <span class="hljs-attr">"iat"</span>: <span class="hljs-number">1516239022</span>,
  <span class="hljs-attr">"exp"</span>: <span class="hljs-number">1616239022</span>,
  <span class="hljs-attr">"process"</span>: {
    <span class="hljs-attr">"$type"</span>: <span class="hljs-string">"System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"</span>,
    <span class="hljs-attr">"StartInfo"</span>: {
      <span class="hljs-attr">"FileName"</span>: <span class="hljs-string">"cmd.exe"</span>,
      <span class="hljs-attr">"Arguments"</span>: <span class="hljs-string">"/c calc.exe"</span>,
      <span class="hljs-attr">"CreateNoWindow"</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">"UseShellExecute"</span>: <span class="hljs-literal">false</span>
    }
  }
}
</code></pre>
<p>The above translates into a JWT. I censored the JWT, but the payload is the same.</p>
<pre><code class="lang-json">eyJh***.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE2MTYyMzkwMjIsInByb2Nlc3MiOnsiJHR5cGUiOiJTeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcywgU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhIiwiU3RhcnRJbmZvIjp7IkZpbGVOYW1lIjoiY21kLmV4ZSIsIkFyZ3VtZW50cyI6Ii9jIGNhbGMuZXhlIiwiQ3JlYXRlTm9XaW5kb3ciOnRydWUsIlVzZVNoZWxsRXhlY3V0ZSI6ZmFsc2V9fX0.jDT3u***
</code></pre>
<h2 id="heading-body">Body</h2>
<p>The following JSON is the Json I used to try to create a file test.txt with the content test.</p>
<pre><code class="lang-json">{ <span class="hljs-attr">"minMaxTempC"</span>: { <span class="hljs-attr">"min"</span>: <span class="hljs-number">-1</span>, <span class="hljs-attr">"max"</span>: <span class="hljs-number">2</span> }, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"crazy"</span>, <span class="hljs-attr">"$type"</span>: <span class="hljs-string">"System.Diagnostics.Process, System.Diagnostics"</span>, <span class="hljs-attr">"StartInfo"</span>: { <span class="hljs-attr">"FileName"</span>: <span class="hljs-string">"cmd.exe"</span>, <span class="hljs-attr">"Arguments"</span>: <span class="hljs-string">"test &gt; test.txt"</span>, <span class="hljs-attr">"RedirectStandardOutput"</span>: <span class="hljs-literal">true</span> } }
</code></pre>
<p>Because the model was not the one that the server expected, I got bad requests. So I ensured that it had the same properties as the model.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">TemperatureCelciusBucket</span>(<span class="hljs-params">TempCRange minMaxTempC, <span class="hljs-keyword">string</span> Name</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> record <span class="hljs-title">TempCRange</span>(<span class="hljs-params"><span class="hljs-keyword">double</span> Min, <span class="hljs-keyword">double</span> Max</span>)</span>;
</code></pre>
<p>In the <code>JsonSerialiserSettingsProvider,</code> you can notice the following comment about the type handling issue.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679773998558/eb37e6da-dd4d-4a90-abd7-a58e8409b11d.png" alt class="image--center mx-auto" /></p>
<p>You need to set up your program to set the <code>TypeNameHandling</code> to <code>All</code> to ensure the attack could be done. Note, you want to set it to <code>None</code> when you try to protect yourself against an attack.</p>
<pre><code class="lang-csharp">builder.Services.AddControllers().AddNewtonsoftJson(options =&gt;
{
    options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
    options.SerializerSettings.ContractResolver = <span class="hljs-keyword">new</span> DefaultContractResolver();
});
</code></pre>
<p>On the website of JSON.NET, for that property and option, you do not get that warning. Check it out for yourself:</p>
<p><a target="_blank" href="https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm">TypeNameHandling Enumeration (</a><a target="_blank" href="http://newtonsoft.com">newtonsoft.com</a><a target="_blank" href="https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm">)</a></p>
<p>They do mention that is a good practice to whitelist the objects that you want to use, which is also recommended by <a target="_blank" href="https://www.linkedin.com/posts/cybersecricki_i-will-be-bringing-some-freshly-delivered-activity-7043002593966522368-9mFL/">OWASP</a>.</p>
<h1 id="heading-outro">Outro</h1>
<p>In my earlier post, I suggested using some sort of middleware to assist with JSON deserialization; however, this is an inefficient approach. Instead, it's better to add a custom converter and whitelist it from there. This way, you'll utilize the existing middleware and adhere to the Open/Closed principle from the SOLID pattern.</p>
<p>All my approaches seem to have failed to execute such an attack. I want to stress though that I am not a pentester. It seemed fun to try out this attack because it seemed simple enough. I sat on my peak of "Mount Stupid".</p>
<p><a target="_blank" href="https://understandinginnovation.blog/2015/07/03/the-dunning-kruger-effect-in-innovation/"><img src="https://understandinginnovation.files.wordpress.com/2015/06/dunning-kruger-0011.jpg" alt="The Dunning-Kruger effect in innovation – understanding ..." /></a></p>
<p>The JSON.NET nuget-package that I have consumed, seems to have scars. Such an attack can now be mitigated. It is a whole new world that opens and I am liking it.</p>
<p>I recently came across a fitting T-shirt, invented by <a target="_blank" href="https://www.linkedin.com/posts/cybersecricki_i-will-be-bringing-some-freshly-delivered-activity-7043002593966522368-9mFL/"><strong>Ricki Burke</strong> on LinkedIn</a> that encapsulates the importance of security.</p>
<p><img src="https://media.licdn.com/dms/image/C5622AQHDe9YOhXXTXQ/feedshare-shrink_1280/0/1679182669921?e=1682553600&amp;v=beta&amp;t=7ZgafBGhdupr6okYSJD65g2IGQpJu_Ef6u238dq9Ph8" alt="No alternative text description for this image" /></p>
<p>Needless to say, I want one of those :)</p>
]]></content:encoded></item><item><title><![CDATA[The Hidden Dangers of JSON]]></title><description><![CDATA[Previously on...
I will take a brief pause from my series on securing and reclaiming control of personal data. To give a little spoiler, it is about using the tool SimpleLogin | Open source anonymous email service.
In previous posts, I mentioned that...]]></description><link>https://dotnet.kriebbels.me/the-hidden-dangers-of-json</link><guid isPermaLink="true">https://dotnet.kriebbels.me/the-hidden-dangers-of-json</guid><category><![CDATA[json]]></category><category><![CDATA[Security]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[hacker]]></category><category><![CDATA[owasp]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 19 Mar 2023 11:17:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HfFoo4d061A/upload/27fb428173a8687da9ebf22339d2167c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>I will take a brief pause from my series on securing and reclaiming control of personal data. To give a little spoiler, it is about using the tool <a target="_blank" href="https://simplelogin.io/">SimpleLogin | Open source anonymous email service</a>.</p>
<p>In previous posts, I mentioned that a white-hat hacker demonstrated their methods of gaining unauthorized access. This was on Azure Cloudbrew. That person states that hackers behave much like little bunnies, hopping between computers and servers while accumulating tiny bits of crucial information. They discreetly gather details such as client IDs, technologies in use (e.g., JSON, <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core), and the versions of installed DLLs. Those hackers gradually acquire a better understanding of what they can accomplish. Once armed with enough knowledge, they can orchestrate a full-scale attack.</p>
<p>Let us zoom in on what a hacker can do with a JSON deserialization attack.</p>
<h1 id="heading-context">Context</h1>
<p>I recently helped a colleague tackle a problem where input validation was missing. There was no distinct separation between layers when processing an HTTP request and initiating a follow-up request.</p>
<p>After reviewing the initial security report and researching the vulnerability online, we have taken the follow actions:</p>
<ul>
<li><p>implemented layer separation,</p>
</li>
<li><p>updated Swagger's JSON serializer to have no type handling,</p>
</li>
<li><p>and added some validation checks.</p>
</li>
</ul>
<p>I thought we were making progress, but due to ambiguous requirements, only a "string.IsNullOrEmpty" check was conducted.</p>
<p>The second security report still indicated that the property was transferred from input to output without any validation checks. I did not understand the problem. I researched the vulnerabilities but did not came across this problem. The security team firmly declared that such code would not be permitted in production.</p>
<p>When I sought more information about the security scan and its purpose, the team responded vaguely, saying it was simple and referring to a particular line in the report. However, when I requested specific guidance on addressing the issue and pinpointing the vulnerabilities detected by the tool, the conversation became tense and defensive. I had to remind people that I also find security important. I do not want to discuss if the report is wrong or not. I admitted I didn't fully understand the attack mentioned concerning possible JSON in a string property. This has nothing to do with the importance of validation of the input.</p>
<p>Ultimately, the developers in that meeting determined that using RegEx validation on the properties of the Models that <a target="_blank" href="http://ASP.NET">ASP.NET</a> Core processes and deserializes was the way to go. At least, we will discover that after the security scan runs again. That will take two days before we know if that will fix the result.</p>
<p>After that meeting, I talked with another coworker. We agreed that simulating the attack was the optimal strategy for better understanding the issue.</p>
<h1 id="heading-the-journey-starts">The journey starts</h1>
<p>After googling a bit a round, I came to a very intresting magazine called <a target="_blank" href="https://pentestmag.com/magazines/">Pentestmag</a>.</p>
<p>There I have a step-by-step example of how I can recreate the problem. However, they make use of tools that I am not familiar with yet. Let us take a step back. First I need to know what the vulnerability is all about. OWASP seems a good source for that. The vulnerability is listed here: <a target="_blank" href="https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization">OWASP Top Ten 2017 | A8:2017-Insecure Deserialization | OWASP Foundation</a> to stress the problem, I make a copy from that website for your easy reading:</p>
<p><code>The impact of deserialization flaws cannot be overstated. These flaws can lead to remote code execution attacks, one of the most serious attacks possible. The business impact depends on the protection needs of the application and data.</code></p>
<h2 id="heading-owasp">OWASP</h2>
<p>OWASP have a sheet cheat for all kind of technologies and vulnerabilities. You can find that on this location: <a target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html">Deserialization - OWASP Cheat Sheet Series</a>.</p>
<p>After reading the sheet cheat, I can not help but figure out that I should just not use JSON at all. The plot thickens when they link to YsoSerial.net. YsoSerial.Net is a tool designed to generate and analyze payloads for .NET applications that are vulnerable to deserialization attacks.</p>
<h2 id="heading-ysoserialnet">YsoSerial.Net</h2>
<p>For the reader, I will make copy and paste the introduction on what YsoSerial.Net is:</p>
<p><a target="_blank" href="http://ysoserial.net"><code>ysoserial.net</code></a> <code>is a collection of utilities and property-oriented programming "gadget chains" discovered in common .NET libraries that can, under the right conditions, exploit .NET applications performing unsafe deserialization of objects. The main driver program takes a user-specified command and wraps it in the user-specified gadget chain, then serializes these objects to stdout. When an application with the required gadgets on the classpath unsafely deserializes this data, the chain will automatically be invoked and cause the command to be executed on the application host.</code></p>
<p>For a person that is just trying to create a sample project about deserialisation hacks, I need to understand first what the text above really means. They talk about gadgets. What have small physical devices have to do with JSON?</p>
<h3 id="heading-what-are-the-gadgets-they-talk-about">What are the gadgets they talk about?</h3>
<p>The term "gadget" is confusing for someone like me. I am not familiar with computer security on that level yet. The word "gadget" is often used to describe small, innovative devices or tools in everyday life. However, the underlying concept of a "gadget" is a versatile, reusable, and adaptable component without injecting any code into memory. A gadget is a small piece of reusable code that can be leveraged to create an exploit. Gadget chaining is then reusing a lot of small pieces, executing after each other. That is used in ROP (Return-Oriented Programming)</p>
<h3 id="heading-down-the-rabbit-hole-we-go-what-is-rop-now">Down the rabbit hole, we go... What is ROP now?</h3>
<p>Return-Oriented Programming (ROP) is an advanced exploitation technique used by attackers to bypass security mechanisms, such as non-executable memory protections (e.g., DEP or Data Execution Prevention). ROP allows an attacker to execute arbitrary code without injecting any new code into the target process or system. Instead, ROP relies on reusing existing code sequences, called "gadgets," that are already present in the memory of the target program or system libraries. Hence the word "gadget chaining".</p>
<h2 id="heading-getting-out-of-the-rabbit-hole-and-into-the-next">Getting out of the rabbit hole and into the next.</h2>
<p>Let us go back to the magazine and after some good keyword searching using Google, I came to a <a target="_blank" href="https://pentestmag.com/insecure-deserialization-with-json-net/">blogpost</a> that gives us a beautiful showcase of how dangerous JSON can be. Let me give you a summary before you hop over to see what is happening.</p>
<p>First of all, the author describes insecure deserialization as a critical vulnerability in the OWASP Top 10 list, which can lead to issues like denial-of-service attacks, authentication bypasses, and arbitrary code execution.</p>
<p>In the blog post by Nairuz Abulhul, Nairuz demonstrates exploiting insecure deserialization in a .NET application using JSON. Nairuz uses <a target="_blank" href="https://portswigger.net/burp">Burp Suite</a>. That can be used for manual <a target="_blank" href="https://en.wikipedia.org/wiki/Fuzzing">fuzzing</a>. This means generating error messages to see how the application will react. <a target="_blank" href="https://www.linkedin.com/posts/michaelcontento_mutation-testing-und-fuzzing-in-c-basta-activity-7025826515657334784-P3Ob?utm_source=share&amp;utm_medium=member_desktop">I learned about Fuzzing on an innovation day at Xebia | Xpirit</a>. Big shout out to <a target="_blank" href="https://www.linkedin.com/in/michaelcontento/">(6) Michael Contento | LinkedIn</a> who introduced me to this topic.</p>
<p>Through testing, Nairuzidentifies that the Bearer token, which is part of the OAuth 2.0 authorization framework, is the vulnerable parameter. To exploit this vulnerability, <a target="_blank" href="http://ysoserial.net">ysoserial.net</a> is used. As a result, she can do a remote code execution attack, compromising the target machine. To prevent such attacks, the author recommends avoiding serialization if possible, using digital signatures like HMAC to ensure data integrity, and always validating and sanitizing user input before serialization.</p>
<h3 id="heading-but-my-code-runs-in-azure">But my code runs in Azure...</h3>
<p>One of my thoughts was that Azure is secured in a manner, <a target="_blank" href="https://www.onmsft.com/news/microsoft-announces-new-azure-security-lab-challenges-researchers-to-hack-azure/">that Fort Knox would be jealous</a> of... After a little bit of searching, I came across a site called <a target="_blank" href="https://cloud.hacktricks.xyz/">https://cloud.hacktricks.xyz/</a>. Once your browse a bit through the site, you notice a section dedicated to <a target="_blank" href="https://cloud.hacktricks.xyz/pentesting-cloud/azure-pentesting">Azure</a>.</p>
<p>Searching for a bit more on this topic, <a target="_blank" href="https://www.alphabot.com/security/blog/2017/net/How-to-configure-Json.NET-to-create-a-vulnerable-web-API.html">you find a blog post that explains how to create a file on the Azure WebApp</a> by having code executed by the JsonDeserialiser.</p>
<h1 id="heading-easy-fix">Easy fix?</h1>
<ol>
<li><p>Choose libraries that have built-in security mechanisms to prevent deserialization attacks. <a target="_blank" href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/overview">For example, the <code>System.Text.Json</code> library in .NET Core is considered safer than <code>Newtonsoft.Json</code></a>, as it doesn't support vulnerable deserialization features by default.</p>
</li>
<li><p>Binary formatters, like <code>BinaryFormatter</code> and <code>NetDataContractSerializer</code>, can introduce security risks. Instead, use safer alternatives such as <code>DataContractJsonSerializer</code>, <code>XmlSerializer</code>, or <code>System.Text.Json</code>.</p>
</li>
<li><p>Restrict deserialization to specific types: If you have to use a library that supports type information during deserialization, restrict the deserialization process to a predefined set of known and safe types. For example, in <code>Newtonsoft.Json</code>, you can use the <code>TypeNameHandling</code> and <code>SerializationBinder</code> settings to control the deserialization process.</p>
</li>
</ol>
<h2 id="heading-show-me-code">Show me code</h2>
<p>I deleted the code that was in here. There is a better solution. I mentioned it on the follow up <a target="_blank" href="https://dotnet.kriebbels.me/the-hidden-dangers-of-jsons-hunger-silenced">blogpost</a>.</p>
<h2 id="heading-hunger">Hunger</h2>
<p>I am still not satisfied with my search for this vulnerability. It was stated by the security team that it is very important to validate your properties as well. I am not discussing that. But I want to understand what mechanisms are in play to abuse that. One thing that comes to mind is using <code>JsonConvert.DeserializeObject</code> method on a string property of the input object.</p>
<p>I am also not convinced yet, that adding validation on your properties using attributes will mitigate the problem. A good read for this would be the following article by Microsoft: <a target="_blank" href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/docs/ThreatModel.md">runtime/ThreatModel.md at main · dotnet/runtime · GitHub</a></p>
<h2 id="heading-outro">Outro</h2>
<p>I still need to search for time to play with this. I did not end up playing with creating the source code myself. However, I gained insight into how hackers can misuse JSON and even a security framework like OAuth2 to execute remote code. I have found some examples and sources that are clear enough to set my next baby steps.</p>
]]></content:encoded></item><item><title><![CDATA[Protect Your Digital Life: A Password Manager? Really?]]></title><description><![CDATA[Previously on...
I started this series when I got fed up with all those scam emails and sms. It is time to retake my digital data. In my previous post, I talked about 2FA and the weak link named "the user".
Context
Many websites require us to create ...]]></description><link>https://dotnet.kriebbels.me/protect-your-digital-life-a-password-manager-really</link><guid isPermaLink="true">https://dotnet.kriebbels.me/protect-your-digital-life-a-password-manager-really</guid><category><![CDATA[privacy]]></category><category><![CDATA[Security]]></category><category><![CDATA[Bitwarden]]></category><category><![CDATA[Keepass ]]></category><category><![CDATA[password manager]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 12 Mar 2023 08:05:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/r8VbpgMS6Uc/upload/9ed7a155fd94bfd0a21505a5eaf6c28a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p>I started this series <a target="_blank" href="https://dotnet.kriebbels.me/how-to-know-if-your-data-is-leaked">when I got fed up with all those scam emails and sms</a>. It is time to retake my digital data. In my <a target="_blank" href="https://dotnet.kriebbels.me/when-two-factor-authentication-is-useless">previous post</a>, I talked about 2FA and the weak link named "the user".</p>
<h1 id="heading-context">Context</h1>
<p>Many websites require us to create a login that includes various personal information such as a username, email, phone number, and sometimes even a <a target="_blank" href="https://authenticate.lnz.be/FederationSTS/Default.aspx?wa=wsignin1.0&amp;wtrealm=urn%3Asharepoint%3Anzvl.lnz.be&amp;wctx=https%3A//nzvl.lnz.be/_layouts/15/Authenticate.aspx%3FSource%3D%252F&amp;wreply=https%3A//nzvl.lnz.be/_trust/default.aspx">national registry number</a>. Initially, a lot of people used the same login credentials for multiple websites. As a result, the next step in the evolution of online security was to require passwords with more characters, making it more difficult for hackers to guess them through brute force methods. However, this was not enough, as many websites did not store passwords securely, resulting in data breaches where login credentials were exposed. Criminals could then use these compromised credentials on other websites until they gained access. Therefore, it has become increasingly important to use unique passwords for each website where you have an account. Password managers are software that helps to achieve this.</p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=aHaBH4LqGsI">I suggest watching Michael McIntyre's humorous video on passwords.</a></p>
<h1 id="heading-hackers-were-interested-only-in-our-credentials">Hackers were interested only in our credentials?</h1>
<p>Before personal information became a valuable commodity, gaining access to email accounts, online banking systems, and other platforms through stolen login credentials was a valuable goal for hackers.</p>
<p>By obtaining login credentials, hackers can access sensitive information such as financial data, personal communications, and confidential business information. In addition, login credentials can be used to carry out fraudulent activities such as identity theft, bank fraud, and phishing scams.</p>
<p>Moreover, with the rise of e-commerce and other online transactions, the value of personal information has also increased over time. Login credentials, combined with personal information like names, addresses, and social security numbers can be used for more advanced and sophisticated cyber attacks like spear phishing, social engineering attacks, and more.</p>
<h1 id="heading-password-managers">Password managers</h1>
<p>A password manager is a software application or tool that helps users generate, store, and manage their passwords securely. This eliminates the need for users to remember multiple complex passwords, making it easier to maintain good password hygiene and protect their online accounts from security breaches and hacking attempts. Password managers should encrypt your passwords and store them securely, making it much harder for hackers to access them.</p>
<p>However, there is a downside to this as well. Since your master password is the key to all of your stored passwords, if it is compromised, then all of your passwords are compromised. This is why it is crucial to choose a strong master password and to keep it secure. Because companies will do everything to protect your data... right? Oh, wait... <a target="_blank" href="https://www.businessinsider.com/stolen-data-of-533-million-facebook-users-leaked-online-2021-4?r=US&amp;IR=T">we all remember how Facebook uses and leaked our data</a>... Erm... Still, a password manager has its uses. It still protects us from criminals that could gain access to other websites and use that sensitive information to do more harm.</p>
<p>There are a lot of sites that give an overview of "password manager"-related data breaches. I started with this article: <a target="_blank" href="https://password-managers.bestreviews.net/faq/which-password-managers-have-been-hacked/">Which Password Managers Have Been Hacked? – Best Reviews</a></p>
<h1 id="heading-dedicated-or-browser">Dedicated or browser?</h1>
<p>Even if you do not explicitly choose a password manager, modern browsers like Firefox, Edge and Chrome offer to save your passwords. Browser-based password managers often have limited features compared to dedicated password manager apps. For example, they may not offer advanced security features such as two-factor authentication or password sharing.</p>
<ol>
<li><p>Cross-device syncing: While some browsers may offer cross-device syncing of passwords, this feature may not work as well as dedicated password managers. For example, you may have trouble syncing passwords across multiple devices or browsers.</p>
</li>
<li><p>Security risks: Browser-based password managers are still vulnerable to security risks, such as phishing attacks and data breaches. In addition, browser extensions can be a target for attackers who want to compromise your passwords.</p>
</li>
</ol>
<h2 id="heading-so-what-is-out-there">So what is out there?</h2>
<p>Other sites are better equipped to give you answers to the question of what good password managers are. Go visit <a target="_blank" href="https://www.passwordmanager.com/">passwordmanager.com</a>. But while you are here...</p>
<p>I'd like to draw attention to two open-source password managers: <a target="_blank" href="https://bitwarden.com/">Bitwarden</a> and <a target="_blank" href="https://keepass.info/">Keepass</a>. Both of these options are open source, with Bitwarden providing <a target="_blank" href="https://bitwarden.com/download/">a unified solution</a> for both Windows and mobile devices, while Keepass offers a more customizable experience, allowing you to pick and choose the features you desire from <a target="_blank" href="https://keepass.info/plugins.html">a wide array of available plugins.</a></p>
<p><a target="_blank" href="https://bitwarden.com/blog/new-deployment-option-for-self-hosting-bitwarden/">Bitwarden can be self-hosted if desired</a> using the new unified deployment that requires just one docker image. It adds a layer of protection in the event of a breach on their servers. Go ahead an play around with our free Azure credits each month. For the ones that want to make use of their Synology NAS, <a target="_blank" href="https://mariushosting.com/how-to-install-bitwarden-on-your-synology-nas/">there are good reads to find as well.</a> Do make sure that you take every precaution when you want to host a service and expose it to the internet. Another downside is that you need to update the software as well with the updates they provide.</p>
<p>Though it's worth noting that the service has yet to experience any data breaches and appears to have strong security measures in place. They had <a target="_blank" href="https://www.cvedetails.com/vulnerability-list/vendor_id-22468/Bitwarden.html">two vulnerabilities</a> that have been addressed. The pull requests are an interesting read: <a target="_blank" href="https://github.com/bitwarden/server/pull/827">CVE-2020-15879</a> and <a target="_blank" href="https://github.com/bitwarden/server/issues/589">CVE-2019-19766</a> . <a target="_blank" href="https://github.com/bitwarden/server/pull/827">CVE-2020-15879</a> was discovered by <a target="_blank" href="https://www.hackerone.com/">HackerOne</a>.</p>
<p>It is cool to note that Bitwarden also has <a target="_blank" href="https://bitwarden.com/help/public-api/">a public API</a>. If you want to integrate Bitwarden's password management and security features into your application or website. Just make sure your integration does not have any security risks...</p>
<p>While there have been <a target="_blank" href="https://www.cvedetails.com/vulnerability-list/vendor_id-12214/Keepass.html">some vulnerabilities</a> identified in Keepass, the tool's offline nature makes it a less attractive target for hackers seeking large amounts of valuable data to sell to malicious parties.</p>
<h1 id="heading-form-filling">Form filling</h1>
<p>While it's important to use unique passwords to limit the scope of a potential cyber attack, it's also important to remember that if personal data is stolen, it can be difficult to regain control of that information. Therefore, if possible, it's best to avoid storing personal data with the company or website in question. Instead, consider using the form-filling feature and opting for guest access when possible, to limit the amount of personal data that needs to be shared. There will be another post on the dangers of leaking data...</p>
<h1 id="heading-outro">Outro</h1>
<p>I did some research for this blog post and I am happy with my choice of using Bitwarden. However, the way that Chrome and Edge offer to fill in login prompts, gives a superior user experience than the way that Bitwarden offers. Not that Bitwarden's offers are bad, not at all. I am still in doubt so I use both of them. That is bad practice because my passwords are now out of sync and in two places. I need to make work of that.</p>
<p>The problem is not that I do not use a password manager... The problem is the leak at the companies where my data is stored. By using a password manager I can limit the risk that criminals can do something with my credentials. However, the criminals are not interested in only those credentials... Personal information is also leaked. That is the reason why I get scam emails and sms. I need to do more research on how to protect myself further.</p>
<p>For the persons that are still sceptical about what leaking personal information can do, <a target="_blank" href="https://www.standaard.be/cnt/dmf20230309_95135028">listen to this flemish podcast</a> (start at minute 20). To quote this <a target="_blank" href="https://www.thesun.co.uk/tech/20733191/whatsapp-scam-danger-avoid-how-warning/">source</a>: <code>It's the beginning of a con that involves tricking parents into thinking they're</code> <a target="_blank" href="https://www.thesun.co.uk/tech/17159706/parents-warned-whatsapp-scam-distressed/"><code>speaking to their children</code></a><code>.</code></p>
]]></content:encoded></item><item><title><![CDATA[When two-factor authentication is useless]]></title><description><![CDATA[Previously on...
In my previous post, I stated that I will begin a series that will give the reader insight into my journey of protecting my data. I summed up multiple subjects I want to explore. I already put my IoT devices on my guest network. But ...]]></description><link>https://dotnet.kriebbels.me/when-two-factor-authentication-is-useless</link><guid isPermaLink="true">https://dotnet.kriebbels.me/when-two-factor-authentication-is-useless</guid><category><![CDATA[privacy]]></category><category><![CDATA[Security]]></category><category><![CDATA[lastpass]]></category><category><![CDATA[databreach]]></category><category><![CDATA[2FA]]></category><dc:creator><![CDATA[Kristof Riebbels]]></dc:creator><pubDate>Sun, 05 Mar 2023 08:39:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/RMIsZlv8qv4/upload/ecff3864b50b2417a05b96c2cbb6665f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-previously-on">Previously on...</h1>
<p><a target="_blank" href="https://dotnet.kriebbels.me/how-to-know-if-your-data-is-leaked">In my previous post, I stated that I will begin a series that will give the reader insight into my journey of protecting my data</a>. I summed up multiple subjects I want to explore. I already put my IoT devices on my guest network. But that is for another post.</p>
<h1 id="heading-context">Context</h1>
<p>This week, it came to our ears in <a target="_blank" href="https://tweakers.net/nieuws/207282/lastpass-hack-gebruikte-plex-kwetsbaarheid-die-drie-jaar-geleden-al-was-gedicht.html">Tweakers.net</a>, <a target="_blank" href="https://www.tiktok.com/discover/lastpass">TikTok</a> and other sources that a data breach happened at the company LastPass. <a target="_blank" href="https://www.pcmag.com/news/lastpass-becomes-independent-firm-but-its-still-owned-by-private-equity">LastPass is a company that is owned by LogMeIn</a>. <a target="_blank" href="https://www.lastpass.com/">LastPass</a> has a product that is a password manager. A password manager should keep all of your passwords safe in a vault. In a follow-up post, I will write about the importance and dangers of password managers.</p>
<p><a target="_blank" href="https://www.pcmag.com/news/lastpass-employee-couldve-prevented-hack-with-a-software-update">A PCMag investigation</a> found that the senior DevOps programmer of LastPass installed malware, allowing hackers to record the victim's keystrokes and obtain the master password. LastPass recently revealed that hackers accessed its cloud backups through this programmer, gaining access to customer data.</p>
<p>This could have been avoided when the system was protected with two-factor authentication, right... right?</p>
<h1 id="heading-what-is-two-factor-authentication">What is two-factor authentication?</h1>
<p>Two-factor authentication (2FA) is a security process that requires a user to provide two forms of identification to access a system or application. The two factors of identification typically include something the user knows (such as a password or PIN) and something the user has (such as a physical token or a mobile device). By requiring two forms of identification, 2FA makes it more difficult for an attacker to gain unauthorized access to a system or application, even if they have obtained the user's password.</p>
<h2 id="heading-types-of-two-factor-authentication">Types of two-factor authentication</h2>
<p>By now you figured out that by enabling 2FA, you protect your login against password breaches. Even if a hacker knows your password, they won't be able to log in without the second factor of authentication. You have multiple forms of two-factor authentication.</p>
<ol>
<li><p>SMS Authentication: This involves sending a unique code to your phone via SMS, which you then enter into the website or app you're trying to access. While this method is convenient, it is not the most secure option, as hackers can intercept text messages, trick you into giving up the code, or even clone your phone number. Therefore, SMS authentication is not recommended for high-security scenarios.</p>
<p> <a target="_blank" href="https://www.pinterest.com/pin/in-a-world-where-technology-evolves-continually-to-serve-the-demands-of-the-consumer-the-bad-elemen--819795938417502106/"><img src="https://assets.biola.edu/4396738754672012438/embedded_image/5ba17c0041b16f00013e6d51/2_Step_Logo_Full.png" alt="Two-factor authentication (2FA) - SMS - OKRoute" class="image--center mx-auto" /></a></p>
</li>
<li><p>Authenticator Apps: Authenticator apps like Google Authenticator, Authy, and Microsoft Authenticator generate time-based one-time passwords (TOTP) that can be used as the second factor for authentication. These apps are more secure than SMS authentication since they don't rely on SMS, and the generated codes are unique and expire after a short time. However, if someone gains access to your phone or the authentication app itself, they can generate the codes and bypass the authentication. So, it's still important to protect your phone and authentication app with a strong password or PIN.</p>
<p> <a target="_blank" href="https://authy.com/guides/twilio/"><img src="https://authy.com/wp-content/uploads/TWILIO7.png" alt class="image--center mx-auto" /></a></p>
</li>
<li><p>Hardware Tokens: Hardware tokens are physical devices that generate one-time passwords or use public key cryptography to authenticate the user. They are more secure than SMS and authenticator apps because they are not vulnerable to online attacks or phishing. <a target="_blank" href="https://flow.gi/SecurIDReverseEngineering/">Even reverse engineering them is hard.</a> However, hardware tokens can be lost or stolen, and they may not be as convenient to carry around as a phone. <a target="_blank" href="https://www.wired.com/story/the-full-story-of-the-stunning-rsa-hack-can-finally-be-told/">In 2011, there was a data breach in one of those companies. The information was leaked on how those numbers could be generated. Every hardware token was vulnerable back then...</a></p>
<p> <a target="_blank" href="https://www.pinterest.com/pin/597008494328044958/"><img src="https://img3.exportersindia.com/product_images/bc-full/dir_184/5496627/security-token-1517377592-3618729.jpg" alt="Examples of security tokens" class="image--center mx-auto" /></a></p>
</li>
<li><p>Biometric Authentication: Biometric authentication uses physical characteristics like fingerprints, facial recognition, or iris scans to verify your identity. This method is more secure than the others since biometric features are unique to each individual and can't be easily replicated or stolen. However, biometric authentication is not foolproof, as there have been instances of <a target="_blank" href="https://bitrebels.com/business/how-hackers-bypass-fingerprint-scanners/">hackers bypassing fingerprint sensors</a> or using <a target="_blank" href="https://www.theregister.com/2022/05/22/ai_in_brief/">deep fake technology to trick facial recognition systems</a>.</p>
<p> <a target="_blank" href="https://www.spiceworks.com/it-security/identity-access-management/articles/what-is-biometric-authentication-definition-benefits-tools/"><img src="https://pimages.toolbox.com/wp-content/uploads/2021/02/28143323/Scanner.png" alt="What Is Biometric Authentication? Definition, Benefits, and Tools -  Spiceworks" /></a></p>
</li>
</ol>
<h2 id="heading-multiple-culprits-but-2fa-should-protect-you-right">Multiple culprits... but 2FA should protect you, right?</h2>
<p>Well, it all comes down to the user. LastPass has protected its vaults with 2FA. Only four seniors within the company have access to that vault. The hackers attempted to log in to the server using a keylogger. The 2FA protection they used, asked for approval. The senior developer approved the login, so the hackers were able to access the vault.</p>
<h1 id="heading-outro">Outro</h1>
<p>Security is only as strong as the people who use it. I have worked at some companies where usernames and passwords were shared among developers. One developer wants to access the vault. It is the responsible guard of the vault who approves the login. I suspect this was happening as well at LastPass. Otherwise, I cannot understand why the senior developer approved the login if he did not initiate it.</p>
<p>The whole internet is focused on the vulnerability of the software that was not patched, and there was no separation of home devices and work devices. If everything fails, we should be able to rely on our 2FA. Otherwise, what is the point of setting it up?</p>
<p>I do have issues with the strength of security sometimes. It holds you back and that is frustrating. The internet is a crowded place with a lot of people who want to do good. However, it's also filled with malicious actors who are constantly looking for ways to exploit vulnerabilities and gain unauthorized access to sensitive information. This is why companies need to prioritize security measures and implement the latest technology to protect themselves and their users. It may seem like an inconvenience, but in the end, it's better to err on the side of caution and take every possible step to ensure the safety of our online identities and data.</p>
]]></content:encoded></item></channel></rss>