One place for hosting & domains

      Applications

      Comment redémarrer vos applications Node.js automatiquement avec nodemon


      Introduction

      Sous Node.js, vous devez redémarrer le processus pour que les changements prennent effet, une étape supplémentaire qui s’ajoute à votre flux de travail pour que les modifications soient implémentées. En utilisant nodemon, vous pouvez éliminer cette étape supplémentaire car il se chargera de redémarrer le processus automatiquement.

      nodemon est un utilitaire d’interface de ligne de commande (CLI) développé par @rem. Il enveloppe votre application Node, surveille le système de fichiers et redémarre automatiquement le processus.

      Cet article vous permettra d’en apprendre davantage sur l’installation, le réglage et la configuration de nodemon.

      Conditions préalables

      Pour suivre les étapes de cet article, vous aurez besoin de ce qui suit :

      Étape 1 — Installation de nodemon

      En premier lieu, vous devez installer nodemon sur votre machine. Installez l’utilitaire soit globalement ou localement sur votre projet en utilisant npm ou Yarn  :

      Installation globale

      Vous pouvez installer nodemon de manière globale avec npm :

      Ou avec Yarn :

      Installation locale

      Vous pouvez également utiliser npm pour installer nodemon localement. Pour procéder à une installation locale, nous pouvons installer nodemon sous la forme d'une dev dependency avec --save-dev (ou --dev) :

      • npm install nodemon --save-dev

      Ou avec Yarn :

      Il y a cependant une chose à retenir concernant une installation locale. Il vous sera impossible d'utiliser la commande nodemon directement à partir de la ligne de commande suivante :

      Output

      • command not found: nodemon

      Vous pouvez cependant l'utiliser dans le cadre de certains scripts npm ou avec npx.

      Vous venez de terminer le processus d'installation de nodemon. Maintenant, nous allons utiliser nodemon avec nos projets.

      Étape 2 — Configuration d'un exemple du projet Express avec nodemon

      Nous pouvons utiliser nodemon pour lancer un script Node. Si, par exemple, la configuration du serveur Express se trouve dans un fichier server.js, nous pouvons la lancer et surveiller les modifications de la manière suivante :

      Vous pouvez transmettre les arguments de la même manière que pour exécuter le script avec Node :

      Chaque fois que vous modifiez un fichier avec l'une des extensions surveillées par défaut (.js, .mjs, .json, .coffee ou .litcoffee) dans le répertoire ou le sous-répertoire actuel, le processus redémarrera.

      Supposons que nous écrivions un exemple de fichier server.js qui déclenche le message suivant : Écoute de l'application Dolphin sur le port ${port} !.

      Nous pouvons exécuter l'exemple avec nodemon :

      Nous obtiendrons le résultat suivant sur le terminal:

      Output

      [nodemon] 1.17.3 [nodemon] to restart at any time, enter `rs` [nodemon] watching: *.* [nodemon] starting `node server.js` Dolphin app listening on port 3000!

      Alors que l'exécution de nodemon est toujours cours, modifions le fichier server.js de manière à qu'il fasse apparaître le message suivant :Écoute de l'application Shark sur le port ${port} !

      Nous obtiendrons le résultat supplémentaire suivant sur le terminal :

      Output

      [nodemon] restarting due to changes... [nodemon] starting `node server.js` Shark app listening on port 3000!

      Le résultat qui apparaît sur le terminal de notre application Node.js s'affiche comme prévu. À tout moment, vous pouvez redémarrer le processus en saisissant rs et en appuyant sur ENTRÉE.

      Sinon, nodemon recherchera également le fichier main spécifié dans le fichier package.json de votre projet.

      package.json

      {
        // ...
        "main": "server.js",
        // ...
      }
      

      Ou, un script start :

      package.json

      {
        // ...
        "scripts": {
          "start": "node server.js"
        },
        // ...
      }
      

      Une fois que vous avez apporté vos modifications à package.json, vous pouvez alors appeler nodemon pour lancer l'application exemple en mode de surveillance sans avoir à passer par server.js.

      Étape 3 — Utilisation des options

      Vous pouvez modifier les paramètres de configuration disponibles sur nodemon.

      Passons en revue quelques-unes des principales options :

      • --exec: utilisez le commutateur --exec pour spécifier le binaire avec lequel exécuter le fichier. Par exemple, combiné au binaire ts-node, --exec peut s'avérer utile pour surveiller les modifications et exécuter les fichiers TypeScript.
      • --ext : spécifiez les différentes extensions de fichier à surveiller. Pour cette commutation, vous devez fournir une liste séparée par une virgule des extensions de fichiers (par exemple, --ext js,ts).
      • --delay : lorsqu'un fichier est modifié, nodemon attend par défaut 1 seconde pour redémarrer le processus. Cependant, vous pouvez utiliser le commutateur --delay pour modifier ce délai. Par exemple, avec nodemon --delay 3.2 votre délai sera de 3,2 secondes.
      • --watch : utilisez le commutateur --watch pour une surveillance sur plusieurs répertoires ou fichiers. Activez un commutateur --watch pour chaque répertoire que vous souhaitez surveiller. Par défaut, le répertoire actuel et ses sous-répertoires sont surveillés. Donc, vous pouvez utiliser --watch pour limiter la surveillance à des sous-répertoires ou des fichiers spécifiques.
      • --ignore : utilisez le commutateur --ignore pour ignorer certains fichiers, modèles de fichiers ou répertoires.
      • --verbose : un résultat plus complet avec des informations sur le ou les fichiers modifiés pour déclencher un redémarrage.

      Vous pouvez consulter toutes les options disponibles avec la commande suivante :

      À l'aide de ces options, créons la commande qui satisfait au scénario suivant :

      • surveiller le répertoire server
      • spécifier les fichiers avec l'extension .ts
      • ignorer les fichiers avec le suffixe .test.ts.
      • exécuter le fichier (server/server.ts) avec ts-node.
      • attendre trois secondes pour procéder au redémarrage après modification d'un fichier
      • nodemon --watch server --ext ts --exec ts-node --ignore '*.test.ts' --delay 3 server/server.ts

      Cette commande combine les options --watch, --ext, --exec , --ignore, et --delay pour satisfaire aux conditions de notre scénario.

      Étape 4 — Utilisation des configurations

      Dans l'exemple précédent, l'ajout des commutateurs de configuration lors de l'exécution de nodemon est un exercice qui peut s'avérer être très fastidieux. Il existe une meilleure solution pour les projets qui nécessitent des configurations spécifiques. Elle consiste à spécifier ces configurations dans un fichier nodemon.json.

      Par exemple, voici les mêmes configurations que celles de notre exemple précédent de ligne de commande, mais placées dans un fichier nodemon.json :

      nodemon.json

      {
        "watch": ["server"],
        "ext": "ts",
        "ignore": ["*.test.ts"],
        "delay": "3",
        "execMap": {
          "ts": "ts-node"
        }
      }
      

      Notez que nous utilisons execMap au lieu du commutateur --exec. execMap vous permet de spécifier les binaires à utiliser pour obtenir certaines extensions de fichier.

      Ou alors, si vous ne souhaitez pas ajouter un fichier de configuration nodemon.json à votre projet, vous pouvez ajouter ces configurations dans un fichier package.json sous une clé nodemonConfig.

      package.json

      {
        "name": "test-nodemon",
        "version": "1.0.0",
        "description": "",
        "nodemonConfig": {
          "watch": [
            "server"
          ],
          "ext": "ts",
          "ignore": [
            "*.test.ts"
          ],
          "delay": "3",
          "execMap": {
            "ts": "ts-node"
          }
        },
        // ...
      

      Une fois que vous avez apporté ces modifications à nodemon.json ou package.json, vous pouvez alors lancer nodemon avec le script que vous souhaitez :

      nodemon récupérera les configurations et les utilisera. De cette façon, vos configurations pourront être enregistrées, partagées et répétées tout en évitant les erreurs de copier-coller ou de frappe dans la ligne de commande.

      Conclusion

      Cet article vous a permis d'apprendre à utiliser nodemon avec vos applications Node.js. Cet outil aide à automatiser le processus d'arrêt et de démarrage d'un serveur Node afin de pouvoir consulter les changements.

      Pour de plus amples informations sur les fonctionnalités et les erreurs de dépannage, consultez la documentation officielle.

      Si vous souhaitez en savoir plus sur Node.js, veuillez consulter notre page thématique Node.js dans laquelle vous trouverez des exercices et des projets de programmation.





      Source link

      How To Secure Node.js Applications with a Content Security Policy


      The author selected the Free Software Foundation to receive a donation as part of the Write for DOnations program.

      Introduction

      When the browser loads a page, it executes a lot of code to render the content. The code could be from the same origin as the root document, or a different origin. By default, the browser does not distinguish between the two and executes any code requested by a page regardless of the source. Attackers use this exploit to maliciously inject scripts to the page, which are then executed because the browser has no way of determining if the content is harmful. These situations are where a Content Security Policy (CSP) can provide protection.

      A CSP is an HTTP header that provides an extra layer of security against code-injection attacks, such as cross-site scripting (XSS), clickjacking, and other similar exploits. It facilitates the creation of an “allowlist” of trusted content and blocks the execution of code from sources not present in the allowlist. It also reports any policy violations to a URL of your choice, so that you can keep abreast of potential security attacks.

      With the CSP header, you can specify approved sources for content on your site that the browser can load. Any code that is not from the approved sources, will be blocked from executing, which makes it considerably more difficult for an attacker to inject content and siphon data.

      In this tutorial, you’ll review the different protections the CSP header offers by implementing one in an example Node.js application. You’ll also collect JSON reports of CSP violations to catch problems and fix exploits quickly.

      Prerequisites

      To follow this tutorial, you will need the following:

      • A recent version of Node.js installed on your machine. Follow the steps in the relevant How To Install Node.js tutorial for your operating system to set up a Node.js development environment.

      You should also use a recent browser version, preferably Chrome, as it has the best support for CSP level 3 directives at the time of writing this article (November 2020). Also, make sure to disable any third-party extensions while testing the CSP implementation so that they don’t interfere with the violation reports rendered in the console.

      Step 1 — Setting Up the Demo Project

      To demonstrate the process of creating a Content Security Policy, we’ll work through the entire process of implementing one for this demo project. It’s a one-page website with a variety of content that approximates a typical website or application. It includes a small Vue.js application, YouTube embeds, and some images sourced from Unsplash. It also uses Google fonts and the Bootstrap framework, which is loaded over a content delivery network (CDN).

      In this step, you’ll set up the demo project on your test server or local machine and view it in your browser.

      First, clone the project to your filesystem using the following command:

      • git clone https://github.com/do-community/csp-demo

      Once your project directory is set up, change into it with the following command:

      Next, install the dependencies specified in the package.json file with the next command. You use the express package to set up the web server, while nodemon helps to automatically restart the node application when it detects file changes in the directory:

      Once the dependencies you’ve installed the dependencies, enter the following command to start the web server on port 5500:

      You can now visit your_server_ip:5500 or localhost:5500 in your browser to view the demo page. You will find the text Hello World!, a YouTube embed, and some images on the page.

      CSP Demo

      In the next section, we’ll implement a CSP policy that covers only the most basic protections. We’ll then build on that in the subsequent sections as we uncover all the legitimate resources that we need to allow on the page.

      Step 2 — Implementing a Basic CSP

      Let’s go ahead and write a CSP policy that restricts fonts, images, scripts, styles, and embeds to those originating from the current host only. The following is the response header that achieves this:

      Content-Security-Policy: default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self';
      

      Here’s an explanation of the policy directives in this header:

      • font-src defines the sources from where fonts can be loaded from.
      • img-src defines the sources from which image loading is permitted.
      • script-src controls any script-loading privileges on a web page.
      • style-src is the directive for allowing stylesheet sources.
      • frame-src defines allowed sources for frame embeds. (It was deprecated in CSP level 2, but reinstated in level 3.)
      • default-src defines a fallback policy for certain directives if they are not explicitly specified in the header. Here is a complete list of the directives that fall back to default-src.

      In this example, all the specified directives are assigned the 'self' keyword in their source list. This indicates that only resources from the current host (including the URL scheme and port number) should be allowed to execute. For example, script-src 'self' allows the execution of scripts from the current host, but it blocks all other script sources.

      Let’s go ahead and add the header to our Node.js project.

      Leave your app running and open a new terminal window to work with your server.js file:

      Next, add the CSP header from the example in an Express middleware layer. This ensures that you’re including the header in every response from the server:

      server.js

      const express = require('express');
      const bodyParser = require('body-parser');
      const path = require('path');
      const app = express();
      
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy',
          "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self'"
        );
        next();
      });
      
      app.use(bodyParser.json());
      app.use(express.static(path.join(__dirname)));
      
      app.get('/', (req, res) => {
        res.sendFile(path.join(__dirname + '/index.html'));
      });
      
      const server = app.listen(process.env.PORT || 5500, () => {
        const { port } = server.address();
        console.log(`Server running on PORT ${port}`);
      });
      

      Save the file and reload the project in your browser. You’ll notice that the page is completely broken.

      Our CSP header is working as expected and all the external sources that we included on the page have been blocked from loading because they violate the defined policy. However, this is not an ideal way to test a brand-new policy since it can break a website when violations occur.

      Broken page after adding basic CSP

      This is why the Content-Security-Policy-Report-Only header exists. You can use it instead of Content-Security-Policy to prevent the browser from enforcing the policy, while still reporting the violations that occur—this means that you can refine the policy without putting your site at risk. Once you’re happy with your policy, you can switch back to the enforcing header so that the protections are activated.

      Go ahead and replace the Content-Security-Policy header with Content-Security-Policy-Report-Only in your server.js file:

      Add the following highlighted code:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self'"
        );
        next();
      });
      . . .
      

      Save the file and reload the page in your browser. The page returns to a working state, but the browser console still reports the CSP violations. Each violation is prefixed with [Report Only] to indicate that the policy is not enforced.

      Report only mode is now active

      In this section, we created the initial implementation of our CSP and set it to report-only mode so that we can refine it without causing the site to break. In the next section, we’ll fix the violations triggered through our initial CSP.

      Step 3 — Fixing Policy Violations

      The policy we implemented in the previous section triggered several violations because we restricted all resources to the origin only—however, we have several third-party assets on the page.

      The two ways to fix CSP violations are: approving the sources in the policy, or removing the code that triggers the violations. Since legitimate resources are triggering all the violations, we’ll concentrate mainly on the former option in this section.

      Open up your browser console. It will display all the current violations of the CSP. Let’s fix each of these issues.

      Allowing the Stylesheets

      The first two violations in the console are from the Google fonts and Bootstrap stylesheets, which you’re loading from https://fonts.googleapis.com and https://cdn.jsdelivr.net respectively. You can allow them both on the page through the style-src directive:

      style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net;
      

      This specifies that CSS files from the origin host, https://fonts.googleapis.com, and https://cdn.jsdelivr.net, should be executed on the page. This policy is quite broad, because it allows any stylesheet from the allowlist domains (not just the ones you’re currently using).

      We can be more specific by using the exact file or directory we’d like to allow instead:

      style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css;
      

      Now, it will only allow the exact, specified stylesheet to execute. It will block all other stylesheets—even if they originate from https://cdn.jsdelivr.net.

      You can update the CSP header like the following with the updated style-src directive. By the time you reload the page, both violations will be resolved:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self';"
        );
        next();
      });
      . . .
      

      Allowing the Image Sources

      The images you’re using on the page are from a single source: https://images.unsplash.com. Let’s allow it through the img-src directive like the following:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self'; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self'"
        );
        next();
      });
      . . .
      

      Allowing the Youtube Embed

      You can allow valid sources for nested browsing contexts, which use elements such as <iframe>, through the frame-src directive. If this directive is absent, the browser will look for the child-src directive, which subsequently falls back to the default-src directive.

      Our current policy limits frame embeds to the origin host. Let’s add https://www.youtube.com to the allowlist so that the CSP doesn’t block Youtube embeds from loading once we enforce the policy:

      frame-src 'self' https://www.youtube.com;
      

      Note that the www subdomain is significant here. If you have an embed from https://youtube.com, it will be blocked according to this policy unless you also add https://youtube.com to the allowlist:

      frame-src 'self' https://www.youtube.com https://youtube.com;
      

      Here’s the updated CSP header. Change the frame-src directive as following:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self'; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
        );
        next();
      });
      . . .
      

      Allowing the Font Files

      Google fonts violations

      The Google fonts stylesheet contain references to several font files from https://fonts.gstatic.com. You will find that these files currently violate the defined font-src policy (currently 'self'), so you need to account for them in your revised policy:

      font-src 'self' https://fonts.gstatic.com;
      

      Update the font-src directive in the CSP header as following:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self'; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
        );
        next();
      });
      . . .
      

      Once you reload the page, the console will no longer report violations for the Google fonts files.

      Allowing the Vue.js Script

      A Vue.js script loaded over a CDN is rendering the Hello world! text at the top of the page. We’ll allow its execution on the page through the script-src directive. As mentioned earlier, it’s important to be specific when allowing CDN sources so we don’t open up our site to other possible malicious scripts that are hosted on that domain.

      script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js;
      

      In this example, you’re only allowing the exact script at that URL to execute on the page. If you want to switch between development and production builds, you’ll need to add the other script URL to the allowlist as well, or you can allow all the resources present in the /dist location, to cover both cases at once:

      script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/;
      

      Here’s the updated CSP header with the relevant changes:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
        );
        next();
      });
      . . .
      

      At this point, we’ve successfully allowed all the external files and scripts that our page relies on. But we still have one more CSP violation to resolve due to the presence of an inline script on the page. We’ll explore a few solutions to this problem in the next section.

      Step 4 — Handling Inline Sources

      Although you can approve inline code (such as JavaScript code in a <script> tag) within a CSP using the 'unsafe-inline' keyword, it is not recommended because it greatly increases the risk of a code-injection attack.

      This example policy allows the execution of any inline script on the page, but this is not safe for the aforementioned reasons.

      script-src 'self' 'unsafe-inline' https://unpkg.com/vue@3.0.2/dist/;
      

      The best way to avoid using unsafe-inline is to move the inline code to an external file and reference it that way. This is a better approach for caching, minification, and maintainability, and it also makes the CSP easier to modify in the future.

      However, if you absolutely must use inline code, there are two major ways to add them to your allowlist safely.

      Option 1 — Using a Hash

      This method requires that you calculate a SHA hash that is based on the script itself and then add it to the script-src directive. In recent versions of Chrome, you don’t even need to generate the hash yourself as it’s already included in the CSP violation error in the console:

      [Report Only] Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https://unpkg.com/vue@3.0.2/dist/". Either the 'unsafe-inline' keyword, a hash ('sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='), or a nonce ('nonce-...') is required to enable inline execution.
      

      The highlighted section here is the exact SHA256 hash that you would need to add to the script-src directive to allow the execution of the specific inline script that triggered the violation.

      Copy the hash and add it to your CSP as follows:

      script-src 'self' https://unpkg.com/vue@3.0.2/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM=';
      

      The disadvantage to this approach is that if the contents of the script changes, the generated hash will be different, which will trigger a violation.

      Option 2 — Using a Nonce

      The second way to allow the execution of inline code is by using a nonce. These are random strings that you can use to allow a complete block of code regardless of its content.

      Here’s an example of a nonce value in use:

      script-src 'self' https://unpkg.com/vue@3.0.2/dist/ 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
      

      The value of the nonce in the CSP must match the nonce attribute on the script:

      <script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
        // Some inline code
      </script>
      

      Nonces must be unguessable and dynamically generated each time the page is loaded so that an attacker is unable to use them for the execution of a malicious script. If you decide to implement this option, you can use the crypto package to generate a nonce as following:

      const crypto = require('crypto');
      let nonce = crypto.randomBytes(16).toString('base64');
      

      We will opt for the hash method in this tutorial since it’s more practical for our use case.

      Update the script-src directive in your CSP header to include the SHA256 hash of the sole inline script as shown following:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://unpkg.com/vue@3.0.2/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com;"
        );
        next();
      });
      . . .
      

      This removes the final CSP violation error that the inline script triggers from the console.

      In the next section, we will monitor the effects of our CSP in a production environment.

      Step 5 — Monitoring Violations

      Once you have your CSP in place, it’s necessary to keep an eye on its effect once in use. For example, if you forget to allow a legitimate source in production or when an attacker is trying to exploit an XSS attack vector (which you need to identify and stop immediately).

      Without some form of active reporting in place, there’s no way to know of these events. This is why the report-to directive exists. It specifies a location that the browser should POST a JSON-formatted violation report to, in the event it has to take action based on the CSP.

      To use this directive, you need to add an additional header to specify an endpoint for the Reporting API:

      Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"http://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}
      

      Once that is set, specify the group name in the report-to directive as following:

      report-to csp-endpoint;
      

      Here’s the updated portion of the server.js file with the changes. Be sure to replace the <your_server_ip> placeholder in the Report-To header with your actual server IP address:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Report-To',
          '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://<your_server_ip>:5500/__cspreport__"}],"include_subdomains":true}'
        );
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint;"
        );
        next();
      });
      . . .
      

      The report-to directive is intended to replace the now deprecated report-uri directive, but most browsers don’t support it yet (as of November 2020). So, for compatibility with current browsers while also ensuring compatibility with future browser releases support, you should specify both report-uri and report-to in your CSP. If the latter is supported, it will ignore the former:

      server.js

      . . .
      app.use(function (req, res, next) {
        res.setHeader(
          'Report-To',
          '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}'
        );
        res.setHeader(
          'Content-Security-Policy-Report-Only',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint; report-uri /__cspreport__;"
        );
        next();
      });
      . . .
      

      The /__cspreport__ route needs to exist on the server as well; add this to your file like the following:

      server.js

      . . .
      app.get('/', (req, res) => {
        res.sendFile(path.join(__dirname + '/index.html'));
      });
      
      app.post('/__cspreport__', (req, res) => {
        console.log(req.body);
      });
      . . .
      

      Some browsers send the Content-Type of the report payload as application/csp-report, while others use application/json. If the report-to directive is supported, the Content-Type should be application/reports+json.

      To account for all the possible Content-Type values, you have to set up some configurations on your express server:

      server.js

      . . .
      app.use(
        bodyParser.json({
          type: ['application/json', 'application/csp-report', 'application/reports+json'],
        })
      );
      . . .
      

      At this point, any CSP violations will be sent to the /__cspreport__ route and subsequently logged to the terminal.

      You can try it out by adding a resource from a source that is not compliant with the current CSP, or modifying the inline script in the index.html file as shown following:

      index.html

      . . .
      <script>
        new Vue({
          el: '#vue',
          render(createElement) {
            return createElement('h1', 'Hello World!');
          },
        });
        console.log("Hello")
      </script>
      . . .
      

      This will trigger a violation because the hash of the script is now different from what you included in the CSP header.

      Here’s a typical violation report from a browser using the report-uri:

      {
        'csp-report': {
          'document-uri': 'http://localhost:5500/',
          referrer: '',
          'violated-directive': 'script-src-elem',
          'effective-directive': 'script-src-elem',
          'original-policy': "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-uri /__cspreport__;",
          disposition: 'report',
          'blocked-uri': 'inline',
          'line-number': 58,
          'source-file': 'http://localhost:5500/',
          'status-code': 200,
          'script-sample': ''
        }
      }
      

      The parts to this report are:

      • document-uri: The page the violation occurred on.
      • referrer: The page’s referrer.
      • blocked-uri: The resource that violated the page’s policy (an inline script in this case).
      • line-number: The line number where the inline code begins.
      • violated-directive: The specific directive that was violated. (script-src-elem in this case, which falls back to script-src.)
      • original-policy: The complete policy of the page.

      If the browser supports the report-to directive, the payload should have a similar structure to what is following. Notice how it’s different from the report-uri payload while still carrying the same information:

      [{
          "age": 16796,
          "body": {
              "blocked-uri": "https://vimeo.com",
              "disposition": "enforce",
              "document-uri": "https://localhost:5500/",
              "effective-directive": "frame-src",
              "line-number": 58,
          'original-policy': "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-uri /__cspreport__;",
              "referrer": "",
              "script-sample": "",
              "sourceFile": "https://localhost:5500/",
              "violated-directive": "frame-src"
          },
          "type": "csp",
          "url": "https://localhost:5500/",
          "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
      }]
      

      Note: The report-to directive is supported only in secure contexts, which means that you need to set up your Express server with a valid HTTPS certificate, otherwise you won’t be able to test or use it.

      In this section, we successfully set up CSP monitoring on our server so that we can detect and fix problems quickly. Let’s go ahead and finish this tutorial by enforcing the final policy in the next step.

      Step 6 — Publishing the Final Policy

      Once you’re confident your CSP is set up correctly (ideally after leaving it in production for a few days or weeks in report-only mode), you can enforce it by changing the CSP header from Content-Security-Policy-Report-Only to Content-Security-Policy.

      In addition to reporting the violations, this will stop unauthorized resources from being executed on the page, leading to a safer experience for your visitors.

      Here is the final version of the server.js file:

      server.js

      const express = require('express');
      const bodyParser = require('body-parser');
      const path = require('path');
      const app = express();
      
      app.use(function (req, res, next) {
        res.setHeader(
          'Report-To',
          '{"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"http://your_server_ip:5500/__cspreport__"}],"include_subdomains":true}'
        );
        res.setHeader(
          'Content-Security-Policy',
          "default-src 'self'; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://images.unsplash.com; script-src 'self' https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/ 'sha256-INJfZVfoUd61ITRFLf63g+S/NJAfswGDl15oK0iXgYM='; style-src 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css; frame-src 'self' https://www.youtube.com https://youtube.com; report-to csp-endpoint; report-uri /__cspreport__;"
        );
        next();
      });
      
      app.use(
        bodyParser.json({
          type: [
            'application/json',
            'application/csp-report',
            'application/reports+json',
          ],
        })
      );
      app.use(express.static(path.join(__dirname)));
      
      app.get('/', (req, res) => {
        res.sendFile(path.join(__dirname + '/index.html'));
      });
      
      app.post('/__cspreport__', (req, res) => {
        console.log(req.body);
      });
      
      const server = app.listen(process.env.PORT || 5500, () => {
        const { port } = server.address();
        console.log(`Server running on PORT ${port}`);
      });
      

      Browser support
      The CSP header is supported in all browsers with the exception of Internet Explorer, which uses the non-standard X-Content-Security-Policy header instead. If you need to support IE, you have to issue the CSP twice in the response headers.

      The latest version of the CSP spec (level 3) also introduced some newer directives that are not well supported at the moment. Examples include the script-src-elem and prefetch-src directives. Make sure to use the appropriate fallbacks when setting up those directives to ensure the protections remain active in browsers that have not caught up yet.

      Conclusion

      In this article, you’ve set up an effective Content Security Policy for a Node.js application and monitored the violations. If you have an older or more complex website, it will require a wider policy setup that covers all the bases. However, setting up a thorough policy is worth the effort as it makes it a lot harder for an attacker to exploit your website to steal user data.

      You can find the final code from this tutorial in this GitHub repository.

      For more security-related articles, check out our Security topic page. If you would like to learn more about working with Node.js, you can read our How To Code in Node.js series.



      Source link

      7 Ways to Implement Conditional Rendering in React Applications


      Introduction

      With React, we can build Single Page Applications that are dynamic and highly interactive. One way we fully utilize such interactivity is through conditional rendering.

      Conditional rendering as a term describes the ability to render different UI markup based on certain conditions. In React-speak, it is a way to render different elements or components based on a condition. This concept is applied often in the following scenarios:

      • Rendering external data from an API
      • Showing/hiding elements
      • Toggling application functionality
      • Implementing permission levels
      • Authentication and Authorization

      In this article, we examine seven(7) ways to implement such conditional rendering in React applications.

      The Challenge

      As a challenge, based on the value of isLoggedIn in our component state, we want to be able to display a Login button if the user isn’t logged in, and a Logout button if he/she is.

      This is what our starter component looks like:

      Visually:

      Code:

      import React, { Component } from "react";
      import ReactDOM from "react-dom";
      import "./styles.css";
      
      
      class App extends Component {
        constructor(props) {
          super(props);
          this.state = {
            isLoggedIn: true
          };
        }
        render() {
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              <button>Login</button>
              <button>Logout</button>
            </div>
          );
        }
      }
      
      
      const rootElement = document.getElementById("root");
      ReactDOM.render(<App />, rootElement);
      

      Bear in mind that within the code snippets implies that some code which isn’t directly connected with the point being explained goes there.

      1. Using an If…else Statement

      An if…else statement allows us to specify that a particular action be carried out if a condition evaluates to true as well as do something else if it doesn’t. Using the sample project, we will examine two ways if…else conditions may be used to implement conditional rendering in React.

      In JSX, we are able to mix up JavaScript code with our markup to ensure stunning interactivity within our application. To do this we use a set of curly braces {} and write our JavaScript within. The caveat however is that there is a limit to what can be done within such braces. As a result the code snippet below would fail to achieve the desired result.

      // index.js
      ...
      render() {
          let {isLoggedIn} = this.state;
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {
                if(isLoggedIn){
                  return <button>Logout</button>
                } else{
                  return <button>Login</button>
                }
              }
            </div>
          );
      }
      ...
      

      To understand more about this behavior, visit this link.

      To solve this, we extract the conditional logic into a function as shown below:

      // index.js
      ...
      render() {
          let {isLoggedIn} = this.state;
          const renderAuthButton = ()=>{
            if(isLoggedIn){
              return <button>Logout</button>
            } else{
              return <button>Login</button>
            }
          }
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {renderAuthButton()}
            </div>
          );
        }
      ...
      

      Notice that we extract the logic from JSX into a function renderAuthButton. Thus, we only need to execute the function within the JSX curly braces.

      Multiple return statements

      In using this method, the component must be kept as simple as possible to avoid a wasted re-render of sibling or parent components. As a result of this, we create a new functional component called AuthButton.

      // AuthButton.js
      
      import React from "react";
      
      const AuthButton = props => {
        let { isLoggedIn } = props;
        if (isLoggedIn) {
          return <button>Logout</button>;
        } else {
          return <button>Login</button>;
        }
      };
      export default AuthButton;
      

      AuthButton returns various elements/components depending on the value of state that is passed down via the isLoggedIn props. Thus we import it in our index.js and pass down the appropriate state as shown below:

      // index.js
      ...
      import AuthButton from "./AuthButton";
      
      ...
        render() {
          let { isLoggedIn } = this.state;
          return (
            <div className="App">
            ...
              <AuthButton isLoggedIn={isLoggedIn} />
            </div>
          );
        }
      ...
      

      You must avoid doing this:

      // index.js
      ...
      render() {
          let { isLoggedIn } = this.state;
          if (isLoggedIn) {
            return (
              <div className="App">
                <h1>
                  This is a Demo showing several ways to implement Conditional
                  Rendering in React.
                </h1>
                <button>Logout</button>;
              </div>
            );
          } else {
            return (
              <div className="App">
                <h1>
                  This is a Demo showing several ways to implement Conditional
                  Rendering in React.
                </h1>
                <button>Login</button>
              </div>
            );
          }
        }
      }
      ...
      

      The snippet above would achieve the same result but bloat the component unnecessarily while introducing performance issues as a result of constantly re-rendering an unchanging component.

      2. Using Element Variables

      Element variables are an extension of **Extracting the conditional rendering into a function** as shown above. Element variables are simply variables that hold JSX elements. Thus we can conditionally assign elements/ components to these variables outside our JSX and only render the variable within JSX. See demo below:

      // index.js
      ...
      render() {
          let { isLoggedIn } = this.state;
          let AuthButton;
          if (isLoggedIn) {
            AuthButton = <button>Logout</button>;
          } else {
            AuthButton = <button>Login</button>;
          }
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {AuthButton}
            </div>
          );
        }
      ...
      

      Notice how we conditionally assign values(components) to AuthButton and then we only have to render it neatly within our JSX.

      3. Using a Switch Statement

      As shown previously, we can conditionally return different markup from a component based on set conditions using an if…else statement. The same could be achieved with a switch statement where we can specify the markup for various conditions. See example below:

      // AuthButton.js
      import React from "react";
      
      const AuthButton = props => {
        let { isLoggedIn } = props;
        switch (isLoggedIn) {
          case true:
            return <button>Logout</button>;
            break;
          case false:
            return <button>Login</button>;
            break;
          default:
            return null;
        }
      };
      export default AuthButton;
      

      Notice how we return various buttons based on the value of isLoggedIn. It is more reasonable to apply this method when there’s more than two possible values or outcomes. You may also do away with the break statement as the return statement automatically terminates the execution.

      Note: Returning **null** from a component will cause it to hide itself/display nothing. This a good way to toggle visibility of components.

      4. Ternary Operators

      The conditional (ternary) operator is the only JavaScript operator that takes three operands. This operator is frequently used as a shortcut for the if statement.

      If you are familiar with ternary operators, then you are aware that is is simply a more concise way to write an if statement. Thus we have:

      // index.js
      ...
      render() {
          let { isLoggedIn } = this.state;
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {isLoggedIn ? <button>Logout</button> : <button>Login</button>}
            </div>
          );
        }
      ...
      

      In cases where, this approach makes the component bloated, bulky or less readable, you may encapsualte the conditional within a functional component as shown below:

      // AuthButton.js
      import React from "react";
      
      const AuthButton = props => {
        let { isLoggedIn } = props;
        return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
      };
      
      export default AuthButton;
      

      5. Logical && (Short Circuit Evaluation with &&)

      Short circuit evaluation is a technique used to ensure that there are no side effects during the evaluation of eperands in an expression. The logical && helps us specify that an action should be taken only on one condition, otherwise, it would be ignored entirely. This is useful for situations where you only need to take an action when a certain condition is true, otherwise do nothing.

      For instance if we only needed to show the Logout button if the person is logged in, otherwise we do nothing. We’d have something like this:

      // index.js
      ...
      render() {
          let { isLoggedIn } = this.state;
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {isLoggedIn && <button>Logout</button>}
            </div>
          );
        }
      ...
      

      This would display the logout button if isLoggedIn is true otherwise it’d display nothing. We could adapt this to fit our use case as shown below. However, it is not advisable.

      // index.js
      ...
      return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {isLoggedIn && <button>Logout</button>}
              {!isLoggedIn && <button>Login</button>}
            </div>
          );
        }
      ...
      

      This would render the right button based on the value of isLoggedIn. However, this isn’t recommended as there are better, cleaner ways to achieve the same effect. Also this could easily make your code look messy and unintuitive once the component gets slightly larger.

      Earlier we covered that JSX limitations make it unable to execute every type of JavaScript code. This isn’t entirely true as there are ways to bypass such behavior. One such way is by using IIFEs.

      An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined. It’s used in the format below.

      (function () {
          statements
      })();
      

      You may learn more about IIFE’s from MDN here.

      With this technique, we are able to to write conditional logic directly within JSX but wrapped within an anonymous function that is immediately invoked on evaluation of that portion of our code. See example below:

      //index.js
      ...
      render() {
          let { isLoggedIn } = this.state;
          return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {(function() {
                if (isLoggedIn) {
                  return <button>Logout</button>;
                } else {
                  return <button>Login</button>;
                }
              })()}
            </div>
          );
        }
      ...
      

      This can also be written in a slightly more concise manner using an arrow function as shown below:

      // index.js
      ...
      return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              {(()=> {
                if (isLoggedIn) {
                  return <button>Logout</button>;
                } else {
                  return <button>Login</button>;
                }
              })()}
            </div>
          );
        }
      ...
      

      7. Using Enhanced JSX

      Certain libaries expose functionality to extend JSX, thus making it possible to implement conditional rendering directly with JSX. One of such libraries is JSX Control Statements. It is a Babel plugin that transforms component-like control statements into their JavaScript counterparts during transpilation. See example below for how this may be implemented.

      // index.js
      ...
      return (
            <div className="App">
              <h1>
                This is a Demo showing several ways to implement Conditional Rendering
                in React.
              </h1>
              <Choose>
                <When condition={isLoggedIn}>
                   <button>Logout</button>;
                </When>
                <When condition={!isLoggedIn}>
                   <button>Login</button>;
                </When>
              </Choose>
            </div>
          );
        }
      ...
      

      This approach is however not recommended as the code you write is eventually transpiled to a regular JavaScript conditional. It is probably always better to just write JavaScript than add an extra dependency over something so trivial.

      Performance Concerns

      As a general rule, it is best to ensure that in implemementing conditional rendering you:

      • Do not change the position of components arbitrarily in order to prevent components from unmounting and remounting unnecessarily.
      • Change only the markup that is concerned with the conditional rendering and leave out every other unchanging bit of the component.
      • Do not bloat your component unnecessarily within the render method, thus causing components to delay in rendering.

      For more on writing high performing conditionals in React, see this article by Cole Williams.

      Conclusion

      We have successfully examined 7 ways to implement conditional rendering in React. Each method has it’s own advantage and the choice of which to use is mostly dependent on the use case. Things to consider include:

      • The size of markup to be rendered conditionally
      • The number of possible outcomes
      • Which would be more intuitive and readable

      Generally, keep in mind the following recommendations:

      • When there is only one expected outcome, the Logical && Operator comes in very handy.
      • For boolean situations or use cases with only 2 possible outcomes, you may use If…else, Element variables, Ternary Operators and IIFEs.
      • For cases of more than 2 outcomes, you may use a Switch statement, an extracted function or extracted functional component.

      This is however merely a recommendation and the choice of which to go with is primarily yours.

      Further Reading

      You may learn more via the following resources:



      Source link