Expressのバリデーション

概要: このチュートリアルでは、express-validatorライブラリを使用して入力データを検証およびサニタイズする方法を学びます。

Expressアプリケーションがユーザー入力などの外部ソースからデータを受信する場合、入力データを検証およびサニタイズすることが重要です。

  • データ検証は、入力データが型、範囲、形式などの特定の基準を満たしていることを保証します。入力データが有効であることを確認します。たとえば、メールアドレスが有効な形式であるかどうかを確認できます。
  • データサニタイズは、有害な文字を削除またはエスケープすることにより、入力データをクリーンアップします。コードインジェクションなどの悪意のある入力を防ぐのに役立ちます。たとえば、Webページにレンダリングする前に入力データからHTMLタグまたはスクリプトタグを削除できます。

Expressアプリケーションでは、入力データを手動で検証およびサニタイズできますが、このプロセスには時間がかかり、より多くの労力が必要です。

より効率的にするために、サードパーティの検証ライブラリを利用できます。このチュートリアルでは、express-validatorライブラリを使用して入力データを検証およびサニタイズする方法を学びます。

クエリ文字列の検証

まず、簡単なExpressアプリケーションを作成します

import express from 'express';

const PORT = process.env.PORT || 3000;
const app = express();

app.get('/hi', (req, res) => res.send(`Hi, ${req.params.name}!`));

app.listen(PORT, () => console.log(`The server is listening on port ${PORT}`));Code language: JavaScript (javascript)

このアプリには、クエリ文字列nameを受け入れるルート/hiが含まれています。Webブラウザに挨拶メッセージが表示されます。

次に、ターミナルで次のnpmコマンドを実行して、プロジェクトにexpress-validatorライブラリをインストールします

npm install express-validatorCode language: JavaScript (javascript)

3番目に、次のエンドポイントへのリクエストを作成します

http://localhost:3000/hi?name=JohnCode language: JavaScript (javascript)

Webブラウザに次のメッセージが表示されます

Hi, John!Code language: JavaScript (javascript)

ただし、nameクエリ文字列を渡さずに次のエンドポイントをリクエストすると

http://localhost:3000/hiCode language: JavaScript (javascript)

画面に次のメッセージが表示されます

Hi, undefinedCode language: JavaScript (javascript)

その理由は、この例ではreq.query.nameundefinedであるためです。

最悪の場合、クエリ文字列にJavaScriptコードが含まれていると、悪意のあるページにリダイレクトされる可能性があります。例:

http://localhost:3000/hi?name=<script>window.location ='https://www.google.com';</script>Code language: JavaScript (javascript)

この例では、google.comにリダイレクトするコードを注入します。実際のシナリオでは、悪意のあるページにリダイレクトされる可能性があります。これはクロスサイトスクリプティング(XSS)と呼ばれます。

クロスサイトスクリプティング(XSS)は、攻撃者が悪意のある実行可能スクリプトを信頼できるWebサイトのコードに注入する攻撃です。

nameクエリ文字列の値を検証およびサニタイズするには、express-validatorライブラリを使用できます。

技術的には、express-validatorライブラリは、入力データを検証およびサニタイズするミドルウェア関数のセットです。

4番目に、express-validatorライブラリの関数を使用してnameクエリ文字列を検証します

import express from 'express';
import { query, validationResult, matchedData } from 'express-validator';

const PORT = process.env.PORT || 3000;
const app = express();

app.get('/hi', query('name').notEmpty().escape(), (req, res) => {
  // validate data
  const result = validationResult(req);
  if (!result.isEmpty()) {
    res.status(400).send({ errors: result.array() });
  }

  // sanitize data
  const cleanedData = matchedData(req);
  res.send(`Hi, ${cleanedData.name}!`);
});

app.listen(PORT, () => console.log(`The server is listening on port ${PORT}`));Code language: JavaScript (javascript)

仕組み。

ステップ1。検証を処理するためにexpress-validatorライブラリから関数をインポートします

import { query, validationResult, matchedData } from 'express-validator';Code language: JavaScript (javascript)

インポートされた関数の概要は次のとおりです

  • query()関数は、クエリパラメータを検証するミドルウェアです。
  • validationResult()関数は、受信リクエストの検証とサニタイズの結果を収集します。
  • matchedData()関数は、検証およびサニタイズされたデータを抽出します。

