セキュリティ・キャンプ2026全国大会 応募課題さらし(CDN自作ゼミ)

セキュリティ・キャンプ2026全国大会 応募課題さらし(CDN自作ゼミ)

date: Tue, 07 Jul 2026 author: repunit11
#セキュリティキャンプ #CDN自作ゼミ

こんにちは!学部4年のレプです!
今回、セキュリティ・キャンプに参加させていただけることになりました。
すごくうれしいです。 セキュリティ・キャンプでは応募課題晒しという文化があるようなので僕もやろうと思います。

セキュリティ・キャンプとは

まずセキュリティ・キャンプとはなにかについて軽く説明します。
IPAが主催するセキュリティ人材を発掘・育成するプログラムです。
毎年夏に1度全国大会があり、その他にミニキャンプが年に10回ほど全国各地で開催されています。
参加するためには応募課題を出して書類審査に通過する必要があります。

詳しくはこちら https://www.ipa.go.jp/jinzai/security-camp/index.html

応募課題

早速応募課題を晒していきます。一部改変している部分がありますが、ほとんどこのままの状態で提出しました。

プログラミング自己アピール

これまでのプログラミング経験について教えてください。

質問の背景:CDNの自作は、発展的なシステムソフトウェアのプログラミング課題です。受講生の皆さんには、何らかのプログラムを開発した経験があることを期待しています。特に、低レイヤの開発経験、システムプログラム、ネットワーク関連ソフトウェアの開発経験があれば、ぜひ教えてください。

以下の点について、特にお聞きしたいです: ・Go言語やC言語の利用経験(演習はこれらのプログラミング言語を使用します) ・(強く推奨) 実際に書いたソースコード(GitHubなど、公開レポジトリへのリンクを歓迎します) ・ソフトウェアを開発した動機や背景、解決したかった課題 ・技術的に自信のある点 ・開発の際に参考にした文献・資料・コードなど ・ 「なぜ〇〇という技術的手法を選んだのか?」その選択の理由(△△や⬜︎⬜︎ではなく〇〇を選んだ理由)を教えてください ・ 開発時に苦労した点。例えば、どのようなバグに直面し、どのようにデバッグしたのかなど

補足: ・開発したソフトウェアが複数ある場合は、いくつ書いていただいても構いません。 ・技術的な側面を中心に記述してください。ソフトウェアの社会的意義などは深掘りしなくて大丈夫です(「自分が考える最強のHTTPサーバを作ってみたかった」などでもOKです)。 ・既存のドキュメントやレポートなどがある場合は、ぜひ共有してください。

ここでは2つ制作したプロダクトを紹介します。

私はx86-64向けのCコンパイラをGoで実装するということを行いました。
セルフホストができるレベルには達していないのですが、小さめのプログラムであれば動く程度にはできています。
実際に書いたソースコードはこちらです。https://github.com/repunit11/gominicc
これを開発しようと思ったのはただコンパイラを実装してみたいという好奇心からでした。昨年度は活動の幅を広げた一年で、いろいろな人に出会い、システムプログラミングのおもしろさを感じることができました。作りたいもの、やりたいことがたくさん出てきてその一つとしてCコンパイラを実装することに決めました。
開発の際に参考にした文献を以下に示します。
https://www.sigbus.info/compilerbook
https://speakerdeck.com/latte72/x86-64-assembly-essentials
https://www.fos.kuis.kyoto-u.ac.jp/~umatani/le4/pdf/mainSlides.pdf
今回初めて低レイヤの開発を行ったので、見よう見まねで作成しました。そのため、技術的に手法を選ぶというほどのことはできませんでした。
苦労した点としては、intとポインタのサイズを分けて実装する時にintのサイズ、ポインタそのもののサイズ、ポインタがさしている先のサイズ、スタック上の配置間隔を区別する必要があり、そこが難しかったです。ポインタを実装した当初、ポインタはメモリ上のアドレスを表す整数値としてとらえていました。そのため、隣の変数にアクセスする際は*(&y + 8) = 7 のようなテストを書いていました。sizeofではintは4バイト、ポインタは8バイトとして扱う必要がある一方、ポインタ演算ではp+1が1バイト進めるのではなく、指している型のサイズ分だけ進む、さらに現在の実装では簡略化のためローカル変数を8バイト間隔で配置していたためCの型のサイズと実装上の配置サイズが完全には一致せず、その違いを意識する必要がありました。サイズの問題でテストが通らないことが頻出してどのようにすればいいのかをLLMに相談しながら理解を進めて実装を進めました。

