DEV Community

Justin Martin for Kezios

Posted on • Edited on • Originally published at kezios.fr

React.js - Indicateur de "force" d'un mot de passe

Pour sécuriser les mots de passe, on demande souvent à l’utilisateur d’utiliser un mot de passe “complexe” en ajoutant par exemple une majuscule, un caractère spécial ou un chiffre. Cependant, ces méthodes ne permettent pas de créer un mot de passe aussi sécurisé qu’on le pense.

Par exemple, le mot de passe: [Password1234] réponds à toutes ces règles, cependant il est l’un des plus testés lors des attaques.

Comment faire alors ?

L’une des solutions pour créer un processus de validation de mot de passe fiable est d’utiliser une librairie comme zxcvbn-ts (https://zxcvbn-ts.github.io/zxcvbn/). Cette librairie permet d’estimer la complexité d’un mot de passe et ainsi d’empêcher l’utilisateur d’utiliser un mot de passe jugé trop faible.

Implémentation en React.js

L’idée est de calculer le score du mot de passe indiqué par l’utilisateur et en fonction de ce score affiché les indicateurs qui correspondent :

Indicateur de mot de passe

App.tsx :

import React, { useEffect, useState } from "react";
import { zxcvbn } from "@zxcvbn-ts/core";

import { Indicators } from "./components/Indicators";

import "./App.css";

interface Indicator {
  score: number;
}

const App = () => {
  const [password, setPassword] = useState("");
  const [indicator, setIndicator] = useState<Indicator>({ score: -1 });

  useEffect(() => {
    if (password === "") return;

    setIndicator(zxcvbn(password));
  }, [password]);

  const { score } = indicator;

  return (
    <div className="d-block mx-4">
      <div className="position-relative mt-3">
        <label htmlFor="password-input" className="mr-2">
          Mot de passe
        </label>
        <input
          is="password-input"
          type="password"
          onChange={(event) => setPassword(event.target.value)}
          value={password}
          placeholder={"**********"}
        />
        {password !== "" && <Indicators score={score} />}
      </div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Indicators.tsx

import React from "react";

const colors = {
  0: "#e5e5e5",
  1: "#9B2C2C",
  2: "#D44949",
  3: "#DCA02D",
  4: "#387F95",
  5: "#48AE65"
};

const getColor = (power, index) => {
  if (power > index) {
    return colors[power];
  }
  return colors[0];
};

const indicatorIndexes = [0, 1, 2, 3, 4];

const Indicators = ({ score }: { score: number }) => (
  <div className="mt-2 indicator-container">
    {indicatorIndexes.map((indicatorIndex, index) => (
      <div
        className="indicator"
        key={indicatorIndex}
        style={{ backgroundColor: getColor(score + 1, indicatorIndex) }}
      />
    ))}
  </div>
);

export { Indicators };
Enter fullscreen mode Exit fullscreen mode

App.css

.indicator {
  height: 4px;
  border-radius: 4px;
  width: 15%;
  margin-right: 8px;
}

.indicator-container {
  flex-direction: row;
  display: flex;
}
Enter fullscreen mode Exit fullscreen mode

Pour allez plus loin

A présent, on va ajouter des options dans notre validation. Avec pour objectif pour rendre notre validation de mot de passes plus sécurisé. On va aussi ajouter des suggestions pour indiquer à l’utilisateur comment rendre son mot de passe plus fort.

Indicateur de mot de passe avec suggestions

App.tsx :

import React, { useEffect, useState } from "react";
import { zxcvbn, ZxcvbnOptions } from "@zxcvbn-ts/core";
import zxcvbnCommonPackage from "@zxcvbn-ts/language-common";
import zxcvbnFrPackage from "@zxcvbn-ts/language-fr";
import { FeedbackType } from "@zxcvbn-ts/core/dist/types";

import { Indicators } from "./components/Indicators";
import { Suggestions } from "./components/Suggestions";

import "./App.css";

const options = {
  translations: zxcvbnFrPackage.translations,
  graphs: zxcvbnCommonPackage.adjacencyGraphs,
  dictionary: {
    ...zxcvbnCommonPackage.dictionary,
    ...zxcvbnFrPackage.dictionary
  }
};

ZxcvbnOptions.setOptions(options);

interface Indicator {
  score: number;
  feedback: FeedbackType;
}

const App = () => {
  const [password, setPassword] = useState("");
  const [indicator, setIndicator] = useState<Indicator | null>();

  useEffect(() => {
    if (password === "") return;

    setIndicator(zxcvbn(password));
  }, [password]);

  const score = indicator ? indicator.score : -1;
  const feedback = indicator ? indicator.feedback : undefined;

  return (
    <div className="d-block mx-4">
      <div className="position-relative mt-3">
        <label htmlFor="password-input" className="mr-2">
          Mot de passe
        </label>
        <input
          is="password-input"
          type="password"
          onChange={(event) => setPassword(event.target.value)}
          value={password}
          placeholder={"**********"}
        />
        {password !== "" && <Indicators score={score} />}
        {feedback && feedback.warning.length > 0 && (
          <Suggestions suggestions={feedback.suggestions} />
        )}
      </div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Suggestions.tsx

import React from "react";

const Suggestions = ({ suggestions }: { suggestions: string[] }) => (
  <ul>
    {suggestions.map((suggestion, index) => (
      <li key={suggestion}>{suggestion}</li>
    ))}
  </ul>
);

export { Suggestions };
Enter fullscreen mode Exit fullscreen mode

Lien codesandbox:

https://codesandbox.io/s/password-zxcvbn-react-ts-3lt0q

Top comments (0)