こんにちは。Flatt Securityの @toyojuni です。弊社は セキュリティ診断(脆弱性診断) や、セキュアコーディングのeラーニング 「KENRO」 を提供し、SaaS企業などさまざまなプロダクト開発チームのセキュリティをサポートしています。
今回、2022年末から2023年始にかけて1ヶ月ほど、「新卒開発エンジニアへのセキュアコーディング挑戦状 presented by KENRO」というキャンペーンを展開しました。Webセキュリティに関する簡単なクイズを3問解いてもらって、正答者にはステッカーをプレゼント!という企画です。
ハンズオンの設問も含むので一定ボリュームがあるものでしたが、Twitter上で確認できる限り合計で180人以上の方に全問正解いただくなど大反響でした。皆様本当にありがとうございました。
ステッカープレゼントは既に終了していますが設問への回答は現在も可能ですので、まだの方は是非トライして見てください😉
今回のブログでは、「なぜこのようなキャンペーンを実施したか」という背景を紹介した上で、「エンジニア向けのセキュリティ学習・教育は『楽しく』始める」ことが大事であるという我々の考え方を紹介できればと思います。
弊社ブログの読者のエンジニアの方は自社で新卒をはじめとした若手の育成に関わることもきっと多いでしょう。そんなみなさんがセキュリティ学習・教育を考える上で参考になれば幸いです。
※以下、今回のクイズのヒントになる情報や解答・解説を含みます。
「セキュアコーディング挑戦状」概要
セキュアコーディング挑戦状は全3問の構成ですが、それぞれ以下のようなものでした。
- XSS(クロスサイトスクリプティング)に関する4択問題
- オープンリダイレクトに関する4択問題
- SQLインジェクションを体験するハンズオン問題
3問目のようにデモ環境に擬似攻撃を行うハンズオンはセキュリティ技術を競い合うCTF(のWeb問題)と同様のものです。 解答するに当たって負担がかかりすぎるものにはしたくなかったので、1問だけハンズオンという構成としました。
なぜ「セキュアコーディング挑戦状」キャンペーンを実施したか
このトピックは以下のように3つに分解して、順に見ていきます。
- なぜ(新卒・若手)Webエンジニアがセキュリティを学ぶ必要があるか
- なぜ現代でもXSSなど基礎的なコンテンツを学ぶ必要があるか
- なぜクイズ形式で実施したか
なぜ(新卒・若手)Webエンジニアがセキュリティを学ぶ必要があるか
そりゃセキュリティは言わずもがな重要だろうというツッコミを受けそうな見出しではありますが、改めて我々なりの視点で強調させていただきます。
前述の通り我々はセキュリティ診断(脆弱性診断)サービスを提供し、様々な企業様のプロダクトを時にはソースコードレベルで見させていただいています。そして多くの場合重大な脆弱性を検出し、報告させていただきます。
もちろん「セキュリティ屋」として上から目線な話がしたいわけではありません(それは非常に良くないことです)。
セキュリティは特殊で情報の非対称性が大きい領域ですからやはり開発者の皆さんが学ぶのは簡単ではない、ということです。Webエンジニア人口の裾野も広がっている中、社会全体としてよりエンジニアがセキュリティを学習しやすい環境が求められていると思います。
それはまさに我々が「KENRO」を提供したり、本技術ブログでの発信を行っている理由でもあります。
なぜ現代でもXSSなど基礎的なコンテンツを学ぶ必要があるか
前述の通り今回扱ったコンテンツはXSS、オープンリダイレクト、SQLインジェクションといったWebセキュリティの基礎と言える領域でした。
「KENRO」で取り扱っているのも同様に基礎的な領域なのですが、そこでよくいただく質問が「現代ではそのような典型的な脆弱性はWebフレームワークが防いでくれるのでは?」というものです。
端的には「残念ながらそういった基礎的な脆弱性は現代であっても検出されるので学ぶ必要がある」というアンサーになるのですが、「KENRO」を導入していただいたウォンテッドリー様のCTO(当時)の川崎様のコメントが非常にわかりやすいので、引用させていただきます。
Ruby on Railsはよくできているフレームワークです。普通に使っているうちは脆弱性も生まれにくいでしょう。しかし、だからこそフレームワークが担ってくれている基礎的な部分をエンジニアが学ぶ機会が少ないのです。そうなるとRailsの標準的な使い方から外れて行った時に、どのようにすればセキュアに開発できるかわからなくなってしまいます。
(中略)
Ruby on Railsはフレームワークレベルで脆弱性を防ぐ仕組みがいくつもありますが、開発者自身が気をつけないといけない点も多々あります。先ほどお話しした課題に近い話ですが、フレームワークレベルの仕組みがあるからこそ意識が低くなりがちなので、堅牢化演習で実践形式で学べてよかったという意見もありました。
※「堅牢化演習」とは「KENRO」内における脆弱なソースコードの修正演習です。
なぜクイズ形式で実施したか
ここまでの内容で、Webセキュリティの基礎の学習の重要性はお伝えできたかと思うのですが「やれ」と言うだけで全体的な底上げが進むことはないでしょう。何より、仕組みとしてイケていません。
そこで、今回のクイズのように楽しんで学習できる仕組みというのはとても大事です。
セキュリティというとっつきにくい領域に「楽しんで第一歩を踏み出せる」ことを目指して今回のセキュアコーディング挑戦状のコンテンツは制作しました。
またまたお客様の声の引用ですが、クイズやハンズオンを通した学習は特に若手メンバーに関して有効であるということを、イルグルム 様もお話していました。
僕もエンジニア出身なのでわかるのですが、やはり若手エンジニアは、セキュリティを学ぶより動くものを作ることに目が向きがちなんですよね。
IPAのドキュメントや技術書を読むことをすすめても、受け身の学習は楽しみながら進められないため、なかなか読み切れないようでした。だから「CTF形式でセキュリティを学習できるサービスなら楽しみながら取り組んでくれるのでは」と思い、問い合わせをしました。
よほどシニアメンバーばかりでない限り、セキュリティを組織的に学習していくに当たって課題がないという開発チームは少ないのではないでしょうか。そういった皆さんに参考にしていただければ幸いです。
宣伝
解答・解説に移る前に宣伝です🙇♂️
Webセキュリティの学習に興味を持った方は是非以下より「KENRO」のトライアル版もご利用ください。有料版のコンテンツの一部ではありますが、無料・無期限でハンズオンに取り組むことができます。
また、今回の挑戦状より難易度がやや高いクイズを本日(2/14)の20時より24時間実施予定ですので、是非公式Twitterをフォローしてお待ちください!
⚡️ Developers' Quiz #5 明日20時開催! ⚡️
— 株式会社Flatt Security (@flatt_security) 2023年2月13日
大人気企画第5回!明日20時に皆さんにクイズを出題します。
正答者のうち、抽選で100名にオリジナルチョコとステッカーをプレゼント 🍫
奮ってご参加ください! pic.twitter.com/3oPgkTQnic
「セキュアコーディング挑戦状」解答・解説
最後に、今回のクイズの解答・解説です。
1. クエリパラメータの値がDOMに反映されるアプリケーション
設問
以下のように、クエリパラメータの入力値がDOMに反映される機能がとあるWebサイト(以下、サイトA)で提供されていました。
このサーバーの実装が以下のソースコードのようなとき、 どのようなリスクがあると考えられるでしょうか。
const http = require('node:http'); const {URL} = require('node:url'); const portNum = 8082; const host = 'localhost'; const server = http.createServer(function(request, response) { const url = new URL(`http://${host}:${portNum}${request.url}`); const name = url.searchParams.get('name') || ""; response.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'}); if(name === "") { response.end('<h1>誰かさん、お誕生日おめでとう!!</h1>'); }else{ response.end(`<h1>${decodeURI(name)}さん、お誕生日おめでとう!!</h1>`); } }); console.log(`access http:/${host}:${portNum}`); server.listen(portNum);
選択肢
- 攻撃者がnameパラメータに
<script>
タグを入力したURLを作成し、サイトAのユーザにアクセスさせることで、ユーザのブラウザ上で任意のスクリプトを実行させられてしまう。 - 攻撃者がnameパラメータにHTTPレスポンスヘッダを改ざんする文字列を入力したURLを作成し、サイトAのユーザにアクセスさせることで、ユーザのブラウザ上で任意のスクリプトを実行させられてしまう。
- 攻撃者がパラメータにサイトAのサーバー上のリソースを指定することで、攻撃者のブラウザにそのデータが送信されてしまい機密情報が漏洩する。
- 攻撃者がパラメータにシェル上でコマンドを実行するような値を入力することで、サイトAのサーバー上で任意のコードを実行されてしまう。
解答・解説
正答は「1」でした。入力値がDOMに反映されるアプリケーションではXSS(クロスサイトスクリプティング)のリスクが存在します。
クエリパラメータなど、ユーザが自由に入力できる値がDOMに反映され、かつ適切な対処がなされていない時、<script>
タグなどを用いて攻撃者にJavaScriptを注入されると、被害者のブラウザ上で任意のJavaScriptコードが実行可能となりCookieの窃取など様々なリスクにつながります。XSSのさまざまなリスクを解説したブログ記事もぜひご覧ください。
2. 認証完了後に遷移するページを柔軟に指定できるアプリケーション
設問
以下のように、ログイン認証後クエリパラメータに入力されたURLに遷移する機能がとあるサイトで提供されていました。
このリダイレクト処理はサーバーサイドで実行されますが、クエリパラメータに入力されたURLに対して適切な対応がなされてない場合にはどのようなリスクがあると考えられるでしょうか。
選択肢
- 外部の立場から、特定のメールアドレスがそのサービスへ登録されているかどうか確認できる。
- ログイン後に攻撃者の用意したページへ遷移させられフィッシング詐欺等の被害につながってしまう。
- 認証を回避してログインができてしまう。
- ログイン後のセッションIDが推測できてしまい、なりすまし被害等につながる。
解答・解説
正答は「2」でした。リダイレクト先を自由に指定できてしまうとオープンリダイレクトにつながります。
リダイレクト先がクエリパラメータなど外部から操作できる値で決定されている場合、適切な対策を施さないと外部の悪意あるサイトへのリダイレクトを許してしまいます。攻撃者の用意したパラメータ付きのURLでログインしてしまったがために、ユーザがフィッシングサイトに誘導されてしまうようなリスクは防ぐべきでしょう。
3. SQLによって商品検索を行うアプリケーション
設問
以下のように定義されているテーブルの中を検索する機能を持った Web アプリケーションがあるとします。
CREATE TABLE `item_list` ( `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `available` BOOLEAN NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
このテーブルを検索する際には available が TRUE のものだけが表示されるようにアプリケーションが作られています。具体的には、検索時に以下のようなSQL文が発行されて、その実行結果が返されています。
SELECT name, price FROM item_list WHERE name LIKE '%(ユーザからの入力値)%' AND available = TRUE
しかし、このアプリケーションには入力値の処理に関する脆弱性が存在するため、available が FALSE の商品もアプリケーション中に表示することができてしまいます。演習環境で脆弱性を突き、available が FALSE の商品を表示させることで flatt{...}
形式の隠されたデータを奪取してください。
解答・解説
検索欄に入力する文字列の解答例としては '; --
などになります。
';
によってSQL文を終了させ、--
のコメントアウトによって商品検索のフィルタとして機能している AND available = TRUE
の部分を無効化することがポイントです。
根本的な対策としては静的プレースホルダなどを用いて、ユーザーの入力値によって構文を破壊されないようにすることが挙げられますが、「KENRO」のトライアルを含め様々な文献が世の中にありますので、ぜひ調べてみてください。
ユーザーの入力値を直接受け付けてしまうことには様々なリスクが潜んでおり、SQLインジェクションはその一例に過ぎませんので、他のリスクに関しても類推を働かせながら学習できるようになると理想と言えるでしょう。
解答・解説は以上です。 ここまでお読みいただきありがとうございました!