ステップ2. nameクエリ文字列を検証します

query('name').notEmpty().escape()Code language: JavaScript (javascript)

この構文では

  • notEmpty()関数は、nameクエリ文字列の値が空でないことを保証します。
  • escape()関数は、XSS攻撃を防ぐためにフィールド値をエスケープします。

query()notEmpty()、およびescape()関数は、検証チェーンを形成します。ミドルウェア関数を返すため、app.get()メソッドで使用できます。

ステップ3. validationResult()関数を使用して検証結果を取得します

const result = validationResult(req);
if (!result.isEmpty()) {
   res.status(400).send({ errors: result.array() });
}Code language: JavaScript (javascript)

query()関数は、検証エラーを自動的に報告しません。代わりに、検証エラーを収集し、validationResult()関数を使用して検証します。validationResult()関数は、ValidationErrorオブジェクトを返します。

ValidationErrorオブジェクトのisEmpty()メソッドは、検証エラーが発生しなかった場合はtrueを返し、それ以外の場合はfalseを返します。コードでは、HTTPステータスコード400で検証エラーを含むJSON応答を返します。

ステップ4. サニタイズされたデータを取得します

サニタイズされたデータを取得するには、matchedData()関数を使用します

const cleanedData = matchedData(req);Code language: JavaScript (javascript)

ステップ5. サニタイズされたデータをレンダリングします

res.send(`Hi, ${cleanedData.name}!`);Code language: JavaScript (javascript)

ルートパラメータの検証

ルートパラメータを検証するには、express-validatorライブラリのparam()関数を使用できます。

param()関数を使用すると、ルーターパラメータの検証ルールを指定できます。

次の例は、param()関数を使用してidルートパラメータを検証する方法を示しています

app.get(
  '/api/todos/:id',
  param('id').isInt({ min: 1 }).withMessage('ID must be a positive integer'),
  (req, res) => {
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const id = req.params.id;
    res.send(`Fetching record with ID: ${id}`);
  }
);Code language: JavaScript (javascript)

仕組み。

param('id')は、検証のためのidルートパラメータを指定します

  • isInt({ min: 1 })は、idパラメータが整数で、少なくとも1であることを保証します。
  • withMessage('IDは正の整数でなければなりません')は、検証に失敗した場合にカスタムエラーメッセージを指定します。

残りのコードは、クエリ文字列の検証と同じように機能します。

リクエストボディの検証

ステップ1. リクエストをJSONオブジェクトとして処理するには、express.json()と呼ばれる組み込みミドルウェアを登録します

app.use(express.json());Code language: JavaScript (javascript)

これにより、Expressアプリケーションに、ボディをJSONオブジェクトとして解析するように指示し、req.bodyプロパティを使用してアクセスできるようになります。

JSONオブジェクトのフィールドにアクセスするには、express-validatorライブラリのbody()関数を使用できます。

ステップ2. express-validatorライブラリからbody関数をインポートします

import {body, validationResult, matchedData} from 'express-validator';Code language: JavaScript (javascript)

ステップ3. リクエストのボディにあるtitleフィールドとcompletedフィールドを検証します

app.post('/api/todos',
  [body('title').notEmpty().isString(), body('completed').isBoolean()],
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).send({ errors: errors.array() });
    }

    const record = matchedData(req);
    res.send(record);
  }
);Code language: JavaScript (javascript)

この例では、app.post()関数にミドルウェアの配列を渡します。最初のミドルウェアはtitleフィールドを検証し、2番目のミドルウェアはリクエストボディのcompletedフィールドを検証します。

たとえば、リクエストボディにtitleフィールドとcompletedフィールドを指定せずに/api/todosエンドポイントにPOSTリクエストを行うと、次のエラーが発生します

{
  "errors": [
    {
      "type": "field",
      "msg": "Invalid value",
      "path": "title",
      "location": "body"
    },
    {
      "type": "field",
      "msg": "Invalid value",
      "path": "title",
      "location": "body"
    },
    {
      "type": "field",
      "msg": "Invalid value",
      "path": "completed",
      "location": "body"
    }
  ]
}Code language: JavaScript (javascript)

概要

  • クエリ文字列を検証するには、query()関数を使用します。
  • ルートパラメータを検証するには、param()関数を使用します。
  • リクエストボディを検証するには、body()関数を使用します。
このチュートリアルは役に立ちましたか?