|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="ja"> |
| 3 | +<head> |
| 4 | +<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| 5 | +<meta charset="utf-8"> |
| 6 | +<meta name="viewport" content="width=device-width, initial-scale=1"> |
| 7 | +<link rel="stylesheet" href="https://best.openssf.org/assets/css/style.css"> |
| 8 | +<link rel="stylesheet" href="checker.css"> |
| 9 | +<script src="checker.js"></script> |
| 10 | +<script src="input2.js"></script> |
| 11 | +<link rel="license" href="https://creativecommons.org/licenses/by/4.0/"> |
| 12 | + |
| 13 | +</head> |
| 14 | +<body> |
| 15 | +<!-- For GitHub Pages formatting: --> |
| 16 | +<div class="container-lg px-3 my-5 markdown-body"> |
| 17 | +<h1>ラボ演習 input2</h1> |
| 18 | +<p> |
| 19 | +これはセキュアなソフトウェア開発に関するラボ演習です。 |
| 20 | +ラボの詳細については、<a href="introduction.html" target="_blank">概要</a>をご覧ください。 |
| 21 | + |
| 22 | +<p> |
| 23 | +<h2>タスク</h2> |
| 24 | +<p> |
| 25 | +<b> |
| 26 | +正規表現を使って、特定の形のテキスト入力の検証を練習しましょう。 |
| 27 | +</b> |
| 28 | + |
| 29 | +<p> |
| 30 | +<h2>背景</h2> |
| 31 | +<p> |
| 32 | +この演習では、Expressフレームワーク(バージョン4)とexpress-validatorライブラリを使用して、JavaScriptで書かれたサーバー側のプログラムに簡単な入力検証を追加します。 |
| 33 | +</p> |
| 34 | + |
| 35 | +<p> |
| 36 | +しかし、今回は正規表現を使って、特定のデータ値に対する入力検証を行います。 |
| 37 | +多くのプログラムには、特殊なデータの値があり、正規表現によって簡単にテストできるものがあります。 |
| 38 | + |
| 39 | +<p> |
| 40 | +以下のコードは、<tt>/parts</tt>というパスに対する<tt>get</tt>リクエストに対するハンドラをセットアップするものです。 |
| 41 | +このコードは、例えば<tt>http://localhost:3000/parts?id=AX-794-7</tt>に対するリクエストによって実行されます(<tt>localhost</tt>で実行し、3000番ポートで待ち受けている場合)。 |
| 42 | +もし検証でエラーがなければ、コードはパーツのIDを表示します。 |
| 43 | +検証でエラーがあった場合には、HTTPのエラーコード422(処理できないコンテンツ/"Unprocessable Content")をエラーメッセージとともに返します。 |
| 44 | +このステータスコードは、リクエストが何らかの理由で無効であることを意味します。 |
| 45 | + |
| 46 | +<p> |
| 47 | +この場合では、適切な入力検証を実装する必要があるでしょう。 |
| 48 | +そこで、入力が一定の長さを超えていないこと、ある特定のパターンにマッチしていることを確認する必要があります。 |
| 49 | +input1のラボで書いたように、このプログラムは、クロスサイト・スクリプティング(XSS)と呼ばれる、まだ説明してない脆弱性があります。 |
| 50 | +この脆弱性については、より良い入力検証を行うことで完全に防ぐことができるでしょう。 |
| 51 | + |
| 52 | +<p> |
| 53 | +<h2>タスクの詳細</h2> |
| 54 | +<p> |
| 55 | + |
| 56 | +<p> |
| 57 | +このアプリケーションでは、パーツIDのフォーマットは常に、2文字の大文字アルファベット(<tt>A</tt>から<tt>Z</tt>まで)、ハイフン(<tt>-</tt>)、1桁以上の数字、ハイフン(<tt>-</tt>)、1桁以上の数字、となっています。 |
| 58 | + |
| 59 | +<p> |
| 60 | +タスクを完了するには、以下を実行します。 |
| 61 | + |
| 62 | +<ol> |
| 63 | +<li><tt>app.get</tt>の<tt>'/parts'</tt>という最初のパラメータの後に、コンマで区切られた新しいパラメータを追加します |
| 64 | +<li>この新しいパラメータを<tt>query('id')</tt>で始め、検証のために<tt>id</tt>パラメータを選択するようにします。(このラボでは、この部分は書かれて<i>いません</i>) |
| 65 | +<li>ピリオド(<tt>.</tt>)を追加し、検証要件<tt>isLength()</tt>を追加します。 |
| 66 | +<li>この<tt>isLength</tt>メソッドは、カッコ内にオプショナルの引数として、最小値や最大値といった情報を与えるオブジェクトを取ることができます。 |
| 67 | +今回は、最大値のみ検証したいので、<tt>isLength({max: 最大値})</tt>というような形になるはずです。 |
| 68 | +JavaScriptをよく知っている方は、この長さ(Length)の値はUTF-16での文字単位で表されることもご存知でしょう。今回の目的には問題ありません。 |
| 69 | +</ol> |
| 70 | + |
| 71 | +<p> |
| 72 | +また、入力が正規表現を使ったパターンにマッチしていることも検証する必要があります。 |
| 73 | +この場合は、以下のように行います。 |
| 74 | +<ol> |
| 75 | +<li>さらにピリオド(<tt>.</tt>)と検証要件<tt>matches()</tt>を追加します。 |
| 76 | +<li>カッコの中にスラッシュ(<tt>/</tt>)、続けてマッチさせる正規表現のテキスト、最後にスラッシュ(<tt>/</tt>)を与えなければいけません。 |
| 77 | +JavaSriptでは、正規表現はスラッシュ(<tt>/</tt>)によって囲まれて表現されます。 |
| 78 | +<li>正規表現の<i>全体</i>がマッチするようにしてください(つまり、<tt>^</tt>と<tt>$</tt>を使いましょう)。 |
| 79 | +<li>また、大文字一文字にマッチさせるパターンは、<tt>[A-Z]</tt>であることを忘れずに。 |
| 80 | +</ol> |
| 81 | + |
| 82 | +<p> |
| 83 | +必要に応じて、「ヒント」ボタンと「諦める」ボタンを使用してください。 |
| 84 | + |
| 85 | +<p> |
| 86 | +<h2>演習 (<span id="grade"></span>)</h2> |
| 87 | +<p> |
| 88 | +<b>下記のコードを、クエリパラメータ<tt>id</tt>が80文字以下であり、パーツIDのフォーマット要件に合致している場合にのみ受け入れられるように変更してください。 |
| 89 | +フォーマットは、2文字の大文字アルファベット(<tt>A</tt>から<tt>Z</tt>まで)、ハイフン(<tt>-</tt>)、1桁以上の数字、ハイフン(<tt>-</tt>)、1桁以上の数字、です。 |
| 90 | +</b> |
| 91 | +<p> |
| 92 | + |
| 93 | +<!-- |
| 94 | +You can use this an example for new labs. |
| 95 | +For multi-line inputs, instead of <input id="attempt" type="text" ...>, use |
| 96 | +<textarea id="attempt" rows="2" cols="65">...</textarea> |
| 97 | +--> |
| 98 | +<form id="lab"> |
| 99 | +<pre><code |
| 100 | +>// Expressフレームワークとexpress-validatorライブラリのセットアップ |
| 101 | +const express = require("express"); |
| 102 | +const app = express(); |
| 103 | +const { query, matchedData, validationResult } = |
| 104 | + require('express-validator'); |
| 105 | + |
| 106 | +// リクエストの実装 (例:http://localhost:3000/parts?id=1) |
| 107 | +app.get('/parts', |
| 108 | +<textarea id="attempt0" rows="2" cols="64" spellcheck="false"> |
| 109 | + ,</textarea> |
| 110 | + (req, res) => { // /partsが現れたときに実行 |
| 111 | + const result = validationResult(req); // エラーを取得 |
| 112 | + if (result.isEmpty()) { // エラーがない場合 |
| 113 | + const data = matchedData(req); // マッチしたデータを取得 |
| 114 | + return res.send(`You requested part id ${data.id}!`); |
| 115 | + } |
| 116 | + res.status(422).send(`Invalid input`); |
| 117 | + }) |
| 118 | +</code></pre> |
| 119 | +<button type="button" class="hintButton">ヒント</button> |
| 120 | +<button type="button" class="resetButton">リセット</button> |
| 121 | +<button type="button" class="giveUpButton">諦める</button> |
| 122 | +<br><br> |
| 123 | +<p> |
| 124 | +<i>このラボは、<a href="https://www.linuxfoundation.org/">Linux Foundation</a>のDavid A. Wheelerによって開発されました。</i> |
| 125 | +<br><br> |
| 126 | +<p id="correctStamp" class="small"> |
| 127 | +<textarea id="debugData" class="displayNone" rows="20" cols="65" readonly> |
| 128 | +</textarea> |
| 129 | +</form> |
| 130 | + |
| 131 | +</div><!-- End GitHub pages formatting --> |
| 132 | +</body> |
| 133 | +</html> |
0 commit comments