<?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: 0xdbe</title>
    <description>The latest articles on DEV Community by 0xdbe (@0xdbe).</description>
    <link>https://dev.to/0xdbe</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%2F644065%2Fc1c6ab25-e3e2-4daf-9d99-89a7ec2d891d.jpeg</url>
      <title>DEV Community: 0xdbe</title>
      <link>https://dev.to/0xdbe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/0xdbe"/>
    <language>en</language>
    <item>
      <title>GitHub: signing commit in a workflow</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Thu, 04 Apr 2024 13:30:43 +0000</pubDate>
      <link>https://dev.to/0xdbe/github-signing-commit-in-a-workflow-98p</link>
      <guid>https://dev.to/0xdbe/github-signing-commit-in-a-workflow-98p</guid>
      <description>&lt;p&gt;Committing in your workflow can normally be done using git commands or other actions that perform commits for you.&lt;br&gt;
However, if your repository requires commit signing, it is difficult to manage securely a GPG keys and set up GitHub Runner to sign your commit.&lt;br&gt;
Fortunately, this can be done through the GitHub GraphQL API.&lt;/p&gt;
&lt;h2&gt;
  
  
  GraphQL Mutation
&lt;/h2&gt;

&lt;p&gt;Github provides a GraphQL Mutation &lt;a href="https://docs.github.com/en/graphql/reference/mutations#createcommitonbranch"&gt;createcommitonbranch&lt;/a&gt; which creates a commit.&lt;br&gt;
Commits made using this mutation are automatically signed by GitHub and will be marked as verified in the user interface.&lt;/p&gt;

&lt;p&gt;For better reusability, we can define a GraphQL mutation in a file &lt;code&gt;.github/api/createCommitOnBranch.gql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$githubRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$branchName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$expectedHeadOid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GitObjectID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$commitMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FileAddition&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createCommitOnBranch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;repositoryNameWithOwner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$githubRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;branchName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$branchName&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$commitMessage&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;fileChanges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;additions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;expectedHeadOid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$expectedHeadOid&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following input fields must be set when you call this mutation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;githubRepository&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;branchName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expectedHeadOid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commitMessage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;files&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage with gh CLI
&lt;/h2&gt;

&lt;p&gt;The mutation can now be called using &lt;code&gt;gh&lt;/code&gt; CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh api graphql &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;$githubRepository&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"owner/repo"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;branchName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;expectedHeadOid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;commitMessage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"chore: commit file"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; files[][path]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; files[][contents]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-w0&lt;/span&gt; README.md&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; files[][path]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"HELLO.md"&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; files[][contents]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-w0&lt;/span&gt; HELLO.md&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s1"&gt;'query=@.github/api/createCommitOnBranch.gql'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Warning: &lt;code&gt;files&lt;/code&gt; is an array of &lt;code&gt;FileAddition&lt;/code&gt;, but fortunately, the &lt;code&gt;gh&lt;/code&gt; CLI allows defining nested objects in fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage in a GitHub Workflow
&lt;/h2&gt;

&lt;p&gt;In order to sign a new commit in your workflow, you can add a step to call the mutation using the &lt;code&gt;gh&lt;/code&gt; CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;statuses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;committing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;edit file&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "hello" &amp;gt;&amp;gt; README.md&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;commit&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;gh api graphql \&lt;/span&gt;
          &lt;span class="s"&gt;-F $githubRepository=$GITHUB_REPOSITORY \&lt;/span&gt;
          &lt;span class="s"&gt;-F branchName=$BRANCH \&lt;/span&gt;
          &lt;span class="s"&gt;-F expectedHeadOid=$(git rev-parse HEAD) \&lt;/span&gt;
          &lt;span class="s"&gt;-F commitMessage="chore: commit file" \&lt;/span&gt;
          &lt;span class="s"&gt;-F files[][path]="README.md" -F files[][contents]=$(base64 -w0 README.md) \&lt;/span&gt;
          &lt;span class="s"&gt;-F files[][path]="HELLO.md" -F files[][contents]=$(base64 -w0 HELLO.md) \&lt;/span&gt;
          &lt;span class="s"&gt;-F 'query=@.github/api/createCommitOnBranch.gql'&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.token }}&lt;/span&gt;
        &lt;span class="na"&gt;BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This commit will be signed by &lt;code&gt;github-actions[bot]&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>github</category>
      <category>githubactions</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Next.js: consequence of Next/Image on your CSP</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Thu, 04 Apr 2024 13:29:11 +0000</pubDate>
      <link>https://dev.to/0xdbe/nextjs-consequence-of-nextimage-on-your-csp-5d6m</link>
      <guid>https://dev.to/0xdbe/nextjs-consequence-of-nextimage-on-your-csp-5d6m</guid>
      <description>&lt;p&gt;The &lt;code&gt;Next/Image&lt;/code&gt; component is a crucial part of the Next.js framework, offering image optimization functionalities.&lt;br&gt;
