概要: このチュートリアルでは、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-validator
Code language: JavaScript (javascript)
3番目に、次のエンドポイントへのリクエストを作成します
http://localhost:3000/hi?name=John
Code language: JavaScript (javascript)
Webブラウザに次のメッセージが表示されます
Hi, John!
Code language: JavaScript (javascript)
ただし、name
クエリ文字列を渡さずに次のエンドポイントをリクエストすると
http://localhost:3000/hi
Code language: JavaScript (javascript)
画面に次のメッセージが表示されます
Hi, undefined
Code language: JavaScript (javascript)
その理由は、この例ではreq.query.name
がundefined
であるためです。
最悪の場合、クエリ文字列に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()
関数を使用します。