今回は最初だったのでこれで終わりましたが、もう一度作成したいと思っています。その理由としては、最初の方は資料をそのままGoに置き換えるようなものでいけたのですが、後半は前半の理解が甘い部分が積もってきて理解、実装に時間がかかり完璧な理解で完成することができませんでした。ただ、現在であれば全体像を理解している状態で再び作成する事ができると思うし、システムプログラミングの知識もかなりついてきているので次はCコンパイラだけでなくGoのコンパイラを作ってみたいと思いました。
つい最近、GoコンパイラをGoで自作してセルフホストしている学生の方がいて、その方のブログを読みました。これを読んでかなり悔しさを感じました。自分も作れるようになりたいと思いました。このブログを読んで、自分に足りないこととしてOS周りの知識が足りないと感じました。具体的にはシステムコールの使い方、呼び出し方、リンカの使い方・仕組みなどです。また、英語文献を読む力も足りないと感じました。Goの言語仕様は英語でかかれていて、現在はAIがあるから比較的簡単に読めるけれど英語で読んだ方がニュアンスも分かったり、翻訳をかけるという手間がなくなるので英語のまま読めるようになりたいと思いました。

簡単にまとめたレポートです。https://repunit11.com/blogs/2026-03-22-c-compiler-in-go/

また、最近行っているのはGoのnetパッケージを中心に利用してHTTPサーバーをTCPソケット上で実装しています。
実際に書いたソースコードはこちらです。https://github.com/repunit11/go-http
HTTP/1の実装からHTTP/1.1で行われている実装、具体的にはHTTP/1ではリクエストのたびにTCPコネクションを作り、レスポンスのたびにTCPコネクションを閉じるという流れを初めは実装しHTTP通信をソケット上での処理の流れを理解しました。HTTP/1.1の特徴的な機能として、Keep-Alive、gzip圧縮、チャンク形式の転送、パイプライニングに対応しました。

開発の際に参考にした本はこちらです。
渋川よしき、『Goならわかるシステムプログラミング -第2版-』、ラムダノート株式会社

開発をしようと思ったのはこの本に出会ったからです。この本はGoのパッケージ仕様や言語仕様、ランタイムなどからシステムプログラミングを勉強するというテーマの本で、IO、システムコール、ソケット、ファイルシステム、プロセス、並行処理、メモリ管理、コンテナといった低レイヤ全般を解説しています。私はこの本に2か月ほど前に出会いました。読み進めるうえで知らないことがたくさん出てきて実装してみたいと思うようになりました。そこで目についたのがHTTPサーバーの実装でした。
この実装では、HTTP/1.1の各機能を追加したときに通信の流れや性能がどう変わるかを確認するためにベンチマークも取りました。ただ機能を追加するだけでなく、どの部分を複雑にしすぎないか、どこまでを小さく保つかを考える必要がありプログラムの構造を考えるいい機会になりました。
特に難しさを感じた点はパイプライニングです。複数のリクエストを連続して送ることができますが、レスポンスはリクエストと同じ順序で返す必要があります。接続ごとにリクエストの順序や状態を管理する必要がある。現状の実装ではGETメソッドを中心に取り扱っているのでデータ競合などが起こらないようにしていますが、より実用的にするには接続ごとの状態管理や並行処理などを考えて実装していく必要があると感じました。