However, utilizing this component can have significant implications for Content Security Policy (CSP).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is documented as an ADR (Architectural Decision Record) because, in my perspective, this represents a crucial security decision.&lt;br&gt;
This includes the context of how the decision was made and the consequences of adopting it&lt;br&gt;
Feel free to share this ADR with your team members if you find it beneficial.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Issue
&lt;/h2&gt;

&lt;p&gt;To understand the implications of &lt;code&gt;Next/Image&lt;/code&gt;, let's examine the following example extracted from the default Next.js template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Image&lt;/span&gt;
  &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/next.svg"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Next.js Logo"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component generates the following HTML code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Next.js Logo"&lt;/span&gt;
  &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color:transparent"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/next.svg"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As observed, the outcome contains an unsafe inline style used to conceal the &lt;code&gt;alt&lt;/code&gt; text.&lt;/p&gt;

&lt;p&gt;There are another properties translated into inline style by &lt;code&gt;Next/Image&lt;/code&gt;.&lt;br&gt;
For example, &lt;code&gt;fill&lt;/code&gt; property is translated by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"position:absolute;height:100%;width:100%;left:0;top:0;right:0;bottom:0;object-fit:contain;color:transparent"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Considered Options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Unsafe Inline
&lt;/h3&gt;

&lt;p&gt;The simplest approach is to allow the &lt;code&gt;unsafe-inline&lt;/code&gt; keyword for &lt;code&gt;style-src&lt;/code&gt; directive.&lt;br&gt;
However, this leaves you vulnerable to CSS injection attacks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Unsafe Hashes
&lt;/h3&gt;

&lt;p&gt;Since styles for images are predetermined, we can pre-compute hashes for styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo -n "color:transparent" | openssl dgst -sha256 -binary | openssl base64 -A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subsequently, you can append the following content to your CSP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style-src 'self' 'sha256-zlqnbDt84zf1iSefLU/ImC54isoprH/MRiVZGskwexk=' 'unsafe-hashes'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, the &lt;code&gt;unsafe-hashes&lt;/code&gt; keyword is necessary to permit hashes for the &lt;code&gt;style&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove Style
&lt;/h3&gt;

&lt;p&gt;Even without utilizing any properties that generate inline style, there's only one persistent style attribute that you can't eliminate: &lt;code&gt;color:transparent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To remove the style attribute, it is possible to create a new component called &lt;code&gt;ImageNoStyle&lt;/code&gt;, which omits the style attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ImageNoStyle.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NextImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getImageProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ComponentProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ImageNoStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;NextImage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getImageProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_omit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;delegated&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextProps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;delegated&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component uses &lt;code&gt;getImageProps()&lt;/code&gt;, available from Next.js 14.1, to generate image properties and omit the style attribute.&lt;br&gt;
Then, &lt;code&gt;ImageNoStyle&lt;/code&gt; can be used like this with the same properties as &lt;code&gt;NextImage&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ImageNoStyle&lt;/span&gt;
  &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/next.svg"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Next.js Logo"&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;{180}&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;{37}&lt;/span&gt;
  &lt;span class="na"&gt;priority&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it's worth noting that this workaround removes inline style for images.&lt;br&gt;
Consequently, this workaround can modify rendering of an existing website.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML Tag
&lt;/h3&gt;

&lt;p&gt;The basic HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag can be used to embed an image in react component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision
&lt;/h2&gt;

&lt;p&gt;Pending a resolution for issues &lt;a href="https://github.com/vercel/next.js/issues/61388"&gt;61388&lt;/a&gt; and &lt;a href="https://github.com/vercel/next.js/issues/45184"&gt;45184&lt;/a&gt;, it's advisable to refrain from using &lt;code&gt;Next/Image&lt;/code&gt;.&lt;br&gt;
Employing the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; HTML tag helps maintain a strict CSP (Content Security Policy).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This decision is relevant to a new application.&lt;br&gt;
For existing applications, the choice may differ, particularly if image optimization is already in use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Consequence
&lt;/h2&gt;

&lt;p&gt;Opting for the basic &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; HTML tag means foregoing the image optimization features provided by Next.js, as outlined in the &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images"&gt;image optimization&lt;/a&gt; documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/vercel/next.js/discussions/61209"&gt;inline style color:transparent in Image #61209&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vercel/next.js/issues/45184"&gt;CSP error when using next/image #45184&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vercel/next.js/issues/61388"&gt;next/Image uses unsafe inline style #61388&lt;/a&gt; on GitHub&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images"&gt;Image Optimization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>nextjs</category>
      <category>appsec</category>
    </item>
    <item>
      <title>Next.js: Crafting a Strict CSP</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Thu, 07 Mar 2024 15:56:21 +0000</pubDate>
      <link>https://dev.to/0xdbe/nextjs-crafting-a-strict-csp-49lg</link>
      <guid>https://dev.to/0xdbe/nextjs-crafting-a-strict-csp-49lg</guid>
      <description>&lt;p&gt;Next.js lacks many built-in security measures. In fact, it doesn't offer predefined configurations for your Content Security Policy (CSP). Consequently, setting up CSP becomes your responsibility.&lt;br&gt;
