セキュリティキャンプ2023応募課題清書
23時に提出
↓通過した。なのでこのページは、いわゆる「応募課題晒し」となる
2023年度
Webセキュリティクラス
残り時間10分での提出だった
おめでとうございますiNoma.iconiNoma.icon
ありがとうございます!t6o_o6t.icon
1
B4『Webサービスにおける安全な認証とID連携の実装』
過去に、Next.jsのmiddlewareでBASIC認証を実装しました。そのときは、Vercelの環境変数でパスワードを設定しました。BASIC認証は手軽に実装することができます。しかし、私はBASIC認証以外のユーザー認証を具体的にどう実装するのかを知りません。
OAuth2を利用するアプリケーションを実装したことがあります。Discordという通話やテキストチャットが出来るアプリケーションでは、ユーザーが独自の自動化を施すことができます。Discordユーザーの所有するリソースにアクセスする場合には、当該ユーザーがOAuth2のプロセスで権限を認可する必要があります。わたしは、Discordユーザーのユーザー名やアイコン、所属しているDiscordサーバーの情報をもとに、特定のDiscordサーバーに所属している場合にはログインさせ、していない場合はログインを拒否するWebサイトを実装しました。
参考:
実装にはNextAuth.jsというライブラリを使用しました。当時Next.jsを使用していたからです。
今回は残念ながら時間が足らず、書籍などで「OAuth2を」実装する練習はできませんでしたが、この機会に認証機能を実装して、OAuth2によるアプリケーションの認可を実装を学習する予定です。
予定ならスケジュールしないと
B3『クラウドネイティブセキュリティの実践と戦略』
後述するDiscordボットをデプロイする際にAWSやGCPには、クレジットカードの問題や従量課金制への不安があり、高校生のときには使えなかったため、DockerやKubernetesのエコシステムを有効利用できていませんでした。
今後のアプリケーション運用の選択肢として、Kubernetesの利用を経験しておきたいです。
B7『Policy as Code入門』
ポリシーをコードで表現するとはどういうことか?について気になったため、調べました。
ポリシーとは、セキュリティポリシーやプライバシーポリシーといった、組織が定めるルール、ガイドラインです。
ポリシーをコードで表現すると、プログラムがポリシーの持つセキュリティリスクを解析したり、組織のポリシー違反を自動的に検出したりできるのが特徴です。
Policy as Codeを支える技術の一つであるOpen Policy AgentのWebサイトを確認したところ、以前FirebaseのFirestoreを利用したときに記述したSecurity Rulesと似た概念であると感じました。
様々なものにコーディングの文化が持ち込まれる情勢に興味があるので、拝聴したいと思います。
これでよい。次!
2
(1)Webアプリケーションの開発経験
アルバイトやインターンでの実務経験がないことを、前もってお伝えさせていただきます。以下に挙げるのは、すべて趣味のプロジェクトです。
・Discordのボットメッセージを管理するWebアプリ
Discordでは、ユーザーがボットを開発して、プログラムにしたがってチャットにメッセージを投稿したり、他ユーザーのメッセージを取得したりできます。
ボットがREST APIを使って送信したメッセージを、人間が編集はすることはできません。REST APIを介して編集する必要があります。
このため、メッセージを編集するのが手間で、より簡単にメッセージを編集できるようにアプリを開発しました。
構成を説明します。
アプリケーションの構築にはNext.jsを使用し、Vercelでデプロイしています。
スタイルは既存のコンポーネントは使用せずほとんどスクラッチで書きました。
カラーピッカー、日付選択、セレクトボックスはUIライブラリを使用しました。
データベースにFirestoreを使用しました。
このWebアプリのユーザーが、私の指定したDiscordサーバーの管理者であることを確認するために、DiscordのOAuth2を利用しました。
NextAuth.jsというライブラリを利用して実装しました。
コードはPrettierで整形されます。
・コミュニティのメンバー情報を表示するWebサイト
当時計画していたゲームのコミュニティのメンバーを検索するためのWebサイトでした。
選定した技術を説明します。
アプリケーションはNext.jsで記述し、Vercelにデプロイします。
UIライブラリにはMUIを採用しました。ReactのUIライブラリでは人気が高いためです。MUIのスタイルを、事前に作成したデザインに合わせてカスタムする形でUIコンポーネントを実装していきました。
データベースにはPlanetScaleを、ORMにはPrismaを採用しました。
このプロジェクトは、もともとDiscordボットの機能として実装していたものをWebアプリとして利用できるようにしたものです。
元のプロジェクトでは、データベースにはFirestoreを利用していました。PlanetScaleは無料枠が広いため、試用する目的で選びました。
クライアントによるアクセスで無料枠を超えることがないよう、ページは静的生成しています。
コンポーネントのカタログをStorybookで実装しました。Adobe XDで作成したデザインとの整合性を保ち、UIの確認に集中する目的で実装しました。ほかのコミュニティメンバーと進捗を共有する目的でChromaticを用いてStorybookをデプロイしました。
コードのスタイルを保つため、Prettierで整形を行い、Hygenでコンポーネントファイルの自動生成を行いました。
(2)
頻繁に利用するプログラミング言語
・JavaScript / TypeScript
・C言語
・Python
利用したことのあるプログラミング言語
・C++
・Shell Script(bash)
学校で勉強したことのあるプログラミング言語
・C言語
・Java
・C# / Unity
個人的に学習したことのあるプログラミング言語
・Rust
それぞれの言語の詳細を説明します。
・JavaScript / TypeScript
WebアプリケーションでReactとともに使用することが多いですが、Node.js上で動作するスクリプトを書くときに使用するときがあります。
例えば、Discordのテキストチャットに送信されたメッセージの内容を音声合成し、ボイスチャットで再生するDiscordボットを開発していました。
日本では、安定運用されて複数のボイスチャットで使用できるボットに限りがあるため、自作するのが良いと考えました。
音声はOpenJTalkで合成しました。有志がOpenJTalkをWeb API呼び出しで利用できるDockerイメージを配布しており、Docker Composeで複数の音声合成クライアントを稼働する予定でした。
実際には、これを開発する動機になったゲームコミュニティが空中分解してしまい、完成しませんでした。
他には、ScrapboxというWikiのページのピン留めを管理するユーザー定義のスクリプトを開発しました。
Scrapboxでは、作成したページをピン留めすることができますが、ピン留めを入れ替える手段は提供されていないため、上手く順番を考えてピン留めを付け外しする必要がありました。
このスクリプトを使えば、十ページを超えるようなピン留めの入れ替えでも、最小の手順で入れ替えを実行できます。
この開発では、アルゴリズムの妥当性や、考えていることをコードに落とし込む際の正確性が欠乏していると痛感しました。指定したとおりにページを入れ替えられない状態が何度も発生したためです。この体験から、現在はAtCoderを使って実装を練習しています。
直近では、JavaScriptを使った動画編集アプリの実装を考えています。
経緯を紹介します。
動画編集ソフトウェアに必要なファイルは、動画の構成要素のメタ情報を記録した「プロジェクトファイル」と、動画内に読み込まれるオブジェクトのファイルです。
まず、プロジェクトファイルから動画ファイルを読み出すことは可能かどうかが疑問だったため、ReactでPoCを実装することにしました。
ChatGPTからこれについて、<input type="file">要素で指定されたファイルのFileHandlerをIndexedDBなどに保存すると、いつでも保存したFileHandlerを使ってファイルを読み出せる、との回答を得ました。
疑わしい回答と感じ、以下のPoCを作成しました。
これを実行したところ、IndexedDBへオブジェクトが保存されるとき、オブジェクトには「構造化複製アルゴリズム」が適用され、メソッドが剝がされてしまうことを確認しました。
FileHandlerを保存することは難しいと結論付けました。
代わりに、「OPFS」と呼ばれる領域に、ユーザーが過去に<input type="file">で指定したファイルをキャッシュすることにしました。
OPFSは、File System Access APIで使用する特別な領域で、Webアプリケーションがユーザーの操作なしに読み書きすることが可能です。OPFSを使えば、ユーザーが指定したファイルを保存して、あとから自由に読み出すことができます。
次に、読み出した動画のデータから、動画編集に必要なフレームの画像データを取得する方法を考えました。
WebAssemblyからFFmpegを利用できるffmpeg.wasmを使ってフレーム画像を取得するのが、初めに考えたアイデアです。
PoCを実装する前は、ある程度期待通りに動作すると思っていましたが、実際に実装してみると、パフォーマンスが非常に悪かったです。
現在フレーム数をuseRefで保持し、ユーザー入力またはsetIntervalによる自動再生でフレーム数を増加させます。
setIntervalでffmpeg.wasmを呼び出し、画像を取得してCanvasに描画します。
ffmpeg.wasmが動画から1フレームを切り出すのは非常に時間がかかります。普通は、ある程度のフレームをまとめてデコードするのがMPEG4の構造上自然であり、1フレームごとに切り出しを別々に行うと、デコード処理に多くの時間がかかるからです。
このとき既に別のアイデアが浮かんでいたので、この方法の模索は中断しました。
ffmpeg.wasmを使うのではなく、ブラウザが用意している方法でフレーム画像を取得することを考えました。
すなわち、<video>要素を一定間隔でCanvasに写し取る方法です。
これはChromeではよく動きました。
しかし、Firefoxではフレーム画像の描画に許容できない時間がかかり、描画し切る前に次のフレームに移ってしまう状態でした。
Chrome以外のブラウザで、CanvasのdrawImageが遅いという検証が存在します。
(2010年のエントリのため、現在では状況が変化しているかもしれません)
この問題は、グラフィックの領域でフレームバッファを複数用意するアイデアのように、OffscreenCanvasにいくつかのフレーム画像を同時進行で書き込むことで解決できるかもしれない、と考えています。
ほかに、オセロを実装したことがありました。
高校のパソコン授業の裏でこそこそやっていました。
Canvasにオセロの盤面を表示します。
BitBoardによる最適化と、Min-Max法による候補手探索、αβ法による枝刈りを含むプログラムになり、オセロが苦手な自分が苦戦する程度の強さにはなりました。
・C言語
ソケットプログラミングの学習のために大学の図書館で借りた『TCP/IP ソケットプログラミング C言語編』(オーム社)を読んだ際に利用しました。
本を読む際にUbuntuのDevContainer環境を立ち上げました。
FFmpegを利用したプログラミングに習熟するため、libavを学習していました。
・Python
以前にDiscordボットの実装に使用していました。
バックエンドにFlask、フロントエンドにVue.jsを使った、Discordのメッセージ管理アプリを作成したことがありました。
DjangoやFastAPIはチュートリアルを進めたことがあります。実用的なアプリケーションは思いつかず、作っていません。
JavaScriptでオセロを作る以前に、PythonでもオセロができるDiscordボットを開発していました。
Discord.pyというDiscord APIのラッパーのソースコードを読み進め、Qiitaに記事を発表していた時期があります。
ここ数週間は、AtCoderでPythonを利用しています。
・Rust
チュートリアルを時間をかけて読み進めましたが、使う機会がなく忘れている状態です。
・Java
教科書の内容を理解しましたが、使う機会がなく忘れている状態です。
・bash
GitHub Actionsのcronで自動的にスクリプトを実行させたくて書くことがあります。
これはChatGPTの記述したものに手を加えて使っています。
(3)
コンテナ技術は、普段からVisual Studio CodeのDevContainerを使用しています。
普段使いするときの目的は、Linuxで動作するプログラムを実行するためです。
例:
実行時の環境差異を吸収する目的で、Docker上でプログラムを実行するように設計したことがあります:
Kubernetesが必要になるような状況に遭遇したことがないため、Kubernetesを使ったことはありません。
(4)
自動でSSH接続とpull、スクリプトの実行を行うGitHub Actionsを設定したことがあります。
DiscordボットをConoha VPSにデプロイしたいとき、毎回SSHでVPSにログインしてソースコードをpullするのが面倒に感じたためです。
3
ヘッドレスUIを直近で試してみたいと思っています。
ヘッドレスUIは、UIコンポーネントのうち、ロジックやアクセシビリティといった、直接見た目に関わらない部分のみを提供するライブラリです。
従来、MUIやChakraUI、DaisyUIなどが提供するUIコンポーネントには、丁寧にデザインされたスタイルがあるのが普通でした。
これは、Webアプリケーションのモックを作ったり、最低限のセマンティックなUIがあれば良い場合には、細かい見た目を考えなくてよいので、重宝します。
一方で、多くのプロダクトでは、既にUIデザインが存在し、コーダーがCSSを実装するプロセスが一般的だと思います。
(私は実務経験がないため、これはいくつかの記事を読んだうえでの推測です)
既にピクセル単位で詰められたカンプがある場合、UIライブラリが提供するコンポーネントのスタイルは邪魔になってしまいます。
私自身、MUIのコンポーネントのスタイルと、先に作ったカンプが上手く一致せず、sxプロパティで細かいカスタムを施し、疲弊しました。
例:
ヘッドレスUIを使うと、見た目へのこだわりを今までよりも強く反映できると考えています。
階層のあるコンテキストメニューなどは、ボックスの表示位置などを正しく実装するのが難しいです。
動画編集アプリのタイムラインを実装したあと、タイムライン上のオブジェクトに右クリックメニューを追加したくなりましたが、正しく実装できずに後回しになっています。
ヘッドレスUIではロジックと見た目を分離できると思うので、この問題にも良い解決策を見つけたいと考えています。
4
『Practical client-side path-traversal attacks』に興味を持ちました。
(1)
この脆弱性は、Acronis CloudというWebサイトで発生しました。
ユーザーが個人情報を盗まれる危険性があります。
ユーザーはこの攻撃において、攻撃者の用意したURLにアクセスする以外は何も操作をする必要がありません。
ユーザーの背後では任意のCSSファイルがロードされているだけなので、ユーザーは情報漏洩に気付かない可能性があります。
(2)
Acronisではテーマの切り替え機能が実装されていましたが、URLパラメータの入力値を元にロードするCSSファイルを組み立てていました。
加えて、Acronisではパラメータのサニタイズを行っていませんでした。
このため、攻撃者がパラメータに/(%2F)などを含めさえすれば、ロードするCSSファイルの相対パスを自由に組み立てられる状態でした。
CSSファイルとして読み込まれるから、適当なCSSファイルを読み込ませればユーザーはこの攻撃に気付くことができませんし、攻撃者の用意したURLにアクセスする以外にユーザーが何か操作をする必要もありません。
さらに派生して、Acronisがユーザー認証に使っているエンドポイントでは、認証後にstateパラメータに指定されたURLにユーザーをリダイレクトさせる仕組みでした。
攻撃者は、このエンドポイントをURLパラメータに指定してブラウザにバックグラウンドでリクエストを送信させ、さらにstateパラメータを用いて攻撃者のCSSファイルにそのリクエストをリダイレクトさせました。
攻撃者は、任意のURLのCSSファイルをバックグラウンドでロードさせることができます。
リンク先にあるPoCでは、CSSセレクタを用いてAcronis上の個人情報を窃取することの実現可能性が示されました。
(3)
この脆弱性が発生した原因はいくつかあります。
まず、CSSファイルの組み立て方法です。Acronisは、これを独自に実装すべきではありませんでした。
AcronisはURLパラメータのサニタイズを適切に行えなかったため、今回の脆弱性に繋がりました。
また、URLパラメータの値を制限するのも有効です。
今回は、color_schemeというパラメータの値が、想定しない値の場合には不正なアクセスとして取り扱えば問題は拡大しなかった可能性があります。
CSSインジェクションによるDOMの内容の窃取には様々な方法があると、今回の調査で知りました。
CSSセレクタを利用した方法は実際に動作を試してみたかったのですが、時間の都合で難しかったです。提出が終わったら、試したいと思いました。
5
(1)
Webサイトへのアクセスには、ユーザーが直接WebサイトのURLにアクセスする場合と、ほかのWebサイトに埋め込まれる形でアクセスする場合がある。
前者をトップレベルサイトという。
CHIPSは、トップレベルサイトごとにCookie情報を分離(以下Partitioning)する仕組みである。
異なるトップレベルサイトでは、そこに埋め込まれたWebサイトの、PartitioningされたCookieの状態も異なる。
従来、Cookie情報はWebサイトごとに分離されてこなかった。
地図アプリ Hoge Map を例に考える。
Hoge Mapは、ユーザーが最近検索した位置をCookieに保存する。
ECサイト Huga Shop は、地図をアプリ上に埋め込みたいと考えた。
Huga Shopは、Hoge MapをWebサイトに埋め込む実装をした。
もしHoge Mapが、Cookieにユーザーを識別するユニークな番号を持っていたらどうなるか?
まず、CHIPSという仕組みが存在しなかった場合。
Hoge Mapは、Huga Shop上の埋め込みをユーザーが利用した際に、Cookie情報を元に「Huga Shopを利用したユーザーA」と「Hoge MapのアカウントB」を紐づけることができる。
この例では、Hoge Mapは、Huga Shopを利用するユーザーの動向をトラッキングすることができる。
CHIPSがあった場合。
Hoge MapとHuga Shopは異なるトップレベルドメインを持っている。
CookieがPartitioningされるので、Hoge Mapにトップレベルサイトとしてアクセスした場合と、Huga Shop上の埋め込みを利用した場合では、異なるCookieが読み書きされる。
Hoge MapがHuga Shopのユーザーを先の方法でトラッキングするのは難しい。
(2)
従来のWebでは、サードパーティCookieを利用したクロスサイトトラッキングが行われてきた。
JavaScriptなどでユーザーの閲覧履歴を取得することは難しいため、サードパーティCookieを用いたクロストラッキングでユーザーの利用状況を取得しているというからくりである。
ユーザーのWeb利用状況は、Web上でターゲティング広告を表示するのに有効だ。
したがって、広告業者から見ればトラッキング情報は自身の業績を向上させるために必要な道具だ。
一方で、一般のWebユーザーから見れば、許可なく自身の利用状況を取得されてしまう状況である。
サードパーティCookieのPartitioningやブロックがなければ、トラッキングを拒否する権利すらない。
FirefoxやSafaliは、サードパーティCookieをデフォルトでブロックする方針で対応してきた。
特にFirefoxはプライバシー保護を重視する傾向にあり、非営利団体のMozillaが運営している。
Chromeを運営するGoogleは広告業を行っているため、広告の支えであるサードパーティCookieは、ブロックせずにいた。
Googleの主張では、FirefoxのようにサードパーティCookieをブロックすれば、広告業者は新たなトラッキング手法を求めて、不適切なフィンガープリンティングを実行する可能性がある。
サードパーティCookieのブロックにより適切な広告を表示できなければ、パブリッシャーの資金が半分程度まで下落するとも主張した。
適切な広告を表示できないと、広告主は十分な広告効果が得られない。
パブリッシャーは広告主に広告の基盤を販売する組織なので、適切な広告を表示できなければ、販売実績は悪化するだろう。
広告業が縮小すると、今までWebで文書を無料で公開してきたユーザーが報酬を受け取れなくなり、現在のWebが崩壊すると主張する。
したがって、GoogleはサードパーティCookieを廃止こそすれど、ユーザーのトラッキング情報を取得する新しいメカニズムを実装する道を選んだ。
トラッキングができないと、適切なターゲティング広告を表示できないからである。
・・・
大変恐縮ですが、時間内に文章をまとめ切れなかったため、以下に調べた記録のURLを掲載させていただきます。
①CHIPSについて、Chromeの主張を起点に調査したもの。
② PythonでWebサーバーを2つ立て、localhostの各ポートをngrokに転送することで実験したもの。
参考までに、ご一読いただければ幸いです。よろしくお願いいたします。