<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dmitry</title>
    <description>The latest articles on DEV Community by Dmitry (@dbalikhin).</description>
    <link>https://dev.to/dbalikhin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F925876%2F5abce3a1-ab5b-48bd-a75f-d535e0a27660.png</url>
      <title>DEV Community: Dmitry</title>
      <link>https://dev.to/dbalikhin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dbalikhin"/>
    <language>en</language>
    <item>
      <title>Security analysis of a repository pattern and asking ChatGPT about it.</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Sat, 17 Dec 2022 03:05:59 +0000</pubDate>
      <link>https://dev.to/dbalikhin/security-analysis-of-a-repository-pattern-and-asking-chatgpt-about-it-30bj</link>
      <guid>https://dev.to/dbalikhin/security-analysis-of-a-repository-pattern-and-asking-chatgpt-about-it-30bj</guid>
      <description>&lt;p&gt;This week I discovered that SAST tools are struggling with a repository pattern.&lt;/p&gt;

&lt;p&gt;So, let's say we have an &lt;code&gt;IRepo&lt;/code&gt; interface with a single defined method.&lt;/p&gt;

&lt;p&gt;We have 2 implementations: &lt;code&gt;Repo&lt;/code&gt; and &lt;code&gt;DummyRepo&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IRepo&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoRepoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Repo&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRepo&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoRepoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;concatSql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM Accounts WHERE Username='"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' OR  Name='"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlConnection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dummyconnectionstring"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;SqlCommand&lt;/span&gt; &lt;span class="n"&gt;concatSqlCommand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;CommandText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;concatSql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;CommandType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CommandType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;

                &lt;span class="n"&gt;concatSqlCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DummyRepo&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRepo&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoRepoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We declare instances somewhere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IRepo&lt;/span&gt; &lt;span class="n"&gt;_repoVulnerable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IRepo&lt;/span&gt; &lt;span class="n"&gt;_repoDummy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DummyRepo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test case 1:&lt;/strong&gt; Let's call a vulnerable method &lt;code&gt;DoRepoStuff&lt;/code&gt; of &lt;code&gt;_repoVulnerable&lt;/code&gt; instance. Note, that it is &lt;code&gt;IRepo&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;SqlClientVulnerable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_repoVulnerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DoRepoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OkResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we found a security vulnerability - SQL Injection, right?&lt;br&gt;
Yes, but not all tools will report it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test case 2:&lt;/strong&gt; Let's call a safe method &lt;code&gt;DoRepoStuff&lt;/code&gt; of &lt;code&gt;_repoDummy&lt;/code&gt; instance. Note, that it is &lt;code&gt;IRepo&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;SqlClientDummySafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_repoDummy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DoRepoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OkResult&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should not have a problem here, but some security tools will report security vulnerability by following the &lt;code&gt;IRepo&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test case 3:&lt;/strong&gt;&lt;br&gt;
Declare &lt;code&gt;_repoVulnerable&lt;/code&gt; as &lt;code&gt;Repo&lt;/code&gt; and &lt;code&gt;_repoDummy&lt;/code&gt; as &lt;code&gt;DummyRepo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Repo&lt;/span&gt; &lt;span class="n"&gt;_repoVulnerable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DummyRepo&lt;/span&gt; &lt;span class="n"&gt;_repoDummy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DummyRepo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can help some tools to properly identify the true positive &lt;code&gt;_repoVulnerable&lt;/code&gt; and do not trigger safe &lt;code&gt;_repoDummy&lt;/code&gt; because no need to do a taint analysis by interface.&lt;/p&gt;

&lt;p&gt;I can try to group security tools by behaviour.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Following interface implementations and marking all invocations vulnerable&lt;br&gt;
1.1. If a tool displays only a single source, you may not see this behaviour&lt;br&gt;
1.2. If a tool displays all sources that lead to the sink, you will most likely get a security vulnerability for the &lt;code&gt;Dummy&lt;/code&gt; repo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not following interface&lt;br&gt;
2.1. Do not display anything - no findings&lt;br&gt;
2.2. Do not use Taint Analysis decreasing the confidence level.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Which tools are doing what.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Github Code Scanning will follow by interface, thus you will identify all true positives along with &lt;code&gt;dummy&lt;/code&gt; false positives.
&lt;code&gt;Dummy&lt;/code&gt; interface implementation simply returns &lt;code&gt;return&lt;/code&gt; containing no security issues.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzyxethahzzn7yre0u2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzyxethahzzn7yre0u2o.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;SonarCloud will follow by interface but it shows a single source for a single sink. So a single finding.&lt;br&gt;
Note that SonarCloud has 2 rules to detect SQL injections:&lt;br&gt;
2.1. &lt;code&gt;S2077&lt;/code&gt; doesn't use Taint Analysis, thus it is a security hotspot.&lt;br&gt;
2.2. &lt;code&gt;S3649&lt;/code&gt; use Taint Analysis, but like I mention it doesn't show all paths.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security Code Scan is not following by interface, at least in NoAudit mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Semgrep has no clue about used sinks and shows nothing. Knowing its taint analysis limitation, it should find a known sink in the best case without providing the code flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Snyk Code use a single source to report a vulnerability, so it is hard to tell for sure if the &lt;code&gt;Dummy&lt;/code&gt; stuff is in equation. It also decreases security severity of the finding to &lt;code&gt;Low&lt;/code&gt; in my case.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6im9knqd41qw5bzaqr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6im9knqd41qw5bzaqr7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which is funny, because the same issue is reported as &lt;code&gt;High&lt;/code&gt; without using interfaces. So, it is more about confidence then?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
The repository pattern can be tricky for static code analyzers, be ready to do some manual review!&lt;/p&gt;

&lt;p&gt;PS: I mentioned ChatGPT, so let's ask it.&lt;br&gt;
&lt;strong&gt;Why static code analyzers cannot properly check code that uses a repository pattern?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Static code analyzers are tools that automatically scan source code to identify potential issues, such as bugs, security vulnerabilities, and coding errors. These tools are typically designed to work with a specific programming language and follow a set of rules and best practices for that language.&lt;/p&gt;

&lt;p&gt;One of the challenges of using static code analyzers with code that uses a repository pattern is that the repository pattern is a design pattern that is implemented in a variety of ways, and each implementation can have its own unique characteristics. Because static code analyzers are designed to work with specific programming languages and follow a set of rules, they may not be able to properly analyze code that uses a repository pattern if it deviates from those rules.&lt;/p&gt;

&lt;p&gt;Additionally, the repository pattern is often used to abstract away the details of how data is stored and retrieved, which can make it difficult for static code analyzers to understand the full context of the code and identify potential issues. For these reasons, static code analyzers may have difficulty properly checking code that uses a repository pattern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds smart but not a real answer. I consider it as a nice try!&lt;/p&gt;

&lt;p&gt;My code repository is located &lt;a href="https://github.com/dbalikhin/SharpSaster" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>security</category>
      <category>sast</category>
      <category>csharp</category>
    </item>
    <item>
      <title>A quick comparison of Security Static Code Analyzers for C#</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Sat, 19 Nov 2022 19:48:17 +0000</pubDate>
      <link>https://dev.to/dbalikhin/a-quick-comparison-of-security-static-code-analyzers-for-c-2l5h</link>
      <guid>https://dev.to/dbalikhin/a-quick-comparison-of-security-static-code-analyzers-for-c-2l5h</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Static Application Security Testing (SAST) has become an integral part of any Secure Development Lifecycle. It is relatively fast and can catch security issues before committing to the codebase. You may hear Veracode, Coverity, and Checkmarx. These players are a long time in market. Their analyzers are slow and expensive but mark all checkboxes for a typical "enterpise".&lt;/p&gt;

&lt;p&gt;I will test new players for a single language C# and a single vulnerability type - SQL injection. My focus area will be &lt;strong&gt;quality of analysis&lt;/strong&gt; (though it is wrong to make a decision based on a single issue type), &lt;strong&gt;vulnerability review&lt;/strong&gt; (devs can quickly validate findings), and &lt;strong&gt;remediation guidance&lt;/strong&gt; (devs know how to fix it). I would probably try "enterprise" stuff as well if they provide a free tier for open-source projects, but I could not find this option.&lt;/p&gt;