Let's explore how we can implement a CSP.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To ensure a Content Security Policy that aligns with the current standards, we need to meet the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;must include a nonce because Next.js often utilizes inline scripts, such as those for &lt;a href="https://0xdbe.github.io/NextJS-CSP-AppRouter/"&gt;AppRouter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;must be delivered through an HTTP Header. Avoid embedding a CSP in a &lt;code&gt;meta&lt;/code&gt; tag with &lt;code&gt;http-equiv&lt;/code&gt; as it lacks support for crucial features, such as violation reports and frame-ancestors directive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Middleware
&lt;/h2&gt;

&lt;p&gt;In Next.js, middleware allows you to execute a function before a request is completed. In our case, a middleware will be used to generate a random nonce and then create HTTP headers before the page renders.&lt;/p&gt;

&lt;p&gt;Here is the middleware function, which can be adjusted if a middleware chain is used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: middleware.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// step 1&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// step 2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reportUri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getReportUri&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Report-To&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;getReportToHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reportUri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// step 3&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getNonce&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// step 4&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Security-Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nf"&gt;getContentSecurityPolicyHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reportUri&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="nx"&gt;response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Helper functions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize Response
&lt;/h3&gt;

&lt;p&gt;The first step involves initializing the response using the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initResponse&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&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;Using &lt;code&gt;NextResponse.next()&lt;/code&gt; is suitable, in this case, to create an empty response. Although if you're using a chain middleware where the response is already initialized, you might skip this step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Define CSP Violation Reporting
&lt;/h3&gt;

&lt;p&gt;The second step is defining where CSP violation reports will be sent.&lt;/p&gt;

&lt;p&gt;Here's the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getReportToHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reportUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reportTo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;csp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10886400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//1 day&lt;/span&gt;
    &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reportUri&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reportTo&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;Certain providers like Sentry or Datadog offer the capability to collect information on CSP (Content-Security-Policy) violations. Remember, if you're testing violation reports, they won't be sent if you're using &lt;code&gt;localhost&lt;/code&gt; hostname or an insecure protocol like &lt;code&gt;http&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Generate Nonce
&lt;/h3&gt;

&lt;p&gt;The third step involves generating a random nonce using &lt;code&gt;randomUUID()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getNonce&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Generate CSP Content
&lt;/h3&gt;

&lt;p&gt;The final step is to generate the content of the CSP, which is perhaps the most intricate task.&lt;/p&gt;

