WHITE HACKERACADEMY

start-03 隔離した実習環境を準備する

コードを直す前に、何を確かめるか

下の説明と処理図を読み、入力した値がどの判断を通って結果になるかを確認します。実行後は「入力」「途中の値」「期待結果と実際の結果」を比較します。最初から正しく動く必要はありません。

演習 start-03 ローカル実習の宛先を検査する

教材を起動する前の確認係として、設定された宛先が指定のループバックとか検査します。localhostという単語を含む外部を見逃さないようにします。

範囲: 文字列の解析だけを実行します。通信・解決・待受の開始終了はせず、許可は実務の診断権限の代わりにはなりません。

処理図と読み方

処理の流れ
  1. 起動設定
  2. URLの構造
  3. 許可範囲
  4. 起動前の判断

起動設定 → URLの構造 / URLの構造 → 許可範囲 / 許可範囲 → 起動前の判断

独自の説明図。文字列の解析だけを実行します。通信・解決・待受の開始終了はせず、許可は実務の診断権限の代わりにはなりません。

  1. 起動設定:と、この実習で指定したを読みます。

  2. の構造:protocol・hostname・portを で分離します。

  3. 許可範囲:、127.0.0.1またはlocalhost、指定、ユーザー情報なしを検査します。

  4. 起動前の判断:設定の一致だけを返し、実サーバーが起動済みとは扱いません。

input → policy:と指定。

policy → process:分離したscheme・hostname・port。

process → result:許可範囲との一致結果。

観測順序:

  1. input:と、この実習で指定したを読みます。

  2. policy:protocol・hostname・portを で分離します。

  3. process:、127.0.0.1またはlocalhost、指定、ユーザー情報なしを検査します。

  4. result:設定の一致だけを返し、実サーバーが起動済みとは扱いません。

誤解しやすい点: にlocalhostという文字があればローカル、ではありません。解析したとを確認し、実際の待受確認とは区別します。

このコードで確かめること

実習用のWebページの住所を確認します。自分のコンピューターを指す localhost または 127.0.0.1 と、指定のだけを許可してください。localhost という文字が途中にある別の住所を許可しないことが確認点です。

プログラムが満たす条件

の部分一致をやめ、127.0.0.1またはlocalhostと完全一致させます。と条件も満たす場合だけを返します。

初めてコードを編集する方へ:入力・記号・実行の読み方
  1. 入力は教材がケースごとに自動で渡します。例えば input.name は入力の name という項目を読む記述です。下の編集欄に実名や本物のパスワードを入力する必要はありません。
  2. JSONの {} は項目の組、[] は順番のある一覧です。例えば {"name":"A"} は name が文字列 A の入力です。true は「はい」、false は「いいえ」、null は値がないことを表します。false が必ず失敗という意味ではありません。
  3. const は値に名前を付ける記述、=== は同じかの比較、&& は両方、|| はどちらか、! は反対です。return が最後の結果を返し、trace は途中の値を記録します。
  4. まず変更せず「コードを実行し、結果を比較する」を押します。「見直す」のケースを1つ選び、違う項目を確認します。編集欄の「修正対象」の近くを一か所変えて、同じボタンでもう一度実行します。
  5. ヒントと参考実装は編集欄の下で開けます。答えを写す前に、どの入力で結果が変わるはずか予想してください。一致したら、修正した条件がなぜ必要かを自分の言葉で説明します。

「修正対象」と書かれた部分を探します。まず変更せず実行し、期待結果と違う箇所を確かめてから、条件や計算を変更してください。

このコードは外部のWebサイトやファイルには接続しません。図の各段階で trace に渡された値を表示します。文字列や計算などのコードは実行しますが、実際の攻撃・送信・削除は行いません。

この説明文は振り返り用に保存します。文章の内容そのものを自動で正誤判定することはありません。

条件を1つ変えて試す

下の入力は最初のケースのコピーです。課題で扱う範囲の値を1つだけ変え、結果を予想してから実行してください。いつもの全ケースに、この入力を1件追加して比較します。入力の意味は上の課題と処理図で確認できます。

修正する課題

修正する課題

の部分一致をやめ、127.0.0.1またはlocalhostと完全一致させます。と条件も満たす場合だけを返します。

初期コード(修正対象)

初期コード(修正対象)

async function run(input, trace) {
  trace("input", input);
let url;
  try { url = new URL(input.url); } catch { url = null; }
  trace("policy", {hostname:url?.hostname ?? null, expectedPort:input.port});
  const hostAllowed = url && /* 修正対象:ホスト名の部分一致をやめ、127.0.0.1またはlocalhostと完全一致させます。ポートとHTTP条件も満たす場合だけtrueを返します。 */
  url.hostname.includes("localhost") || url?.hostname === "127.0.0.1";
  const allowed = Boolean(hostAllowed && url.protocol === "http:" &&
    (url.port || "80") === String(input.port) && !url.username && !url.password);
  trace("process", {hostAllowed:Boolean(hostAllowed), allowed});
  const output = {allowed, serverStarted:false};
  trace("result", output);
  return output;
}
ケースごとの入力・期待結果・理由

ケースごとの入力・期待結果・理由

ケース1:正常:指定した教材

入力:

{"url":"http://127.0.0.1:8765","port":8765}

期待結果:

{"allowed":true,"serverStarted":false}

理由:設定だけを許可する。起動は別の操作。

ケース2:異常:紛らわしい外部

入力:

{"url":"http://localhost.attacker.test:8765","port":8765}

期待結果:

{"allowed":false,"serverStarted":false}

理由:localhostという部分文字列では同じにならない。

ケース3:境界:別

入力:

{"url":"http://localhost:8766","port":8765}

期待結果:

{"allowed":false,"serverStarted":false}

理由:指定した待受との一致も必要。

ケース4:異常:解析できない値

入力:

{"url":"not a URL","port":8765}

期待結果:

{"allowed":false,"serverStarted":false}

理由:不正を外部へ解決しない。

段階的なヒント

段階的なヒント

  1. 文字列全体より、解析後のhostnameを確認します。

  2. includesとのincludesは異なる比較です。

  3. 通信を開始していないのでserverStartedはのままです。

参考実装

参考実装

async function run(input, trace) {
  trace("input", input);
let url;
  try { url = new URL(input.url); } catch { url = null; }
  trace("policy", {hostname:url?.hostname ?? null, expectedPort:input.port});
  const hostAllowed = url && ["127.0.0.1","localhost"].includes(url.hostname);
  const allowed = Boolean(hostAllowed && url.protocol === "http:" &&
    (url.port || "80") === String(input.port) && !url.username && !url.password);
  trace("process", {hostAllowed:Boolean(hostAllowed), allowed});
  const output = {allowed, serverStarted:false};
  trace("result", output);
  return output;
}

別の状況へ適用する

社内診断:書面の対象と期間も照合する。

検証:解決先や第三者サービスへの転送を追加確認する。

開発環境:を変えると保存先や接続先が変わりうる。

検証:起動と実際の待受を照合する。

到達確認

  • 不審と別を拒否する。

  • 文字列の判定と実待受の確認を分離する。

  • の一致を外部診断の許可と呼ばない。