&lt;p&gt;So, here are the generic requirements for the SAST tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free to try for public repositories&lt;/li&gt;
&lt;li&gt;Supports C#&lt;/li&gt;
&lt;li&gt;Provides security rules, can find security issues&lt;/li&gt;
&lt;li&gt;Supports Taint Analysis (data flow analysis from input (source) to vulnerable invocation (sink))&lt;/li&gt;
&lt;li&gt;Provides a proper description and how to fix it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bonus: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast enough&lt;/li&gt;
&lt;li&gt;Small number of false positives&lt;/li&gt;
&lt;li&gt;IDE plugin (so devs can view results locally) &lt;/li&gt;
&lt;li&gt;Supports SARIF export (so results can be viewed by other tools, e.g., Github Security Scanning)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Candidates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CodeQL&lt;/strong&gt; aka Github Security Scanning (GHAS) - a full-sized security solution from Github (formerly Semmle LGTM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SonarCloud&lt;/strong&gt; - affordable but powerful, a cloud version of SonarQube Dev Edition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semgrep&lt;/strong&gt; - regex on steroids, you don't need to compile anything, and you can create your own rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://security-code-scan.github.io/" rel="noopener noreferrer"&gt;Security Code Scan&lt;/a&gt;&lt;/strong&gt; - Roslyn-based C#/VB only analyzers with minimal integration options, but super fast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snyk Code&lt;/strong&gt; (formerly DeepCode) - "Dark magic" AI-based, you don't need to compile the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are quite different on purpose. Let's see them in action.&lt;/p&gt;

&lt;p&gt;Honorable mentions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sonarlint for C#, Codacy for C#, SonarQube Community Edition - provided rules are great for quality checks only; they lack Taint Analysis, so no Injections can be found!&lt;/li&gt;
&lt;li&gt;Official &lt;a href="https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/security-warnings" rel="noopener noreferrer"&gt;Roslyn Analyzers from MS&lt;/a&gt; (they have a minimal set of sinks meaning they can catch just a few methods).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pumasecurity.io/" rel="noopener noreferrer"&gt;Puma Security&lt;/a&gt; - commercial version of Security Code Scan. The community edition could have been better, but the Pro version sounds interesting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing methodology
&lt;/h2&gt;

&lt;p&gt;I'm not planning to use &lt;a href="https://samate.nist.gov/SARD/test-suites/110" rel="noopener noreferrer"&gt;Juliet Test Suite&lt;/a&gt; (just &amp;gt;28000 test cases for C#) or &lt;a href="https://owasp.org/www-project-benchmark/" rel="noopener noreferrer"&gt;OWASP Benchmark&lt;/a&gt;. Juliet Test Suite is very synthetic, it is a good idea to validate your SAST against it, but nobody shares the results. OWASP Benchmark is a bit easier to run, but companies also do not publicly share results. You can ask for them, and maybe you will be lucky.&lt;/p&gt;

&lt;p&gt;So, I created my project &lt;strong&gt;SharpSaster&lt;/strong&gt; - &lt;a href="https://github.com/dbalikhin/SharpSaster" rel="noopener noreferrer"&gt;https://github.com/dbalikhin/SharpSaster&lt;/a&gt;. It is .NET 6 Web Application, fully compilable but without an actual database. Just enough for our SAST folks.&lt;/p&gt;

&lt;p&gt;There are 5 controllers (uses ControllerBase class):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SqlBasicController&lt;/strong&gt;: one safe method EfCoreInjectionSafe (with multiple sinks), and 8 vulnerable methods - EfCoreInjectionVulnerableX. We access a database with EntityFrameworkCore here. Test new stuff!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SqlBasicSinkController&lt;/strong&gt;: 3 safe and 5 vulnerable methods + extra vulnerable method SqlClientVulnerable10 where we have a parameterized stored procedure but user controllable stored procedure name. We use old-school SqlCommand here. Test old stuff!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SqlAdvancedController&lt;/strong&gt;: 2 safe (integer conversion), 2 vulnerable (1 or many vulnerable sources).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SqlFlowController&lt;/strong&gt;: 4 vulnerable flows with a single sink! 1 unreachable safe flow that easy to detect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SqlFlowSingleSourceController&lt;/strong&gt;: Similar to the previous class, but for each source, we will have our own sink (I found that some tools combine findings be a sink. If you fix a sink (e.g. with parameterization), you will fix all sources. Although I prefer to see a group of sources combined by a sink, see Results section).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All input (sources) will come from an action of the controller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: A typical SAST tool without customization cannot catch conditional cases. I included a couple of them, and all of our candidates marked them vulnerable, as expected. Therefore, I excluded conditional methods from the quality assessment.&lt;br&gt;
An example of the conditional case is below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;localCondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localCondition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ExecuteSQLCommandWithVulnerableInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You should not expect that your SAST analyzer will understand conditions/validation. However, just a few tools support user-controllable customization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Taint Analysis 101
&lt;/h3&gt;

&lt;p&gt;There is input (user-controllable &lt;strong&gt;source&lt;/strong&gt;) - a parameter in the API controller, main method of console applications, etc.&lt;br&gt;
There is a method that may execute vulnerability (&lt;strong&gt;sink&lt;/strong&gt;) - for SQL injections, it will be any method sending a SQL command to a server.&lt;br&gt;
The &lt;strong&gt;source&lt;/strong&gt; is marked as &lt;strong&gt;tainted&lt;/strong&gt;. If it reaches the &lt;strong&gt;sink&lt;/strong&gt; without &lt;strong&gt;sanitization&lt;/strong&gt;, we have a &lt;strong&gt;vulnerability&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Sanitization&lt;/strong&gt; - any known method that will "untaint" (make it safe) a user-controllable value between the source and the sink.&lt;br&gt;
&lt;strong&gt;"Tainting"&lt;/strong&gt; - any assignment / referencing to the tainted variable. I just created this term, but it is what is happening in reality.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// source - I'm tainted&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;otherVariable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"stuff"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// otherVariable - Now I'm tainted too :(&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;An analyzer needs to perform data-flow analysis from the source to the sink (+ from any tainted value in between) "untainting" variables with sanitizers. This is called &lt;strong&gt;Taint Analysis&lt;/strong&gt;. &lt;br&gt;
&lt;strong&gt;Sanitizer&lt;/strong&gt; creates a new safe value as an output. XSS Encoding method or SQL parameterization would be examples of SAST sanitizers, or at least in my interpretation 😉.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validators&lt;/strong&gt; do not change "tainted" status. They do not produce output that will be used later. That's why all conditional cases are problematic for analyzers.&lt;/p&gt;

&lt;p&gt;A good SAST tool should know as many sinks and sanitizers as possible (sources are usually very limited). And, of course, it should have a solid taint analysis engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Categories of results
&lt;/h3&gt;

&lt;h4&gt;
  
  
  True Positives / False Positives
&lt;/h4&gt;

&lt;p&gt;How many findings were detected correctly (true positives) or declared safe code as vulnerable (false negatives)? &lt;br&gt;
"Conditional" issues are ignored!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/dbalikhin/SharpSaster/pull/2/checks?check_run_id=9484395475" rel="noopener noreferrer"&gt;CodeQL&lt;/a&gt;&lt;/strong&gt; (100% of true positives with 0% false positives, conditional stuff is out of scope): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlBasicController: 8 of 8 found, 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlBasicSinkController: 6 of 6 found, 0 false positives, combining results by a sink if there are 2 sources.&lt;/li&gt;
&lt;li&gt;SqlAdvancedController: 2 of 2 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowController: 4 of 4 found but in a single issue (combining results by a sink), 0 false positives&lt;/li&gt;
&lt;li&gt;SqlFlowSingleSourceController: 4 of 4 found similar to SqlFlowController but cannot combine results because we have unique sinks, 0 false positives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://sonarcloud.io/summary/overall?id=dbalikhin_SharpSaster" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt;&lt;/strong&gt; (100% good findings for EFCore, almost 100% bad for SQLCommand. It is an unpleasant "surprise" for me + it is weird to see some SQL Injections in the Hotspots area): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlBasicController: 8 of 8 found, 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlBasicSinkController: &lt;strong&gt;0 of 6 found&lt;/strong&gt;. Checking Security Hotspots.&lt;/li&gt;
&lt;li&gt;SqlAdvancedController: 2 of 2 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowController: 1 of 4 found. I could not find a way to display all sources. A single sink =&amp;gt; a single source.&lt;/li&gt;
&lt;li&gt;SqlFlowSingleSourceController: 4 of 4 found, 0 false positives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SonarCloud has 2 types of security findings: vulnerabilities (confirmed) and security hotspots (maybe context dependant, requires manual review). I found a single issue for SqlBasicSinkController in the security hotspots area. Technicality, 0% false positives, just missed vulnerabilities. &lt;/p&gt;

&lt;p&gt;For some reason, SonarCloud created 22 security hotspots, some for safe items, and other for confirmed vulnerabilities. Unfortunately, I cannot explain why it is doing that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt; (terrible findings - basically 0% true positives, I had to add an example from the official ruleset to make sure I configured it correctly): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlBasicController: 0 of 8 found, 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlBasicSinkController: 1 of 6 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlAdvancedController: 0 of 2 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowController: 0 of 4 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowSingleSourceController: 0 of 4 found, 0 false positives. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn't have any findings, so I went to &lt;a href="https://semgrep.dev/r?q=csharp.lang.security.sqli.csharp-sqli.csharp-sqli" rel="noopener noreferrer"&gt;the rule&lt;/a&gt; to check how it worked. I am confident that my security policy is properly configured, it is not a great ruleset for SQL Injections provided by Semgrep.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/dbalikhin/SharpSaster/pull/2/checks?check_run_id=9484383293" rel="noopener noreferrer"&gt;Security Code Scan&lt;/a&gt;&lt;/strong&gt; (100% of true positives with 0% false positives. It does not group findings by the same sink, so more issues).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlBasicController: 8 of 8 found, 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlBasicSinkController: 6 of 6 found (technically 7 of 7, I do have 2 sources with a single sink in one of the cases), 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlAdvancedController:  2 of 2 found (+ extra finding from 2 sources with a single sink), 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowController: 4 of 4 found (not grouping by the same sink), 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlFlowSingleSourceController: 4 of 4 found, 0 false positives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://app.snyk.io/org/dbalikhin/project/bab74b24-dbb0-4fea-99e4-38ffbce8e0d9" rel="noopener noreferrer"&gt;Snyk Code&lt;/a&gt;&lt;/strong&gt; (it found 100% of true positives. However, it failed significantly on safe EFCore statements).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SqlBasicController: 8 of 8 found, &lt;strong&gt;4 false positives&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;SqlBasicSinkController: 6 of 6 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlAdvancedController: 2 of 2 found, 0 false positives. &lt;/li&gt;
&lt;li&gt;SqlFlowController: 1 of 4 found (I could not find any grouping, so a single sink detected), 0 false positives.&lt;/li&gt;
&lt;li&gt;SqlFlowSingleSourceController: 4 of 4 found, 0 false positives.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  True Positives / False Positives Summary
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt; is a leader along with completely free &lt;strong&gt;Security Code Scan&lt;/strong&gt;. &lt;strong&gt;Snyk&lt;/strong&gt; takes a second place, &lt;strong&gt;SonarCloud&lt;/strong&gt; - third. &lt;strong&gt;Semgrep&lt;/strong&gt; is hardly usable for security needs in this testing scenario.&lt;/p&gt;

&lt;p&gt;Snyk shows inconsistent results, but overall, 100% of true positives with some false positives are better than missed issues.&lt;/p&gt;

&lt;p&gt;In real life, I saw much better results produced by SonarCloud (SonarQube Dev Edition), but not in this run. I'm disappointed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Taint Analysis and Visualization
&lt;/h3&gt;

&lt;p&gt;After a scanner finds an issue, a developer/security specialist will need to validate the finding. For SQL Injection issue type, we will need to review the code flow and make sure that tainted input (source) goes all the way to the SQL invocation (sink) without having any known sanitizing function in between. It is called taint analysis (a form of data flow analysis). Not all security rules require taint analysis, but if you want meaningful results for SQL Injections, you will need proper taint analysis.&lt;/p&gt;

&lt;p&gt;A scanner should produce a trace in a consumable format so a human can identify the correctness of the findings. Let's check the output of the tools and compare them. I will mostly use "Flow" and "Advanced" controllers.&lt;/p&gt;

&lt;p&gt;Note: If a tool supports Github Annotation and allows you to upload results to Github in the SARIF format, you can see annotated code within Github Checks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CodeQL combines findings by the same sink in the UI. So it makes sense  - you need to fix a single sink, e.g., by adding parameters to your SQL statement.&lt;br&gt;
It shows the found sink; to get more details, you need to click on &lt;strong&gt;Show Paths&lt;/strong&gt; to review all available sources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa70f260urvrwdzs7dqkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa70f260urvrwdzs7dqkp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, we have 4 issues here + 2 conditional "safe" flows, that no tool can detect; you need some old fashion manual code review for that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqgenmcccomu3zy7x2jo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqgenmcccomu3zy7x2jo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CodeQL can properly identify the source parameter - &lt;strong&gt;string input&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furlkq6n2crw18a3f2z0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furlkq6n2crw18a3f2z0r.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to scroll down to review the sink. The flow is easy to understand, and a short comment is provided for each step. The execution order is shown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwvd6gckvnqkcbxr9psi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjwvd6gckvnqkcbxr9psi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only possible improvement is to include a variable assignment in the last block, so we can see how &lt;strong&gt;concatSql&lt;/strong&gt; is crafted - I selected this line manually, see below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2t27i4wjdiw4ud7pp87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2t27i4wjdiw4ud7pp87.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's check multiple sources on a single line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjrssv22cvwcarke3lfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjrssv22cvwcarke3lfr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, we have 2 vulnerable inputs, CodeQL created 2 paths for them, and each one clearly identifies the vulnerable source.&lt;/p&gt;

&lt;p&gt;Overall, the taint analysis looks great. A bit narrow window, so you need to scroll horizontally sometimes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SonarCloud&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SonarCloud doesn't combine findings by a sink; it will only report "first" finding. But it is doing it beautifully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoinxsqrlgaohpuqej6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoinxsqrlgaohpuqej6i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Execution order can be easily followed by numbers and comments on the left side. It marks all required code, nothing to add or remove. Unless we are talking about conditional execution 😊 &lt;br&gt;
My only concern, it doesn't show the exact source parameter.&lt;/p&gt;

&lt;p&gt;Now let's check multiple sources on a single line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rm0bqwm3n19dwiw70cs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rm0bqwm3n19dwiw70cs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh well, it simply highlights the method with the source but not the parameter. In our case, &lt;strong&gt;user&lt;/strong&gt; is not vulnerable, but &lt;strong&gt;name&lt;/strong&gt;. It needs to be clarified from the screenshot.&lt;/p&gt;

&lt;p&gt;The tool supports SARIF upload, but you will still need to go to SonarCloud website; it is a simple link on the Code Scanning page with basic remediation examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk44c714pw8ho0dh7xa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk44c714pw8ho0dh7xa9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall, the taint analysis looks great too. The UI requires fewer actions to take than CodeQL. However, a scanner needs to identify a source more specifically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have a single finding. Here it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mgsjpxcgel6ibsjpfj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mgsjpxcgel6ibsjpfj8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not sure if I can say Semgrep supports Taint Analysis. The rule is not simple, but not complicated as well. Semgrep stores just a finding with reference to the Github (permalink).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76hbvu5ozg5nn6o3udns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76hbvu5ozg5nn6o3udns.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It supports SARIF upload, so you can use Github Security Code Scanning page to view results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2upjp7jcy8sd9fip435l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2upjp7jcy8sd9fip435l.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Code Scan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tool supports SARIF upload. The message format is from the Visual Studio Error List window, a single line with minimal required information that is not easy to read but provides some value. We can get the source, the accessing method, and the sink. I would love to see improvements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97li5s1nxkec82sz7w4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97li5s1nxkec82sz7w4a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snyk Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Snyk Code doesn't combine findings by a sink. Taint analysis visualization is easy to understand, and execution (data) flow provides more steps. It displays almost all tainted data, where CodeQL and SonarCloud prefer to show only method invocation and assignments related to reaching the sink. It may be helpful if you need to validate "validators" (by reviewing the whole data flow) manually - different goals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybtsg0v5n947m3rjlkqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybtsg0v5n947m3rjlkqo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes UI is not responsive, but you can switch between the Data flow and the Fix analysis tabs to refresh it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tgh9creruj5b9jqb6rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tgh9creruj5b9jqb6rl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So you will get results after all.&lt;br&gt;
It can properly identify what origin of the source used. No need to guess if one or more parameters are vulnerable in the same method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dwcda1bun585cx7p2ac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0dwcda1bun585cx7p2ac.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can navigate through the steps on the left side. Overall, it is a decent solution.&lt;/p&gt;

&lt;p&gt;Note: I didn't check if Snyk Action allows you to upload to Code Scanning in SARIF format.&lt;/p&gt;

&lt;h4&gt;
  
  
  Taint Analysis and Visualization Summary
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt;, &lt;strong&gt;Snyk&lt;/strong&gt;, &lt;strong&gt;SonarCloud&lt;/strong&gt; provide great data flow visualization. &lt;br&gt;
Only &lt;strong&gt;CodeQL&lt;/strong&gt; can show different paths for the same sink, so I will give it 1st place. &lt;br&gt;
&lt;strong&gt;SonarCloud&lt;/strong&gt; visualization is more intuitive, but it doesn't show what origin of the source was used. &lt;strong&gt;Snyk&lt;/strong&gt; provides much more steps but can properly identify the source. They will share 2nd place.&lt;br&gt;
&lt;strong&gt;Security Code Scan&lt;/strong&gt; and &lt;strong&gt;Sempgrep&lt;/strong&gt; do not really visualize anything, so they are in 3rd place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remediation Guidance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to Code Scanning Page to view details. Don't forget to expand "Show More" section. Recommendations, samples, and references are useful. First-party integration makes it look beautiful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kp10xke41my4cf6lcs4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kp10xke41my4cf6lcs4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SonarCloud&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It provides enough information if you click the "Why is this an issue" link.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qliolnqshfls58oj7om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qliolnqshfls58oj7om.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is even better for Security Hotspots, so I wonder if they decided to mark my SQL injections as a Hotspot for this reason 😊&lt;br&gt;
You can navigate between multiple tabs to get more insights about the vulnerability. Pretty cool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc39dify1nhyyngbicv41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc39dify1nhyyngbicv41.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Scanning Page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ljl2855nmj575k17rta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ljl2855nmj575k17rta.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt;&lt;br&gt;
Semgrep could be more generous in providing details. It is a bare minimum, and I need more!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cocmqi2fdms52u0b16z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cocmqi2fdms52u0b16z.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Scanning Page&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlaqb7genfaeoiy17pm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftlaqb7genfaeoiy17pm8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Code Scan&lt;/strong&gt;&lt;br&gt;
This is Sparta! It will provide a &lt;a href="https://security-code-scan.github.io/#SCS0002" rel="noopener noreferrer"&gt;link&lt;/a&gt; where you can read about the vulnerability type, bad/good code, and find other references. Still useful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawwcqw902bjlixfgher4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawwcqw902bjlixfgher4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Scanning Page&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgjbfidn2tvoiycjlow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhgjbfidn2tvoiycjlow.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snyk Code&lt;/strong&gt;&lt;br&gt;
They made some progress from the last year, but it can be better.&lt;br&gt;
"Details" and "Best Practices" sections are too generic; samples don't make sense most of the time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyml1nv7upf8g256xf8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyml1nv7upf8g256xf8c.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How can I fix a SQL injection with this?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjb3vqjp60dvv4mto2p2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjb3vqjp60dvv4mto2p2t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Remediation Guidance Summary
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt;, &lt;strong&gt;SonarCloud&lt;/strong&gt;, &lt;strong&gt;Security Code Scan&lt;/strong&gt; provide a proper description and compliant/non-compliant samples - 1st place.&lt;br&gt;
&lt;strong&gt;Snyk Code&lt;/strong&gt; and &lt;strong&gt;Semgrep&lt;/strong&gt; - 2nd.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other features
&lt;/h2&gt;

&lt;p&gt;This is a light assessment of the tools. &lt;br&gt;
I can also compare some other valuable features of these tools but without providing any reference 😉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;br&gt;
It depends on technology, the aggressiveness of the scan (e.g., the depth of analysis), and how well-optimized are preparation steps.&lt;br&gt;
&lt;strong&gt;CodeQL&lt;/strong&gt;, &lt;strong&gt;SonarCloud&lt;/strong&gt;, and &lt;strong&gt;Security Code Scan&lt;/strong&gt; will need to compile the code first, so they will also need to fetch the required dependencies. It slows the process, but still, it will be minutes only. On small codebases, expect the time to be between 3-5 minutes. Then it grows this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for &lt;strong&gt;Security Code Scan&lt;/strong&gt; - extra seconds&lt;/li&gt;
&lt;li&gt;for &lt;strong&gt;SonarCloud&lt;/strong&gt; - extra minute or 2&lt;/li&gt;
&lt;li&gt;for &lt;strong&gt;CodeQL&lt;/strong&gt; - extra minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt; and &lt;strong&gt;Snyk&lt;/strong&gt; will complete a scan for a small project within a minute. Simply remove building time from the equation. For bigger projects, analysis time increase is somewhat linear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDE support&lt;/strong&gt;&lt;br&gt;
The most mature will be &lt;strong&gt;SonarCloud&lt;/strong&gt; with its SonarLint extension in the connected mode. However, you cannot perform taint analysis on the client; results will be fetched from the server and displayed in your IDE.&lt;br&gt;
&lt;strong&gt;Snyk Code&lt;/strong&gt; made great progress from the last year, more IDEs supported, and you will get a similar to the portal (app.snyk.io) experience. The plugin will &lt;strong&gt;need to upload all files&lt;/strong&gt; to be scanned on the server, an initial scan will be longer, but then it can handle only delta.&lt;br&gt;
&lt;strong&gt;Semgrep&lt;/strong&gt; supports a limited number of IDEs, but scanning is happening locally.&lt;br&gt;
&lt;strong&gt;Security Code Scan&lt;/strong&gt; is nothing more than a NuGet package with Roslyn analyzers. It will populate your error list, and you can utilize Visual Studio's built-in features. It works in entirely disconnected mode, and scanning is local.&lt;br&gt;
&lt;strong&gt;CodeQL&lt;/strong&gt; doesn't support any IDE, as far as I know. Technically, you can try to export to SARIF format in your Github action and review results with SARIF viewer extension in your IDE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price&lt;/strong&gt;&lt;br&gt;
All options are free for open-source projects.&lt;/p&gt;

&lt;p&gt;If you are developing a closed-source application, you will still pay nothing for &lt;strong&gt;Security Code Scan&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SonarCloud&lt;/strong&gt; is excellent for small and medium businesses. Its "line of code" price model is pretty cheap. Enterprises may prefer &lt;strong&gt;SonarCloud&lt;/strong&gt; because of the cost/value and quality/performance ratio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt; has a free community tier (up to 20 developers). &lt;strong&gt;Snyk Code&lt;/strong&gt; has a Free tier with a hard limit of scans. If we compare Team / Enterprise editions, they will be about the same. Even the same as &lt;strong&gt;CodeQL&lt;/strong&gt;. Expect to spend at least 40 dollars per user per month. Well, your negotiating skills can definitely lower this number, all enterprise-oriented companies are quite flexible 😊&lt;/p&gt;

&lt;p&gt;Don't forget that the &lt;strong&gt;Software Composition Analysis&lt;/strong&gt; add-on is "free" for Sempgrep and Github Advanced Security if you use their SAST solution. However, it costs extra for Snyk because it is an entirely separate product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I will remind you of my focus area first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;quality of analysis&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vulnerability review&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;remediation guidance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CodeQL&lt;/strong&gt; is a mature and solid solution with excellent results in any focus area. Just remember that it doesn't support IDE and will be the slowest one in our group.&lt;br&gt;
If CI/CD checks are enough for you, go for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SonarCloud&lt;/strong&gt; is also a very mature solution. It supports &lt;strong&gt;more programming languages&lt;/strong&gt;, including very exotic ones. Sometimes it will produce not ideal results, but it is easy to use and costs little. It definitely helps to improve security in your organization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sempgrep&lt;/strong&gt; is still in the beta phase in my opinion. You can easily customize rules for your need, and speed is great, but security checks are limited to the underlying engine. I encourage you to check available rules and decide if it is worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security Code Scan&lt;/strong&gt; can be your "second" scanner for C#/VBA. It works in an IDE ultra-fast (literally a couple of seconds at most) and produces solid results. CI/CD integration is very basic, but it is entirely free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snyk Code&lt;/strong&gt; is close to being a solid product. They need to slightly improve quality of analysis and their remediation guidance. Will it justify a high price? Well, maybe, the speed is great.&lt;/p&gt;

</description>
      <category>security</category>
      <category>csharp</category>
      <category>programming</category>
      <category>sast</category>
    </item>
    <item>
      <title>Creating Passwordless FIDO2 experience</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Fri, 07 Oct 2022 22:36:59 +0000</pubDate>
      <link>https://dev.to/dbalikhin/creating-passwordless-fido2-experience-3goh</link>
      <guid>https://dev.to/dbalikhin/creating-passwordless-fido2-experience-3goh</guid>
      <description>&lt;p&gt;How many websites natively support FIDO2 (WebAuthn)? Just a few.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft and other big Identity providers have &lt;a href="https://learn.microsoft.com/en-us/azure/active-directory/authentication/concept-authentication-passwordless"&gt;something&lt;/a&gt; in place.&lt;/li&gt;
&lt;li&gt;Demo sites like &lt;a href="https://webauthn.io/"&gt;webauthn.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Individual companies (to provide the best level of security), e.g. &lt;a href="https://bitwarden.com/help/setup-two-step-login-fido/"&gt;Bitwarden&lt;/a&gt; password manager.&lt;/li&gt;
&lt;li&gt;Start-ups, prototypes, e.g. my &lt;a href="https://fido2me.com/"&gt;fido2me.com&lt;/a&gt; creation (also &lt;a href="https://github.com/Fido2me/fido2me"&gt;open-source&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how can we easily build a website supporting FIDO2 (WebAuthn)?&lt;/p&gt;

&lt;h2&gt;
  
  
  Use FIDO2 libraries
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webauthn.io/"&gt;Webauthn&lt;/a&gt; website contains a list of open-source libraries for many programming languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;dotnet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repositories are great, and fido2me uses a customized version of &lt;a href="https://github.com/passwordless-lib/fido2-net-lib/"&gt;this project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are a developer, I recommend reviewing these repositories. They will provide flexibility in exchange for your time to learn new technology. But it is also rewarding and quite fascinating.&lt;/p&gt;

&lt;p&gt;These projects are focused on supporting all available features of FIDO2. It is not a solution, but rather a framework to build one.&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2 integrations
&lt;/h2&gt;

&lt;p&gt;If you don't want to start from scratch, choose one of the 3 options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API style&lt;/strong&gt;, e.g. &lt;a href="https://www.passwordless.dev/"&gt;passwordless.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt;, e.g. &lt;a href="https://www.identityserver.com/products/fido2-for-aspnet"&gt;fido2-for-aspnet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenId Connect (OIDC)&lt;/strong&gt;: B2B (via &lt;a href="https://help.okta.com/oie/en-us/Content/Topics/identity-engine/authenticators/configure-webauthn.htm"&gt;Identity providers&lt;/a&gt;) or B2C (&lt;a href="https://www.apple.com/ca/newsroom/2022/05/apple-google-and-microsoft-commit-to-expanded-support-for-fido-standard/"&gt;Social login identity providers&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built fido2me as a social login identity provider. You need to create a new account and you will be able to access any website that accepts fido2me. Let's quickly build one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable FIDO2me authentication for Azure Functions
&lt;/h2&gt;

&lt;p&gt;Azure Functions service has built-in OIDC support - a great candidate to start. Similarly, you can enable a new OIDC provider for Azure App Service.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-openid-connect"&gt;official guide&lt;/a&gt; covers integration with a generic OIDC provider. You will need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The metadata URL&lt;/li&gt;
&lt;li&gt;Client ID&lt;/li&gt;
&lt;li&gt;Client Secret&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a new function app, go to the Authentication section, and add a new identity provider selecting "&lt;strong&gt;OpenID Connect&lt;/strong&gt;" as a type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M_4qhuwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xa7zb69497w1cooju87t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M_4qhuwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xa7zb69497w1cooju87t.png" alt="Image description" width="880" height="749"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The metadata URL will be: &lt;strong&gt;&lt;a href="https://fido2me.com/.well-known/openid-configuration"&gt;https://fido2me.com/.well-known/openid-configuration&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt; need to be created on fido2me.com. Let's do it.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://fido2me.com/apps"&gt;https://fido2me.com/apps&lt;/a&gt; and click on "New Client".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZhnSWffh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wys6u1xs612pzdylp3nb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZhnSWffh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wys6u1xs612pzdylp3nb.png" alt="Image description" width="880" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete fields, 2 of them are &lt;strong&gt;required&lt;/strong&gt;: application &lt;strong&gt;Name&lt;/strong&gt; and &lt;strong&gt;Callback URL&lt;/strong&gt; (Redirect URI).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ODudQPh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmxl2itli21lgtp9oxxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ODudQPh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmxl2itli21lgtp9oxxh.png" alt="Image description" width="880" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy and paste Client ID / Client Secret into Azure Portal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can use Secret&lt;/strong&gt; needs to be &lt;strong&gt;selected&lt;/strong&gt;. We use a &lt;strong&gt;confidential client&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unselect &lt;strong&gt;Proof Key&lt;/strong&gt; (PKCE). The authorization code grant with PKCE flow is recommended even for confidential clients. But it is not supported by Azure right now.&lt;/p&gt;

&lt;p&gt;Enter your callback URL - https://&lt;strong&gt;your website&lt;/strong&gt;/.auth/login/&lt;strong&gt;Azure App OIDC provider name&lt;/strong&gt;/callback&lt;/p&gt;

&lt;p&gt;My function is hosted at &lt;a href="https://fido2metest2.azurewebsites.net"&gt;https://fido2metest2.azurewebsites.net&lt;/a&gt;. I called my identity provider as &lt;strong&gt;fido2me2&lt;/strong&gt; in Azure Function App. Thus, my callback URL: &lt;a href="https://fido2metest2.azurewebsites.net/.auth/login/fido2me2/callback"&gt;https://fido2metest2.azurewebsites.net/.auth/login/fido2me2/callback&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the app on fido2me.com and complete the creation of a new OIDC provider at Azure Function App. You may need to accept additional changes related to changing the authentication methods in Azure Function App.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing FIDO2me OIDC
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit Azure Function URL.&lt;/li&gt;
&lt;li&gt;Complete FIDO2 Sign In.&lt;/li&gt;
&lt;li&gt;You are now authenticated and redirected back to your Function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: FIDO2 challenge and related authentication cookies will expire after a few minutes. You will need to refresh the page to try to sign in again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations&lt;/strong&gt;: Now we have one more FIDO2-enabled website. In the next article, I will show how to develop a new web application with &lt;strong&gt;dotnet&lt;/strong&gt; that actually supports the authorization code grant with &lt;strong&gt;PKCE&lt;/strong&gt; flow!&lt;/p&gt;

</description>
      <category>webauthn</category>
      <category>passwordless</category>
      <category>fido</category>
      <category>auth</category>
    </item>
    <item>
      <title>Fido2me: Passwordless registration and login</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Fri, 30 Sep 2022 18:23:46 +0000</pubDate>
      <link>https://dev.to/dbalikhin/fido2me-passwordless-registration-and-login-51gg</link>
      <guid>https://dev.to/dbalikhin/fido2me-passwordless-registration-and-login-51gg</guid>
      <description>&lt;h2&gt;
  
  
  FIDO2 Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fidoalliance.org/fido2/" rel="noopener noreferrer"&gt;FIDO2&lt;/a&gt; is a passwordless technology, meaning you don't need to create and remember a secret. Instead, the secret will be generated for you and stored by any supported authenticator. Authenticators can be a platform (laptop, desktop, mobile) or roaming device (security key, e.g. Yubikey). For simplicity, we can refer to authenticators as devices. &lt;/p&gt;

&lt;p&gt;From a security perspective, if a platform device uses a TPM, it can provide the same level of assurance as a security key. A secret never leaves a device; instead, it supports API to perform basic cryptographic operations. The device can be tamper-proof and compliant with &lt;a href="https://csrc.nist.gov/publications/detail/fips/140/2/final" rel="noopener noreferrer"&gt;FIPS 140-2&lt;/a&gt; standards. It is a good idea to check what devices are FIPS 140 certified. Not all security keys are FIPS 140 certified, but it doesn't make a difference for a regular user.&lt;/p&gt;

&lt;p&gt;You can take a roaming device with you and provide access to any device that supports USB or NFC (at least in theory). In practice, it is more complicated, and depending on the browser and the operating system (OS) you may have different outputs. From my experience, security keys work best with laptops and desktops.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't need a security key to start using FIDO2 Passwordless.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A security key is not something that a typical user has. It will cost you ~25-50 USD. Double it if you need a spare. But everyone has a laptop (desktop) or a mobile device. Let's use it!&lt;/p&gt;

&lt;h2&gt;
  
  
  How FIDO2 works
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://fidoalliance.org/how-fido-works/" rel="noopener noreferrer"&gt;official FIDO website&lt;/a&gt; provides great illustrations for registration and login flows. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Registration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqatr2r7amf0tez4r0s6y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqatr2r7amf0tez4r0s6y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9g6tb5m3bura1hqa4q9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9g6tb5m3bura1hqa4q9j.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FIDO2me follows the same pattern! Keep in mind, it is not limited to mobile devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2me Registration
&lt;/h2&gt;

&lt;p&gt;Let's visit the &lt;a href="https://fido2me.com/" rel="noopener noreferrer"&gt;FIDO2me&lt;/a&gt; website. if it is your first use, you will be redirected to the login page. But we don't have an account yet, click on &lt;a href="https://fido2me.com/auth/register" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2vx9awktslw73pv3oyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk2vx9awktslw73pv3oyb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left, we have the "Username" &lt;strong&gt;required&lt;/strong&gt; field, the "Sign up" button, and device selection. On the right side, a couple of examples of platform/roaming authenticators to give an idea of what you can use. Provide your username and click the button. The &lt;strong&gt;Username&lt;/strong&gt; needs to be &lt;strong&gt;unique&lt;/strong&gt; - it is your main identifier for Fido2me.&lt;/p&gt;

&lt;p&gt;Congratulations, you've just asked a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API" rel="noopener noreferrer"&gt;browser&lt;/a&gt; to create a new credential for you. The browser will ask available authenticators on the system to handle the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Register with Platform authenticator
&lt;/h2&gt;

&lt;p&gt;Platform authenticators are preferred options. If you didn't change a default "Any" device type selection, it will ask you to unlock your platform authenticator. In my case, unlock with a PIN (Windows Hello). Note: Windows Hello needs to be enabled with at least a single verification method, e.g. PIN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmyepc0mxibhu3q7vp5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmyepc0mxibhu3q7vp5k.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complete unlocking the device and let your browser send the attestation response back to our server. New &lt;strong&gt;Credential ID&lt;/strong&gt; will be generated by the device. The server (Fido2me) will complete the registration ceremony according to FIDO2 specifications and create a new user account for you. You will be redirected back to the Login screen. &lt;/p&gt;

&lt;h2&gt;
  
  
  Device Type Selection
&lt;/h2&gt;

&lt;p&gt;If you didn't specify the authenticator type, it will first ask a &lt;strong&gt;platform&lt;/strong&gt; authenticator. Don't want to use it - press &lt;strong&gt;Esc&lt;/strong&gt; or click &lt;strong&gt;Cancel&lt;/strong&gt; - Now you work with a roaming device. You will need to create a new PIN or unlock the device.&lt;/p&gt;

&lt;p&gt;If you specified a device type, it will ask only for this particular authenticator type. &lt;/p&gt;

&lt;h2&gt;
  
  
  Register with Roaming authenticator
&lt;/h2&gt;

&lt;p&gt;A browser / OS will guide you, just follow the process. This is what it will look like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tgbjdkcay4terygw64y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tgbjdkcay4terygw64y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk7lzqxgskxuivffu2ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhk7lzqxgskxuivffu2ai.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf3hz8ftvvqlgu6vmjbh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf3hz8ftvvqlgu6vmjbh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxza9sgjxfzks9xp5mxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxza9sgjxfzks9xp5mxf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijesz3vaz1xudsoe945t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijesz3vaz1xudsoe945t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy aspect
&lt;/h2&gt;

&lt;p&gt;You may notice that the website would like to know the make and model of the security key. It is called &lt;strong&gt;Direct Attestation&lt;/strong&gt;. The device will provide a cryptographically signed statement about itself. As a part of the attestation, it will return the &lt;a href="https://docs.yubico.com/hardware/yubikey/yk-5/tech-manual/yk5-fido2-aaguids.html" rel="noopener noreferrer"&gt;AAGUID&lt;/a&gt; field. Using AAGUID we can identify the model of the device with the &lt;a href="https://fidoalliance.org/metadata/" rel="noopener noreferrer"&gt;FIDO2 Metadata service&lt;/a&gt; (technically, it is just a file). If something terrible happens with the specific model, it should be reflected in the metadata service (MDS). But for our needs, we just need AAGUID to get the model and properly display it in a list of registered devices.&lt;/p&gt;

&lt;p&gt;The type will be empty if AAGUID is unknown (not in the MDS). You can try using the nickname field if it is not provided. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w3v55sd6pv1cyibdoxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w3v55sd6pv1cyibdoxd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AAGUID is not a piece of private information. It is a part of the MDS which is publicly available for everyone. Feel free to check all &lt;a href="https://support.yubico.com/hc/en-us/articles/360016648959-YubiKey-Hardware-FIDO2-AAGUIDs" rel="noopener noreferrer"&gt;AAGUIDs of Yubikey&lt;/a&gt; as an example. &lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2me Login
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9cqew8yxc8fuzcapcaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa9cqew8yxc8fuzcapcaj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Can you spot the difference?&lt;/p&gt;

&lt;p&gt;The "Username" is &lt;strong&gt;optional&lt;/strong&gt;, and the device type is defaulted to "&lt;strong&gt;Any&lt;/strong&gt;" authenticator (so no selection).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Woah, why I don't need my username?&lt;/strong&gt; The credential is stored on the device if we create a new credential as &lt;strong&gt;a resident key&lt;/strong&gt; (typical case for security keys).&lt;/p&gt;

&lt;p&gt;This is what I hear every day during the login process. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fido2me&lt;/strong&gt;: I prepared a challenge already on the initial load and provided it to your browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser / OS&lt;/strong&gt;: Hey, known devices, does anyone have a credential for fido2me? I have the challenge to sign from fido2me. Anyone?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform device&lt;/strong&gt;: Okay, I have fluffybunny1 and fluffybunny3 records associated with fido2me.com, what do you want to use? Or maybe you want to try a security key?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: I feel like fluffybunny3 today; let's do it!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform device&lt;/strong&gt;: You are the boss, but you know I need to verify your PIN&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: Click-clack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform device&lt;/strong&gt;: You did it; now I will send a special response back to the server, so it can complete the login process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fido2me&lt;/strong&gt;: Looks good, you shall pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can still provide the username to speed up the process. In this case, the credential selection is skipped.&lt;br&gt;
...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser / OS&lt;/strong&gt;: Hey, known devices, does anyone have this credential for fido2me? I have the challenge to sign from fido2me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device with this credential&lt;/strong&gt;: It is me, sir! Give me your challenge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... &lt;/p&gt;

&lt;h2&gt;
  
  
  Non-resident keys
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Not all devices support resident keys!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Non-resident keys cannot find a record based on the username, but they work with the &lt;strong&gt;Credential ID&lt;/strong&gt;. They need some help from the server.&lt;/p&gt;

&lt;p&gt;During the registration, your device will create a new one. The &lt;strong&gt;Credential ID&lt;/strong&gt; is a long &lt;strong&gt;random&lt;/strong&gt; string, it doesn't relate to your private key in any way. The server (Fido2me) stores this credential along with the username. The server can find your &lt;strong&gt;Credential ID by the username&lt;/strong&gt; and provide it back to the device.&lt;/p&gt;

&lt;p&gt;Now the device can find &lt;strong&gt;the private key by the Credential ID&lt;/strong&gt; and complete the challenge.&lt;/p&gt;

&lt;p&gt;It means that a &lt;strong&gt;username is required for the non-resident key&lt;/strong&gt; flow.&lt;/p&gt;

&lt;p&gt;Fido2me combines both flows and makes username optional. If you know that you work with &lt;strong&gt;resident keys&lt;/strong&gt;, you can immediately click the "Sign in" button and enjoy the &lt;strong&gt;Usernameless&lt;/strong&gt; experience. If you are not sure, always type the "Username".&lt;/p&gt;

&lt;p&gt;And that's it! Now you can play with this cool technology on the &lt;a href="https://fido2me.com/" rel="noopener noreferrer"&gt;fido2me&lt;/a&gt; website. &lt;/p&gt;

</description>
      <category>fido2me</category>
      <category>passwordless</category>
      <category>authentication</category>
      <category>webauthn</category>
    </item>
    <item>
      <title>Fido2me: When code meets a purpose, promotes security, and improves user experience</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Sun, 25 Sep 2022 02:25:14 +0000</pubDate>
      <link>https://dev.to/dbalikhin/fido2me-when-code-meets-a-purpose-promotes-security-and-improves-user-experience-2e2c</link>
      <guid>https://dev.to/dbalikhin/fido2me-when-code-meets-a-purpose-promotes-security-and-improves-user-experience-2e2c</guid>
      <description>&lt;h2&gt;
  
  
  Try, Fail, Learn, Repeat
&lt;/h2&gt;

&lt;p&gt;I'm a big fan of learning by doing, and in many cases, it leads to something amazing. I can code, and my code works more or less as expected giving me a reason to create something new and experiment with the latest technologies. During this process, challenges meet me, and you make discoveries. That's how I learn, and I assume many of us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and Usability
&lt;/h2&gt;

&lt;p&gt;I wrote a lot of code during my software development career. Now I'm doing application and product security. At some point, I realized that psychological acceptance plays a crucial role in security. &lt;br&gt;
After a while, many security controls started to irritate me as a regular user. I can understand why they are in place, but it doesn't change the fact that security is not a friend of usability and user experience. We used to think this way, but is it always the case?&lt;/p&gt;

&lt;p&gt;You should create a strong password containing A, B, C, .., Z. Rotate it every X days, utilize password history, use min days to change, etc. Do you think you create a password compliant with any policy, &lt;a href="https://passwordfromhell.com/"&gt;try this&lt;/a&gt;. It's annoying, right?&lt;/p&gt;

&lt;p&gt;But NIST studied and provided different password guidelines in 2020 (quick summary &lt;a href="https://stealthbits.com/blog/nist-password-guidelines/"&gt;here&lt;/a&gt;). Complexity doesn't really help, but length does. No need to rotate a password if there is no evidence of compromise. Check for breached passwords. That's common sense and improved user experience. I like it.&lt;/p&gt;

&lt;p&gt;Passwords are not terrible, but they are hard to use correctly. If you care about security, you will use a password manager, unique passwords per site, strong passphrase, disable auto-completion in a browser on a page load, etc. Passwords are easy to transfer - it is the main pros but also the con.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passwords Enhancements
&lt;/h2&gt;

&lt;p&gt;There are &lt;strong&gt;three authentication factors&lt;/strong&gt;: something you know, something you have, and something you are. When you add a second factor, it becomes 2FA / MFA (2-factor or multi-factor authentication). It is the best security practice, and it will effectively protect your accounts. So passwords are something you know, security keys / one-time codes - something you have, biometrics (fingerprints, face, retina) - something you are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do we need extra protection?&lt;/strong&gt; Because password hygiene is hard, we want a safety net to protect against data breaches, exposure in log files, phishing attacks, etc. An additional layer of protection helps to reduce the risk level. Keep in mind that in some cases, a successful phishing campaign can bypass 2FA if a user is tricked into providing a 2FA code or approving a push notification.&lt;/p&gt;

&lt;p&gt;If you use a password manager extension in a browser, you will most likely detect that you are not on a legit website. It is a part of the auto-fill functionality. This functionality is super helpful to protect against phishing attacks, but it is recommended to disable auto-fill on a page load and click on this button manually. Why does a phishing attack fail? Credentials stored in a password manager are bound to the website (origin). If the origin is different, the password manager will have 0 matches and nothing to fill. A user may still find credentials manually, but it is a different story.&lt;/p&gt;

&lt;p&gt;The same situation happens with FIDO U2F security key (for example &lt;a href="https://www.yubico.com/"&gt;Yubikey&lt;/a&gt;). A user login is bound to the origin, meaning that only the real site can authenticate with the key. I will not cover the case when you need to change the origin on purpose, yes, it has this limitation 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO is future
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fidoalliance.org/"&gt;FIDO&lt;/a&gt; stands for Fast Identity Online. The FIDO Alliance is an open industry association with a focused mission: authentication standards to help reduce the world’s over-reliance on passwords. I already mentioned FIDO U2F as the most secure second factor. It relies on a private key (public key cryptography) that never leaves a device. But U2F is not the only technology provided by the FIDO Alliance. Please meet &lt;a href="https://fidoalliance.org/fido2/"&gt;FIDO2&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The FIDO Alliance developed FIDO Authentication standards based on public key cryptography for authentication that is more secure than passwords and SMS OTPs, simpler for consumers to use, and easier for service providers to deploy and manage. FIDO Authentication enables password-only logins to be replaced with secure and fast login experiences across websites and apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;FIDO2 consists of two main parts: &lt;strong&gt;CTAP2&lt;/strong&gt; and &lt;strong&gt;WebAuthN&lt;/strong&gt;. For simplicity, &lt;strong&gt;CTAP2&lt;/strong&gt; protocol handles communication &lt;strong&gt;between a browser and a device&lt;/strong&gt; (authenticator, e.g. Yubikey), and &lt;strong&gt;WebAuthN&lt;/strong&gt; describes &lt;strong&gt;communication between a browser and a relying party&lt;/strong&gt; (FIDO2 Server). WebAuthN is more known than FIDO2, so you likely heard about WebAuthN rather than FIDO2.&lt;/p&gt;

&lt;p&gt;FIDO2 effectively moves 2FA on the user side. It is very similar to a chip-and-pin credit card. A security device will store a private key (something you have), and you will need to unblock the device to use it with something you know (PIN) or something you are (biometrics). You perform a transaction with a credit card with your PIN, and the card has a special chip that cryptographically signs each transaction. What will happen if you enter the PIN 3 times incorrectly? The card will be blocked. Yubikey will erase a security key after 8 bad attempts to unblock it with the PIN. It means that you can have a relatively short PIN code that is easy to remember and type and be secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authenticator's world
&lt;/h2&gt;

&lt;p&gt;You don't need a security key to use FIDO2! A security key is a roaming authenticator, but you can also use any platform authenticator: a desktop, a laptop, an Android or IOS phone. If the platform supports it, you are good to go - simply enable Windows Hello or biometrics on your phone. Using a security key is always a good idea, but you can add another platform authenticator as a backup or vice-versa.&lt;/p&gt;

&lt;p&gt;Having a secondary device is crucial. If you lose your device, you will lose your account. FIDO has great technology to help you with that - passkeys, but it has own limitations. I want to focus on the end game - device-bound credentials. But we need to address handling multiple devices problem.&lt;/p&gt;

&lt;p&gt;Many libraries are available to support FIDO2, but still, it is not easy to build a final solution. I played with FIDO2 a lot and decided why not to try providing a service instead of a library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fido2me
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J7BTPRf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m49c4l3buz9w6oosvjdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J7BTPRf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m49c4l3buz9w6oosvjdd.png" alt="Fido2me announcement" width="489" height="730"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Fido2me = FIDO2 + OAuth Server&lt;/strong&gt;. A user authentication gateway to a passwordless world. Try at &lt;a href="https://fido2me.com/"&gt;Fido2me.com&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why not have FIDO2 social login?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is open sourced and available at &lt;a href="https://github.com/Fido2me/fido2me"&gt;Github&lt;/a&gt; (please visit the link to read more details). It is the opinionated implementation of user-friendly FIDO2 Server. It supports multiple authenticators (devices) and &lt;a href="https://darutk.medium.com/ciba-a-new-authentication-authorization-technology-in-2019-explained-by-an-implementer-d1e0ac1311b4"&gt;CIBA&lt;/a&gt; (Client Initiated Backchannel Authentication) to be able to sign in from external devices (you may or may not to add them as trusted authenticators). If you are using Chrome you can try to add new phone (passkeys flow) but don't forget to enable bluetooth on both devices (laptop/desktop + phone).&lt;/p&gt;

&lt;h2&gt;
  
  
  How to integrate with Fido2me
&lt;/h2&gt;

&lt;p&gt;A gateway will be useless without users and integrated applications. If you have some knowledge about using social providers or generic OAuth2 integration, you are good to go. Create a confidential (public client will be available soon) client, copy Client ID / Client Secret, and use your existing experience. Fido2me is just another OAuth server.&lt;/p&gt;

&lt;p&gt;But to be a social provider, Fido2me needs to be much greater. It requires a &lt;strong&gt;community&lt;/strong&gt; of users and &lt;strong&gt;builders&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you want to play with FIDO2 and Fido2me, learn more, provide feedback, or say nah - do not hesitate to contact me (leave a comment or add a reaction) or open a new Github discussion.&lt;/p&gt;

&lt;p&gt;I believe FIDO2 is really awesome, and at least I will help promote it!&lt;/p&gt;

</description>
      <category>product</category>
      <category>passwordless</category>
      <category>fido2</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Password(less) 101</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Sun, 25 Sep 2022 02:00:55 +0000</pubDate>
      <link>https://dev.to/dbalikhin/passwordless-101-1kb5</link>
      <guid>https://dev.to/dbalikhin/passwordless-101-1kb5</guid>
      <description>&lt;h2&gt;
  
  
  Passwords
&lt;/h2&gt;

&lt;p&gt;Passwords help to confirm the user's identity. When you type your username or email, it is your identity on the website. A password supports your claim that you are who you are. It is something you know, and nobody else knows, allegedly. What else can we use?&lt;/p&gt;

&lt;h2&gt;
  
  
  Email Ownership
&lt;/h2&gt;

&lt;p&gt;You can confirm your identity by proving that you have access to the specific mailbox. One-time codes or magic links can be sent to the email address. If you can access it, all good!&lt;/p&gt;

&lt;p&gt;You need to open an email every time. Sometimes you can get "bad" emails from bad guys. So you need to be careful. A service provider can access your email too. The email ownership model is easy to understand, and widespread, but it is far from ideal.&lt;/p&gt;

&lt;p&gt;What will happen if a verification code goes to a different email address? Someone else claims your identity. There are many potential flows with the email ownership method, but the biggest benefit is accessibility and very low cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other authentication factors
&lt;/h2&gt;

&lt;p&gt;Certificates, smart cards, biometrics. Something that only you can access or possess. These factors are unguessable, but you can still try to steal them.&lt;/p&gt;

&lt;p&gt;Let's talk about public key / certificate-based authentication. It is based on public key cryptography. Two keys are to rule them all - one to encrypt the data and another one to decrypt it. A public part can be shared, but you still need to protect a private key somehow. The default way is to encrypt it with a passphrase. Now, nobody can use it without knowing a secret, nice! Just remember the secret. You cannot use a weak one, because there no brute-force protection is built in. People are bad at remembering long strings, so they utilize password managers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password managers
&lt;/h2&gt;

&lt;p&gt;Password managers use a special master password to encrypt the entire vault. You decrypt the vault with this password. Because you are doing it every day, muscle memory works for you, and it is hard to forget this master secret. Service providers store only encrypted data, if they are breached, attackers will still need to break the encryption, and modern encryption is a state of the art. Unless you typed the master password on a malicious resource, fall a victim to a phishing attack, or forgot the password, you can sleep very well!&lt;/p&gt;

&lt;h2&gt;
  
  
  PIN unlock
&lt;/h2&gt;

&lt;p&gt;It is annoying to type the master password every time to unlock the vault although it is the most secure method. A PIN code or some biometrics factor can be used to unlock the vault on a local device. It improves usability greatly, is it still secure? Yes, if you have a rate limiting in place. If a PIN has only 3 digits and 10 attempts are allowed to unblock the vault, attackers can try to guess the PIN with a 1% success chance. Everyone has their own risk acceptance, 1% is too high for me. I would prefer to have 8 digits PIN with 5 attempts - 0.000005% is much better compared to 1%, but I will have to type 8 digits every time. Think about this simple math when selecting a PIN - longer is better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Biometrics unlock
&lt;/h2&gt;

&lt;p&gt;But it is 2022, we have biometrics available on many devices (laptops, IR web cameras, mobile phones). Yup, start using it! Just keep in mind, that fingerprint readers are not friends with water or grease. Fingerprints are great unless you are a high-profile person or worry that someone can force you to unlock the device. In this case, a PIN is your choice.&lt;/p&gt;

&lt;p&gt;To have a good balance between security and usability you will still need to use a rate-limited "master unlocker" to protect a master secret that is a key to your digital life.&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2 Passwordless
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://fidoalliance.org/fido2/" rel="noopener noreferrer"&gt;FIDO2&lt;/a&gt; device (authenticator) is a vault to store your private keys. FIDO2 relies on public key cryptography and doesn't allow to do anything stupid. It is a very strict process to comply with FIDO2 standards for device manufacturers. So they are doing a heavylifting for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resident Keys
&lt;/h2&gt;

&lt;p&gt;You can ask a device to store the private key and associated metadata. It is called resident keys. Not all devices support &lt;strong&gt;resident keys&lt;/strong&gt;, but when they do they can provide &lt;strong&gt;usernameless&lt;/strong&gt; experience additionally to passwordless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt; We store the metadata within the authenticator, so we can ask the device to check for credentials for this specific server (relying party). If we have multiple entries, a prompt will be shown with all available options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Registration&lt;/strong&gt;: We ask a device to create new resident credentials and provide information only about the relying party. The device will send the &lt;strong&gt;attestation response&lt;/strong&gt; to a relying party, so the server can complete registration and store a public key associated with the device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login&lt;/strong&gt;: A relying party generates a challenge (a random string) that needs to be signed with a private key stored on the device. It responds with a signed challenge as a part of the &lt;strong&gt;assertion response.&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find a great example &lt;a href="https://auth0.com/blog/a-look-at-webauthn-resident-credentials/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to keep in mind when working with resident credentials?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not supported by some devices&lt;/li&gt;
&lt;li&gt;A limited number of entries (e.g. 25 resident keys for Yubikey)&lt;/li&gt;
&lt;li&gt;Possible duplicate entries (there is no way to restrict multiple registrations on the same device with the same username if you do not provide a username)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A device needs to be unlocked during registration and login&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  User Verification
&lt;/h2&gt;

&lt;p&gt;Device unlocking is one of three supported user verification methods (&lt;strong&gt;Required&lt;/strong&gt;, &lt;strong&gt;Preferred&lt;/strong&gt;, or &lt;strong&gt;Discouraged&lt;/strong&gt;). Available user verification methods are provided by a relying party (server), but an authenticator can have their own opinion. Based on my experience, all devices when working with resident keys &lt;strong&gt;require&lt;/strong&gt; user verification.&lt;/p&gt;

&lt;p&gt;So what will you get if you set the &lt;strong&gt;Discouraged&lt;/strong&gt; option for resident keys flow? &lt;strong&gt;Exception!&lt;/strong&gt; In some cases, a device will switch to the Required mode. This is built-in protection against unauthorized use of the device.&lt;/p&gt;

&lt;p&gt;Let's go back to these 3 options for user verification.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Required&lt;/strong&gt; - a user must unlock the device for each action&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preferred&lt;/strong&gt; - a device will say what it wants (expect Required 😊)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discouraged&lt;/strong&gt; - if user verification can be skipped (non-resident keys), it will be skipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can still ask for user presence, e.g. touch a Yubikey, but it is a different setting. From UX perspective, it is not very convenient and doesn't save time.&lt;/p&gt;

&lt;p&gt;You can unlock (verify a user) the device with something you know (PIN) and something you are (biometrics). And it is exactly the same experience as you would get when unlocking a password manager. &lt;strong&gt;Choose your PIN wisely, enable biometrics, and use common sense.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I lost my device (authenticator), am I in trouble?&lt;/strong&gt; Not really, after 5-10 unsuccessful attempts the specific user verification method will be disabled (e.g. fingerprint), or some devices will be wiped (8 tries on Yubikey). If the authenticator is tamper-resistant, it is game over for attackers. Lost FIDO2 device means, it cannot be used, but you cannot use it as well - think about &lt;strong&gt;redundancy&lt;/strong&gt; in this case.&lt;/p&gt;

&lt;p&gt;Hardware authenticators are better than software ones - search for &lt;strong&gt;TPM&lt;/strong&gt; word from this day.&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2 authenticators preps
&lt;/h2&gt;

&lt;p&gt;FIDO2 authenticators are not unified and may require extra steps before first use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;: Enable Windows Hello&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxj6zrx41nb86ux8ftc5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxj6zrx41nb86ux8ftc5t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select at least one method supported by Windows Hello, for example, PIN. If no methods are enabled, a browser handling FIDO2 request will ask to connect a security key (e.g. Yubikey).&lt;/p&gt;

&lt;p&gt;You will need to set a PIN on a &lt;strong&gt;security key&lt;/strong&gt;. Some security keys support biometrics (fingerprints), but they are more expensive and less common.   &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Windows Hello cannot use passwords. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Mac&lt;/strong&gt;: You can use a password for FIDO2. A browser will ask you to enter your local password to unlock "the vault". If fingerprints or other verification methods are configured, you can use them too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile&lt;/strong&gt;: To be honest, I'm unsure if you can use FIDO2 without setting a PIN, pattern, or registering biometrics. If you are reading about FIDO2, most likely your mobile device cannot be unlocked by swiping only 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  FIDO2 Adoption
&lt;/h2&gt;

&lt;p&gt;It is good, but not great. There are many moving parts, I suggest starting from this page to get an idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try FIDO2
&lt;/h2&gt;

&lt;p&gt;Feel free to play with FIDO2 at &lt;a href="https://fido2me.com" rel="noopener noreferrer"&gt;fido2me.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I created this website, and no unicorns were harmed!&lt;/p&gt;

&lt;p&gt;The source code is available &lt;a href="https://github.com/Fido2me/fido2me" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>password</category>
      <category>authentication</category>
      <category>webdev</category>
      <category>passwordless</category>
    </item>
  </channel>
</rss>