&lt;p&gt;Here's a function to define the CSP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContentSecurityPolicyHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;reportUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Default CSP for Next.js&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'none'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frame-ancestors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'none'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;font-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form-action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frame-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;manifest-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'none'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;report-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reportUri&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// for old browsers like Firefox&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;report-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;csp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// for modern browsers like Chrome&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;`'nonce-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;`'strict-dynamic'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// force hashes and nonces over domain host lists&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`'self'`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Webpack use eval() in development mode for automatic JS reloading&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`'unsafe-eval'`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_VERCEL_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://vercel.live&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://*.pusher.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://vercel.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;font-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://vercel.live&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frame-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://vercel.live&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style-src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://vercel.live&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contentSecurityPolicyDirective&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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;If you need to complete the default CSP, use the push method to add additional sources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Page Render
&lt;/h2&gt;

&lt;p&gt;Once we have middleware that creates a CSP with a nonce, we need to include this nonce on pages. Every time a page is viewed, a fresh nonce should be generated. This means you must use dynamic rendering to add nonces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// file: app/layout.tsx
export const dynamic = 'force-dynamic'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this option, Next.js will be able to insert a random number on the rendered page.&lt;/p&gt;

&lt;p&gt;To achieve this, Next.js utilizes &lt;a href="https://github.com/vercel/next.js/blob/v14.1.0/packages/next/src/server/app-render/get-script-nonce-from-header.tsx"&gt;getScriptNonceFromHeader&lt;/a&gt; to extract the nonce from the CSP HTTP header.&lt;br&gt;
Then, &lt;a href="https://github.com/vercel/next.js/blob/7744cc91beae7169c264e4a7508ef55256c4ab42/packages/next/src/server/app-render/app-render.tsx"&gt;AppRender&lt;/a&gt; includes the nonce in all script elements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Keep in mind that dynamic rendering can increase hosting costs. For example, on Vercel, page rendering is done as a serverless function.&lt;/p&gt;

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

&lt;p&gt;Next.js is not designed to use a strict Content-Security-Policy, which may discourage many software engineers. I hope this article can help some of them who might be tempted to use the &lt;code&gt;unsafe-inline&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;If you haven't yet selected a framework for your next secure app, consider avoiding Next.js and opting for a better-suited one, although I haven't identified it yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy"&gt;Configuring Content Security Policy&lt;/a&gt; from &lt;a href="https://nextjs.org/"&gt;nextjs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://content-security-policy.com/examples/meta/"&gt;Example a CSP header with a meta tag&lt;/a&gt; from &lt;a href="https://content-security-policy.com/"&gt;CSP Reference Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Next.js: consequence of AppRouter on your CSP</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Thu, 07 Mar 2024 15:26:02 +0000</pubDate>
      <link>https://dev.to/0xdbe/nextjs-consequence-of-approuter-on-your-csp-839</link>
      <guid>https://dev.to/0xdbe/nextjs-consequence-of-approuter-on-your-csp-839</guid>
      <description>&lt;p&gt;With the integration of AppRouter, Next.js undergoes significant internal changes in component loading and management.&lt;br&gt;
Underneath, AppRouter defaults to employing SSR (Server-Side Rendering) and leverages React Server Components (RSC).&lt;br&gt;
However, this transition brings about consequential impacts on CSP (Content Security Policy).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is written down as an ADR (Architectural Decision Record) because, from my point of view, this is an important security decision.&lt;br&gt;
This includes the context of how the decision was made and the consequences of adopting the decision.&lt;br&gt;
So, if you find it useful, you can share this ADR with your team members, and perhaps it will prove to be an effective strategy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Issue
&lt;/h2&gt;

&lt;p&gt;All Server Components are loaded using an inline script as depicted below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__next_f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1:HL[
            &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;/_next/static/media/c9a5bc6a7c948fb0-s.p.woff2&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,
            &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;font&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;crossOrigin&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"\"&lt;/span&gt;&lt;span class="s2"&gt;,
            &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;font/woff2&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}
           ]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;
         2:HL[
            &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;/_next/static/css/0a4b1961022ab8f5.css&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,
            &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;style&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;
           ]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;
         0:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;$L3&lt;/span&gt;&lt;span class="se"&gt;\"\n&lt;/span&gt;&lt;span class="s2"&gt;
        &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script invokes &lt;code&gt;self.__next_f.push()&lt;/code&gt; with the RSC payload, consisting of serialized HTML content.&lt;br&gt;
From a security standpoint, this presents an issue due to the presence of an unsafe inline script.&lt;/p&gt;
&lt;h2&gt;
  
  
  Considered Options
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Disable AppRouter
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;create-next-app&lt;/code&gt;, it's always an option to create a Next.js app without AppRouter.&lt;br&gt;
When prompted, select &lt;code&gt;No&lt;/code&gt; to the following question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Would you like to use App Router? (recommended)  No / Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This choice replaces the AppRouter with the old PageRouter.&lt;br&gt;
However, it's worth noting that this is not recommended by Next.js, as the PageRouter may potentially be deprecated in future releases.&lt;/p&gt;
&lt;h3&gt;
  
  
  Disable SSR
&lt;/h3&gt;

&lt;p&gt;In order to disable Server Side Rendering, add &lt;code&gt;use client&lt;/code&gt; in each component and layout.&lt;br&gt;
Unfortunately, this means forfeiting the benefits of SSR.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use unsafe-inline
&lt;/h3&gt;

&lt;p&gt;The simplest way to make AppRouter work is by adding &lt;code&gt;unsafe-inline&lt;/code&gt;.&lt;br&gt;
However, this keyword disables protection against XSS (Cross-Site Scripting).&lt;/p&gt;
&lt;h3&gt;
  
  
  Use nonce
&lt;/h3&gt;

&lt;p&gt;Another option to allow inline script is to use a nonce.&lt;br&gt;
A nonce is a unique, random string of characters created for one-time use.&lt;/p&gt;

&lt;p&gt;This nonce must be inserted in the HTTP Header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;script-src: nonce-1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And also in the HTML document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script nonce="1234"&amp;gt;
  //...
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decision
&lt;/h2&gt;

&lt;p&gt;Among the considered options, the only safe solution is to use a CSP with nonce in the &lt;code&gt;script-src&lt;/code&gt; directive.&lt;br&gt;
While nonces should generally be avoided in a CSP, Next.js doesn't currently provide any secure alternatives, and nonces are the only solution to maintain a strict CSP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequence
&lt;/h2&gt;

&lt;p&gt;In order to generate a random nonce for each request, a static storage solution like Bucket S3 can no longer be used to host a Next.js application.&lt;br&gt;
Thus, an application runtime is now required, potentially increasing hosting costs.&lt;br&gt;
Additionally, pages including a random nonce cannot be cached through a CDN (Content Delivery Network).&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"&gt;Cross Site Scripting Prevention Cheat Sheet&lt;/a&gt; from &lt;a href="https://cheatsheetseries.owasp.org"&gt;OWASP Cheat Sheet Series&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://content-security-policy.com/unsafe-inline/"&gt;The CSP unsafe-inline Source List Keyword&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce"&gt;Nonce attribute&lt;/a&gt; from &lt;a href="https://developer.mozilla.org"&gt;MDN&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy"&gt;Configuring Content Security Policy&lt;/a&gt; from &lt;a href="https://nextjs.org/"&gt;nextjs.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel/next.js/discussions/42170"&gt;NEXTJS 13: self.__next_f.push&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giuseppegurgone.com/react-server-component-explained"&gt;React Server Components, Explained&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>GitHub: How To Enable Code Scanning With Semgrep</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Wed, 09 Nov 2022 12:52:22 +0000</pubDate>
      <link>https://dev.to/0xdbe/github-how-to-enable-code-scanning-with-semgrep-501d</link>
      <guid>https://dev.to/0xdbe/github-how-to-enable-code-scanning-with-semgrep-501d</guid>
      <description>&lt;p&gt;Semgrep is an incredible static analysis engine that can be used for finding bugs, detecting vulnerabilities and even for enforcing code standards.&lt;br&gt;
Semgrep is a Swiss army knife for static code analysis.&lt;/p&gt;

&lt;p&gt;This article describes how to automate the discovery of coding vulnerabilities with Semgrep and GitHub Workflows.&lt;br&gt;
For this, we will need 2 workflows: full scan and differential scan.&lt;/p&gt;
&lt;h2&gt;
  
  
  Full scan
&lt;/h2&gt;

&lt;p&gt;The first workflow is dedicated to scan all the codebase of your application and provides a global analysis of the existing.&lt;/p&gt;

&lt;p&gt;To create this workflow, paste the following content in &lt;code&gt;.github/workflows/semgrep-full.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Semgrep Full Scan&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;6'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;semgrep-full&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
      &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;returntocorp/semgrep&lt;/span&gt;

      &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

        &lt;span class="c1"&gt;# step 1&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clone application source code&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

        &lt;span class="c1"&gt;# step 2&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;full scan&lt;/span&gt;
          &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;semgrep \&lt;/span&gt;
              &lt;span class="s"&gt;--sarif --output report.sarif \&lt;/span&gt;
              &lt;span class="s"&gt;--metrics=off \&lt;/span&gt;
              &lt;span class="s"&gt;--config="p/default"&lt;/span&gt;

        &lt;span class="c1"&gt;# step 3&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;save report as pipeline artifact&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v3&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;report.sarif&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;report.sarif&lt;/span&gt;

        &lt;span class="c1"&gt;# step 4&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish code scanning alerts&lt;/span&gt;
          &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v2&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;report.sarif&lt;/span&gt;
            &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;semgrep&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can manually trigger this workflow to run a first full scan. All findings will be published in the &lt;code&gt;Code Scanning alerts&lt;/code&gt; in the &lt;code&gt;Security&lt;/code&gt; tab of your GitHub repository.&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%2Fj6sc8xe1efee5vwmw6u4.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%2Fj6sc8xe1efee5vwmw6u4.png" alt="Code Scanning Alerts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This workflow is also scheduled to run a full scan every Saturday at 1:00 AM. And the result is sync with the &lt;code&gt;Code Scanning Alerts&lt;/code&gt; dashboard. New findings are published and fixed findings are automatically closed. This is an immensely cool feature!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Code Scanning alerts&lt;/code&gt; is free for public repositories but organisations must subscribe to &lt;code&gt;GitHub Advanced Security&lt;/code&gt; which is a very expensive add-on. If you don't have this option, and you don’t want to subscribe, you can use another security dashboard like Defect Dojo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;... and it’s that simple. The first workflow is now operational! &lt;/p&gt;

&lt;p&gt;Now, you’ll probably discover that you have a lot of findings in your &lt;code&gt;Code Scanning Alerts&lt;/code&gt; dashboard. We know that it will not be possible to fix all of them immediately. Fixing those will probably need several weeks of work. That is why this workflow can't block the software pipeline. However, thanks to this workflow, you can follow your progress because, each week, fixed alerts are automatically closed.&lt;/p&gt;

&lt;p&gt;While waiting for these corrections, you can block all &lt;em&gt;Pull Requests&lt;/em&gt; which could add new findings. For that, we can write a second workflow to run a differential scan in order to report only findings in the Pull Requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differential scan
&lt;/h2&gt;

&lt;p&gt;The second workflow is dedicated to analyse Pull Requests.&lt;/p&gt;

&lt;p&gt;To create this workflow, paste the following content in &lt;code&gt;.github/workflows/semgrep-diff.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Semgrep Differential Scan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;pull_request&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;semgrep-diff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;returntocorp/semgrep&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="c1"&gt;# step 1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clone application source code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="c1"&gt;# step 2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;differential scan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;semgrep scan \&lt;/span&gt;
            &lt;span class="s"&gt;--error \&lt;/span&gt;
            &lt;span class="s"&gt;--metrics=off \&lt;/span&gt;
            &lt;span class="s"&gt;--baseline-commit ${{ github.event.pull_request.base.sha }} \&lt;/span&gt;
            &lt;span class="s"&gt;--config="p/default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, Semgrep performs two scans: one on the Pull Request and another on the existing codebase before the Pull Request. Therefore, only new findings are reported.&lt;/p&gt;

&lt;p&gt;Now, you can protect your default branch &lt;code&gt;main&lt;/code&gt; in your repository &lt;code&gt;settings&lt;/code&gt;, by adding &lt;code&gt;semgrep-diff&lt;/code&gt; in &lt;code&gt;Require status checks to pass before merging&lt;/code&gt;.&lt;br&gt;
By the way, you can also check &lt;code&gt;Do not allow bypassing the above settings&lt;/code&gt; to prevent Semgrep bypass.&lt;br&gt;
After that, it will not be possible to merge thes Pull Requests with new findings:&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%2Fzrx86g9daplxnzwdl03v.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%2Fzrx86g9daplxnzwdl03v.png" alt="Pull Request Failed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have setup Semgrep on your GitHub repository with two workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A workflow to perform a full scan on the existing codebase&lt;/li&gt;
&lt;li&gt;A workflow to perform a differential scan on Pull Request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Semgrep with GitHub this way provides more flexibility. As you can see, you can enable code scanning without having to fix all of the findings on your existing codebase.&lt;/p&gt;

&lt;p&gt;Take the time to assess the risks of each finding in order to prioritise them. In the meantime, you will be sure that there will be no additional findings in your repository, and you can even change the rules without freezing any developments.&lt;/p&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>github</category>
    </item>
    <item>
      <title>Spring Boot: Prevent Log Injection Attacks With Logback</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Sun, 13 Mar 2022 20:46:46 +0000</pubDate>
      <link>https://dev.to/0xdbe/spring-boot-prevent-log-injection-attacks-with-logback-m71</link>
      <guid>https://dev.to/0xdbe/spring-boot-prevent-log-injection-attacks-with-logback-m71</guid>
      <description>&lt;p&gt;Log Injection is an attack that has been known to everyone for years.&lt;br&gt;
Despite the fact that any application can record logs from user input, for too long many of us had forgotten about the dangers.&lt;br&gt;
But the recently discovered vulnerabilities concerning log4j2 have reminded us of the importance of preventing log injection attacks.&lt;br&gt;
This article describes one concrete way - albeit not the only way - to prevent log injection attacks in a Spring Boot application using Logback.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is written down as an ADR (Architectural Decision Record) because, from my point of view, this is an important security decision.&lt;br&gt;
This includes the context of how the decision was made and the consequences of adopting the decision.&lt;br&gt;
So, if you find it useful, you can share this ADR with your team members, and perhaps it will prove to be an effective strategy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;By default, a Spring Boot application uses Logback as a logging framework, and it does this with SLF4J as the interface between the application and the logging framework.&lt;/p&gt;

&lt;p&gt;In this way, an application can easily log anything in two steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a logger with &lt;code&gt;LoggerFactory.getLogger()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Log event with &lt;code&gt;logger.debug()&lt;/code&gt; (where &lt;code&gt;debug&lt;/code&gt; is the log level)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example that can be found in a simple greeting controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this controller takes the username as the input and then logs it.&lt;/p&gt;

&lt;p&gt;Consequently, due to this controller logging data from user input, this application is vulnerable to log injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attack
&lt;/h2&gt;

&lt;p&gt;Primarily, log injection allows an attacker to forge log entries; this is what we call "log forging.” The easiest way is to forge a new log entry using CRLF injection. &lt;/p&gt;

&lt;p&gt;CRLF injection involves inserting two control characters called &lt;code&gt;Carriage Return&lt;/code&gt; (&lt;code&gt;%0d&lt;/code&gt; or &lt;code&gt;\r&lt;/code&gt;) and &lt;code&gt;Line Feed&lt;/code&gt; (&lt;code&gt;%0a&lt;/code&gt; or &lt;code&gt;\n&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Here is an example of an CRLF injection on our greeting controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/&lt;span class="se"&gt;\?&lt;/span&gt;name&lt;span class="se"&gt;\=&lt;/span&gt;Marty%0d%0aYou%20have%20been%20pwned
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This request results in the logging of two separate entries in the logger.&lt;br&gt;
This could be annoying when later doing log analysis because there would be additional incorrect log entries.&lt;/p&gt;

&lt;p&gt;However, despite being primarily used to forge entries, sometimes, log injection attacks can also be used to inject malicious code that could then be executed either by the logging framework (like log4j2) or later in the logging pipeline.&lt;/p&gt;

&lt;p&gt;So, it is vital to prevent log injection attacks with a suitable defensive solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  Considered options
&lt;/h2&gt;

&lt;p&gt;There are many ways to prevent log injection attacks, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input validation&lt;/strong&gt; involves checking that user inputs are in the expected format (mail, date, price, value from a list, ...). This is a good thing! However, for some types of data (like comments), input validation is too difficult and would not be very effective. Of course, you can keep going with input validation, but this is not enough to secure an application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input filtering&lt;/strong&gt; involves stripping out unsafe characters. This is well-intentioned, but sometimes mangles perfectly good input. For example, if the filtering function strips the &lt;code&gt;''&lt;/code&gt;, someone like &lt;code&gt;O'Conor&lt;/code&gt; becomes &lt;code&gt;OConor&lt;/code&gt;. Something that I doubt they would appreciate.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These solutions are not acceptable if you want to build secure software.&lt;/p&gt;
&lt;h2&gt;
  
  
  Decision
&lt;/h2&gt;

&lt;p&gt;The best way to prevent log injection is &lt;em&gt;output encoding&lt;/em&gt;.&lt;br&gt;
It is really easy to do with Logback!&lt;/p&gt;

&lt;p&gt;Here is the configuration file &lt;code&gt;logback.xml&lt;/code&gt; to encode logs using &lt;code&gt;json&lt;/code&gt; layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;appender&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"console"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.ConsoleAppender"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;encoder&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.encoder.LayoutWrappingEncoder"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;layout&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.contrib.json.classic.JsonLayout"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;jsonFormatter&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.contrib.jackson.JacksonJsonFormatter"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;appendLineSeparator&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/appendLineSeparator&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/layout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/encoder&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/appender&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;root&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"info"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;appender-ref&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"console"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And here is the dependencies required by Logback to support JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'ch.qos.logback.contrib:logback-json-classic:0.1.5'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'ch.qos.logback.contrib:logback-jackson:0.1.5'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, each log entry is wrapped up in a JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1643015604000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"DEBUG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"thread"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"http-nio-8080-exec-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logger"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"net.example.logging.HelloController"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Hello Marty&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;You have been pwned"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, special characters, like CRLF, are escaped.&lt;br&gt;
This will be the same for quotation marks which will be encoded by &lt;code&gt;\"&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Consequences
&lt;/h2&gt;

&lt;p&gt;From this point onwards, this application is no longer vulnerable to log injection anymore.&lt;br&gt;
However, there are consequences to consider.&lt;/p&gt;
&lt;h3&gt;
  
  
  Unreadable logs
&lt;/h3&gt;

&lt;p&gt;Since each log entry is wrapped up in a JSON object, it becomes difficult to use logs with simple tools like &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt; or &lt;code&gt;grep&lt;/code&gt;.&lt;br&gt;
So, a log management system, such as ELK (Elasticsearch, Logstash and Kibana), is mandatory.&lt;/p&gt;

&lt;p&gt;However, it is still possible to have several configurations using Spring Profile in &lt;code&gt;logback-spring.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;springProfile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"!local"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Configuration with JSON Layout --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/springProfile&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;springProfile&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"local"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Configuration with Pattern Layout --&amp;gt;&lt;/span&gt;.
  &lt;span class="nt"&gt;&amp;lt;/springProfile&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this case, Spring Boot Application uses the default pattern layout when it starts locally.&lt;br&gt;
Thus making logs easier to read for developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensitive Data
&lt;/h3&gt;

&lt;p&gt;Keep in mind that this &lt;code&gt;JSON Layout&lt;/code&gt; doesn't mask sensitive data in log entries.&lt;br&gt;
A custom layout will still be required to mask sensitive line PII. &lt;/p&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>spring</category>
    </item>
    <item>
      <title>Angular Security - Serve application locally over HTTPS</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Thu, 09 Sep 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/0xdbe/angular-security-serve-application-locally-over-https-3dj</link>
      <guid>https://dev.to/0xdbe/angular-security-serve-application-locally-over-https-3dj</guid>
      <description>&lt;p&gt;When you develop an Angular application, you will come to a point where you need to serve it on localhost over HTTPS. This is often the case if you need to interact with an identity provider such as Facebook, Auth0, ... And by the way, testing locally with HTTPS could be useful to detect mixed content issues that can break a production HTTPS website.&lt;/p&gt;

&lt;p&gt;This article will walk you through setting Angular to use locally-trusted development certificate with &lt;code&gt;mkcert&lt;/code&gt;. This is an easy way to expose an application over HTTPS without security warnings and you don't worry too much about OpenSSL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install mkcert
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/FiloSottile/mkcert"&gt;mkcert&lt;/a&gt; is a simple tool for making locally-trusted development certificates.&lt;br&gt;
This tool is written by Filippo Valsorda, Cryptographer and Go security leader. Follow instructions on &lt;a href="https://github.com/FiloSottile/mkcert#installation"&gt;https://github.com/FiloSottile/mkcert#installation&lt;/a&gt; to install this tool.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create local certificate authority
&lt;/h2&gt;

&lt;p&gt;Run this command to create a new local certificate authority (CA):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkcert &lt;span class="nt"&gt;-install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command did the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate CA certificate and its key, and store them in an application data folder in the user home, such as &lt;code&gt;~/.local/share/mkcert/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add this new certificate authority in trust stores (system, Firefox, Chrome, ...). So, all certificates issue with this CA will be trusted by your browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be aware that the &lt;code&gt;rootCA-key.pem&lt;/code&gt; file that &lt;code&gt;mkcert&lt;/code&gt; automatically generates gives complete power to intercept secure requests from your machine. So, do not share it to stay safe against MITM (Man-in-the-middle) attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get certificate
&lt;/h2&gt;

&lt;p&gt;Run the following commands from Angular project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;tls
mkcert &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-cert-file&lt;/span&gt; ./tls/localhost-cert.pem &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-key-file&lt;/span&gt; ./tls/localhost-key.pem &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-ecdsa&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      localhost 127.0.0.1 ::1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This certificate will expire in 3 months. In order to make renewal easier, we can create a shortcut for this command in &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run cert &amp;amp; ng serve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mkdir -p ./tls &amp;amp; mkcert -cert-file ./tls/localhost-cert.pem -key-file ./tls/localhost-key.pem -ecdsa localhost 127.0.0.1 ::1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus, you get a new certificate each time you start your application&lt;/p&gt;

&lt;p&gt;Don't forget to add &lt;code&gt;tls/*&lt;/code&gt;in &lt;code&gt;.gitignore&lt;/code&gt; to prevent publication of your private key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serve application
&lt;/h2&gt;

&lt;p&gt;In order to serve Angular application securely, add &lt;code&gt;ssl&lt;/code&gt;, &lt;code&gt;sslCert&lt;/code&gt; and &lt;code&gt;sslKey&lt;/code&gt; options to &lt;code&gt;serve&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--ssl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--sslCert&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./tls/localhost-cert.pem &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;--sslKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./tls/localhost-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid to write these options each time that we want to run this app over HTTPS, we can set them in the &lt;code&gt;angular.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"serve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"builder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@angular-devkit/build-angular:dev-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ssl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sslCert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tls/localhost-cert.pem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sslKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tls/localhost-key.pem"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like so, you can easily serve your app by using &lt;code&gt;npm start&lt;/code&gt; and then, browse &lt;a href="https://localhost:4200/"&gt;https://localhost:4200/&lt;/a&gt; without security warning. But keep in mind that this could be used only for local development, not for production.&lt;/p&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Security - Disable Inline Critical CSS</title>
      <dc:creator>0xdbe</dc:creator>
      <pubDate>Mon, 06 Sep 2021 20:11:22 +0000</pubDate>
      <link>https://dev.to/0xdbe/angular-security-disable-inline-critical-css-2n9g</link>
      <guid>https://dev.to/0xdbe/angular-security-disable-inline-critical-css-2n9g</guid>
      <description>&lt;p&gt;Improving load time is crucial for the success of your application. One way to reduce this load time is to optimize the CSS loading but it is quite tricky, because CSS files are render-blocking. This means that the browser must download and parse these files before starting to render the web page.&lt;/p&gt;

&lt;p&gt;That's why Angular provides CSS optimization in order to reduce this render-blocking delay, and at the same time, to improve the First Contentful Paint (FCP). This optimization involves first inlining critical CSS and delaying the loading of non-critical CSS.&lt;/p&gt;

&lt;p&gt;This article describes what's wrong with this optimization and how to disable it to keep a strict CSP (Content Security Policy).&lt;/p&gt;

&lt;h2&gt;
  
  
  What's wrong?
&lt;/h2&gt;

&lt;p&gt;Inline Critical CSS is an optimization that impacts our CSP (Content Security Policy):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style-src-elem 'unsafe-inline';    // For Inlining critical CSS
script-src     'unsafe-inline';    // For Delaying non-critical CSS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To understand why it is necessary, let's take a look at these practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inlining critical CSS
&lt;/h3&gt;

&lt;p&gt;During the build process, Angular extracts first all CSS resources that block the rendering. Once critical CSS are extracted, Angular inlines them directly in the &lt;code&gt;index.html&lt;/code&gt; file. In order to authorize inline CSS, we have to add the following content in our CSP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;style-src-elem 'unsafe-inline';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, our CSP is not able to block &lt;a href="https://www.netsparker.com/blog/web-security/private-data-stolen-exploiting-css-injection/"&gt;CSS injections&lt;/a&gt; anymore. This problem is not new since inline CSS is used by Angular for Component Style. So, inlining critical CSS should not further affect our CSP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delaying non-critical CSS
&lt;/h3&gt;

&lt;p&gt;After inlining critical CSS, the rest can be postponed. However, HTML and CSS don't support asynchronous loading for CSS files. To circumvent this issue, there is an Angular trick to load non-critical CSS asynchronously using &lt;code&gt;media&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
  &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.1d6c8a3b8017c43eaeda.css"&lt;/span&gt;
  &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"print"&lt;/span&gt;
  &lt;span class="na"&gt;onload=&lt;/span&gt;&lt;span class="s"&gt;"this.media='all'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Media type (&lt;code&gt;print&lt;/code&gt;) doesn’t match the current environment, so the browser decides that it is less important and loads the stylesheet asynchronously, without delaying the page rendering. On load, we change media type so that the stylesheet gets applied to screens. In order to authorize event handlers that run inline script, we have to include the following content in our CSP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;script-src 'unsafe-inline';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration almost defeats the purpose of CSP, thus we could be exposed to XSS attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix this?
&lt;/h2&gt;

&lt;p&gt;For security purposes, inline critical CSS must be disabled to keep a strict CSP.&lt;/p&gt;

&lt;p&gt;Inline critical CSS is a new optimization introduced in Angular 11.1. However it was disabled by default. This optimization is now enabled by default in v12 and you have to set &lt;code&gt;inlineCritical&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; in &lt;code&gt;angular.json&lt;/code&gt; for each configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"optimization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"minify"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"inlineCritical"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fonts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, Angular includes CSS as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we don't have to weaken our CSP!&lt;/p&gt;

</description>
      <category>security</category>
      <category>appsec</category>
      <category>angular</category>
    </item>
  </channel>
</rss>