このプログラムは、結論からいうと現状の出来にはまだ納得していません。なぜなら、応募している段階ではまだ写経した程度から成長していないからです。ただ、先ほども書いた通り今はHTTP/1.1の機能が実装できた程度でしかないのでHTTP/2、HTTP/3まで実装していきたいという気持ちがあります。応募時点ではHTTP/1.1程度ですが実装は続けていくつもりなのでこの文章を読んでいただいているときにはもう少し発展しているかもしれません。
また、現在の実装はリクエスト、レスポンスの読み込みなどnet/httpパッケージに依存している部分も少しあるのでnetパッケージだけで実装できるように、さらにはシステムコールを利用して実装してみたいと思っています。
また、HTTP/1.1の実装なのでTCPスタックを用いた実装を行っていますが、QUICなどの実装をやろうとするとUDPスタックを用いた実装も進めることになるのでTCPとUDPの実装上の違いなども考えつつ実装していきたいです。
将来的にはTCP/IPプロトコルスタックを実装することを目標にして進めていきたいと思います。

インターネットって何?

「ブラウザのURLバーに、 https://www.shonenjump.com/j/weeklyshonenjump/ を入力して決定キーを押した時になにが起こるか」を調べて、可能な限り詳しく説明してください。

質問の背景:CDNをざっくり説明すると「すごいウェブサーバ」と言うこともできます。しかし、その“すごさ”を理解するには、まず通常の「ウェブサーバ」と手元の端末の間で、どのような処理・データのやりとりが、どのようなプロトコルで行われているのかを把握することが肝要です。

回答にあたっての注意: 文献やウェブサイトを参考にした場合は、参考文献を必ず明記してください。 LLM(大規模言語モデル)を使用した場合は、「共有リンク」を記載するか、それが難しい場合は「LLMに与えたプロンプト」および「編集前の出力結果」を添付してください。

本調査では、自宅ネットワーク内で自分が管理する端末から対象URLにアクセスし、その通信をパケットキャプチャした。他者の通信を取得しないよう、公共ネットワークや第三者が利用するネットワークでは実施していない。

まずはクライアントはwww.shonenjump.comドメインに対応したIPアドレスを取得したいので、まずはブラウザのDNSキャッシュを参照する。キャッシュは目的ドメインのIPアドレスを知らないためブラウザが設定しているキャッシュDNSサーバーに問い合わせる。今回はOSのDNSサーバーを利用すると設定されていた。まずキャッシュDNSサーバーが目的ドメインのIPアドレスを知っているかどうかを調べる。今回はキャッシュDNSサーバーは目的のドメインのIPアドレスを知らないので権威DNSサーバーのルートネームサーバーにcomを担当する権威DNSサーバーの情報を問い合わせる。ルートネームサーバーはcomのネームサーバーのIPアドレスを知っているためそのアドレスを返す。comのネームサーバーに問い合わせると、comのネームサーバーはshonenjump.comを担当する権威DNSサーバーの情報を返す。次にshonenjump.comの権威DNSサーバーに問い合わせることで、www.shonenjump.com のIPアドレスを取得する。キャッシュDNSサーバーはクライアントにそのIPアドレスを伝える。
これでIPアドレスを取得することができた。ちなみにDNSの問い合わせは基本的にはUDPを使って行われる。
2026年4月29日に実際に調べたところ、IPアドレスは202.218.223.232だった。IPv6には対応していないようである。

www.shonenjump.comの名前解決結果
www.shonenjump.comの名前解決結果

DNSの経路を確認するためにdig +trace www.shonenjump.com Aを実行したところ、タイムアウトした。いろいろ試してみて、dig \@8.8.8.8 +trace www.shonenjump.com Aは成功した。このことからPCがデフォルトで使用しているDNSリゾルバがルートゾーンのNS問い合わせに応答できない、または応答しない状態だったと考えられる。
また、この出力からshonenjump.comはAWS Route53のDNSサーバーを利用していると考えられる。

ここまでDNSによる名前解決について説明した。DNSの問い合わせ自体はアプリケーション層のプロトコルだが、実際の通信ではUDP/IPやEthernet/Wi-Fiが使われる。ここからは、IPパケットが宛先まで運ばれる仕組みをL2/L3の観点から説明する。
IPアドレスだけでは通信をすることができるわけではなく、MACアドレスを必要とする。MACアドレスはリンク層で使われている識別子で、IPアドレスはOS上で設定する論理的なアドレスである。
端末がデータを送信するとき、ネットワーク層から受け取ったIPパケットをイーサネットフレームにカプセル化して、ケーブルに流す必要がある。送信元MACアドレスは自身のNICに書き込まれているためわかるが宛先MACアドレスについてはわからない。そこでARPというプロトコルを用いて宛先IPv4から宛先MACアドレスを求める。ただしここで必要になるMACアドレスは最終宛先であるWebサーバーのMACアドレスではなく、同じLAN内で次にパケットを渡す相手のMACアドレスである。
具体的なアドレス解決を説明する。ここで説明上送信元機器をA、送信先機器をBとするAはネットワーク層から受け取ったパケットに含まれるIPv4を見て、自身のARPテーブルを検索する。ARPテーブルは以前アドレス解決をした情報を一定時間保持するテーブルである。すでにこのテーブルに該当する情報がある場合はBのMACアドレスをイーサネットヘッダーの宛先MACアドレスに入れてデータ通信を開始する。ARPテーブルに目的の情報がない場合はARP Requestの処理に移行する。ARP Requestは同一ネットワーク内のすべての機器に送信するブロードキャストである。BはARP Requestを受け入れてARPテーブルにAのMACアドレスとIPアドレスを書き込む。 続いてBはARP Replyを送信する。これはユニキャストである。AはARP Replyを見てARPテーブルにBのIPアドレスとMACアドレスを書き込んでキャッシュする。その後、BのMACアドレスをイーサネットヘッダーの宛先MACアドレスに入れてデータ通信を開始する。

今まで一対一の通信について説明したのでルーティングについて説明する。目的のIPアドレスにデータを送るために、ますはアクセスしている機器からデフォルトゲートウェイにパケットを流す。ルーターは宛先に向かう次ホップのルーターへパケットを渡す必要がある。ルーターはルーティングテーブルを参照し、宛先IPアドレスに対して最も長く一致するネットワークプレフィックスを持つ経路を選ぶ。 次にパケットを渡す相手である次ホップを決定する。次ホップが同一ネットワーク内にある場合、ARPによってその次ホップのMACアドレスを取得する。このとき、IPヘッダの宛先IPアドレスは最終宛先のままだが、Ethernetヘッダの宛先MACアドレスは次ホップのMACアドレスになる。その後ルーターからルーターへパケットを流して、次のルーターを決めて流してを繰り返していく。目的のルーターへ届いたら目的の機器はルーターからパケットを受け入れる。

後述するが目的のサイトではHTTP/1.1、 2、 3が使われていたのでとりあえずHTTP/1.1, 2で利用されているTCPについて説明する。 次に、取得したIPアドレスに向けてTCPコネクションを貼りたいのでSYNパケットを送る。先ほど記述した操作を続けていって目的のアドレスのサーバーにパケットを届ける。パケットが届いたら目的サーバーはSYN/ACKパケットを送り返す。クライアント側に届いたらACKパケットを送る。これでコネクションの確立は完了した。 TCP通信全体でフロー制御、輻輳制御、再送制御などの制御をうまく組み合わせて転送を行う。 時系列としては少しずれるのだが、コネクションを切るときにはクローズとよばれる処理を始める。 パケットを見たところ4ウェイハンドシェイクでクローズしていると考えた。

TCP接続終了時の4ウェイハンドシェイク
TCP接続終了時の4ウェイハンドシェイク

今回はサーバー側がクローズを要求しているようである。サーバー側はクライアント側にFIN/ACKパケットを送信する。FIN/ACKパケットを受け取ったクライアントはFIN/ACKパケットに対するACKパケットを送信する。クライアントはアプリケーションからクローズ処理の要求を待ち、要求があるとFIN/ACKパケットを送信する。サーバーはFIN/ACKを受け取ったらACKパケットを送信する。クライアントはACKパケットを受け取るとコネクションを削除する。

続いてアプリケーション層の話をする。まず、TLS接続を確立する。パケットを見たところTLS1.3であった。

TLS1.3のハンドシェイク
TLS1.3のハンドシェイク

具体的には、TCPコネクションを確立した後、クライアント側が自身が対応している機能や仕様をClient Helloに格納して送信する。そこでは、自身が対応している暗号スイート、TLSのバージョン、共通鍵交換用パラメータなどを送信する。Webサーバー側はClient Helloに含まれる情報と自身の設定をつき合わせて確定した情報をServer Helloに格納して送信する。これ以降の通信は確定した暗号化方式で通信は暗号化されていく。Webサーバーはハンドシェイクに関する追加情報をEncryptedExtensionsに含めて送信する。Webサーバーはインストールされているサーバー証明書と中間証明書をCertificateに格納して送信する。 Webサーバーはこれまでのハンドシェイク内容に対して、サーバー証明書に対応する秘密鍵で署名する。Webサーバーは最後にFinishedを送る。Webブラウザはデジタル署名を検証してFinishedを送る。TLS 1.3では、クライアントとサーバーが共有秘密を計算し、そこから通信用の共通鍵を導出する。サーバー証明書に対応する秘密鍵は、サーバーが本物であることを示す署名に使われ、ブラウザは証明書の公開鍵を使ってその署名を検証する。実際のHTTPデータの暗号化には、公開鍵暗号方式ではなく共通鍵暗号方式が使われる。これは共通鍵暗号方式の方が計算コストが少なく高速だからである。

TLS接続の確立時、ブラウザはClientHelloのALPN拡張で自分が利用できるHTTPのバージョンをサーバーに伝える。サーバーはその中から利用するプロトコルを選択し、TLSハンドシェイク完了後、そのプロトコルでHTTPのやり取りをする。 ブラウザのdevツールを確認したところ、HTTP/1.1/2/3が使われているようである。

HTTP/1.1およびHTTP/2の通信
HTTP/1.1およびHTTP/2の通信
HTTP/2およびHTTP/3の通信
HTTP/2およびHTTP/3の通信

HTTP/1.1ではリクエストライン、ヘッダーセクション、コンテンツで構成されるメッセージフォーマットでリクエストされる。リクエストラインはメソッドとリクエスト対象、HTTPバージョンで構成されている。ヘッダーセクションはフィールド名とフィールド値のペアで構成されている。コンテンツは実際に送りたいデータが格納されている。HTTP/1.1はTCPレベルにおけるパフォーマンス向上を図っている。 HTTP/2ではTCPレベルだけでなくアプリケーションレベルにおけるパフォーマンス向上を図っている。HTTPメッセージをバイナリ形式のフレームに分けて送受信したり、マルチプレキシングというストリーム処理を可能にする機能、HTTPヘッダを圧縮する機能などが追加されている。 HTTP/3ではTCPではなくUDP上のQUICを使う。TCP+TLSだとTCPの3ウェイハンドシェイクの後にTLSハンドシェイクを行うが、QUICでは接続確立と暗号化の手続きを統合できるため接続開始時の往復回数を減らせる場合がある。

参考文献:みやたひろし、『図解入門TCP/IP 第2版』、SBクリエイティブ、2025年
     井上直也・村山公保・竹下隆史・荒井透・苅田幸雄、『マスタリングTCP/IP 入門編 第6版』、オーム社、2019年
     Catchpoint Systems, Inc. TLS 1.2 vs. 1.3—Handshake, Performance, and Other Improvements https://www.catchpoint.com/http2-vs-http3/tls1-2-vs-1-3 (参照:2026-04-29)

自由アピール

問1ではプログラミング制作物にフォーカスしたものでしたが、他にあなたがアピールしたい点があれば、自由に記述してください。

例: ・既存のソフトウェアやハードウェアを組み合わせて複雑なシステムを構築した経験 ・他者のソフトウェアに脆弱性を発見した経験 ・興味や探究心をもって、既知・未知のシステムの動作原理を解明した経験 ・講義を通じて、具体的にやってみたいことがあれば教えてください。

ここ最近はシステムプログラミングにすごく興味を持っており、またGoが好きなのでGoの標準パッケージの内部実装を読んだりすることで理解を進めようとしています。直近のマイブームとしてガベージコレクションがあります。きっかけとしてはGo1.26で新しくなったGreenteaGarbageCollectionです。最初はある人が解説している内容を読んでアルゴリズムを理解しました。そこから自分でも調べてみたり、他の言語でのガベージコレクションがどのように実装されているのかを調べて理解しています。

僕はGoが好きである。Goはコンパイラや標準パッケージの多くがGo自身で実装されており、言語処理系や標準パッケージの実装をGoの知識で追いやすい。C言語や外部ライブラリへの依存をできるだけ小さくして、言語処理系・ランタイム・標準パッケージをGo自身で理解できる形に近づけようとしている点に尊敬を感じている。もちろん、アセンブリやcgoを利用している部分もあるが、通常のGoプログラムでは実装を追うことが比較的容易でであり、標準パッケージやランタイムがOSやアーキテクチャごとの差異をどのように吸収しているのかを調べられる点も面白いと思っている。また、システムプログラミングを最初に学ぶにはGo言語はすごくあっていると思っており、その理由は可読性を重要な指針として設計されていることと標準パッケージがGoで書かれているので最初の概念を学ぶにはいいと思っている。

今まで行ってきた活動としては、技術カンファレンスへの参加、運営、イベントの参加などをやってきました。勉強会などは積極的に参加しており、特に福岡市周辺で開催されている勉強会はかなり参加しています。現時点では外部登壇の経験はないのですが、話したい内容はたくさん有るのでこれから登壇していきたいと思っています。技術カンファレンスへの参加もよくしていて、メインは福岡周辺で開催されているものですが、行きたいカンファレンスは東京だったり名古屋だったりに参加しています。色々参加する上でカンファレンスのスタッフをやってみたいと思ったことがあり、実際にGo Workshop Conference 2025 IN KOBEのコアスタッフをやっていたり、Go Conference 2026のスタッフもやっています。私の野望としては学生のうちにカンファレンスにCfPを通すことです。

今回のセキュリティキャンプではまずはCDNの仕組みを理解して実際に動作するような状態を目指したいです。その後、分散アルゴリズムを実装したいです。私は現在分散アルゴリズムの研究をやっています。大学での研究は理論に寄っているのでそれを実際に実装に組み込んでみたいです。正直なところ、CDNに関する知識はほとんどなく、分散アルゴリズムに関する知識もまだ足りないと思っています。なので作りたいCDNについてのイメージがしっかりついているわけではありません。これらは実際に学んでいく上で、作っていくうえで考えていきたいと思っています。現時点ではエッジサーバーに障害が起きたときに別ノードに切り替えるアルゴリズムやキャッシュ配置などのアルゴリズムに興味があるので詳しく知りたいと思っています。

おわりに

僕はそこまで実力がないと思っているのでこの応募課題も期間内ずっとやっていました。ゴールデンウィークはほとんど課題に取り組んでいました。
今年はセキュリティ・キャンプの応募課題とSecHack365の応募課題がほぼ同じ時期になっていたのでずっとパソコンに張り付いていました。(SecHack365は残念ながら落ちました)
もしセキュリティ・キャンプに興味がある方はぜひ応募課題に取り組んでみたほうがいいと思います。たとえ落ちてしまったとしても課題自体に取り組むことがかなりの力になると思います。

あと一ヶ月で始まるので事前課題から頑張るぞ~!
最後まで読んでいただきありがとうございました。

共有する