IoT Security 15 · ソフトウェア防御と脆弱性管理

Chapter 15

ソフトウェア防御と脆弱性管理

この章がなぜ必要なのか——CRA が要求するのは、まさにここだから.

04 章で見たとおり、セキュアブートは「正規に署名された脆弱なファームウェア」を 喜んで起動する。完全性は守っても、安全性は守らない。

そして 03 章で見たとおり、EU CRA は「既知の脆弱性なしで出荷すること」と 「サポート期間中の脆弱性対応」を法的義務にした。

つまり——脆弱性管理は、もはや技術的な良心ではなく、法的な要件である。

この章で使う既出の用語(定義は各リンク先). セキュアブート(02 章 3 節)、サポート期間中(03 章 2 節)、不可能(04 章 3 節)、完全性(06 章 6 節)、必要(09 章 6 節)、ベンダ提供(13 章 9 節)、最も危険(13 章 6 節)、CRA(14 章 6 節)、市場(14 章 5 節)、確実(14 章 6 節)、開発(14 章 5 節)

1. 組み込みで起きる脆弱性の型

セキュアブートが守らないものセキュアブート:正規に署名されたコードだけが動く★ しかし、その正規のコードに脆弱性があれば止められないメモリ安全境界チェック、安全な文字列関数、Rust の採用実行時の緩和スタック保護、MPU、W^X、ASLR入力の検証外から来るものは全部疑う。ファジングで確かめる署名検証はあくまで「誰が作ったか」の保証。中身の品質は別の層で担保する
セキュアブートを入れると安心してしまいがちだが、守っているのは出所だけ。中身の脆弱性には無力

メモリ安全性のバグ

C/C++ で書かれた組み込みソフトウェアの、最大の脆弱性源である。

型内容典型的な発生箇所
バッファオーバーフロー配列の範囲外に書くパケット解析、文字列処理
整数オーバーフロー長さ計算がオーバーフローして、小さいバッファに大きく書くlen = a + b; の後の malloc(len)
符号の混同int と size_t の比較で負値が巨大な値になる長さチェック
Use-after-free解放後のポインタを使う動的確保がある場合
オフバイワン<= と < の間違いループ、境界チェック
フォーマット文字列printf(user_input)ログ出力
スタックオーバーフロー再帰、大きなローカル変数深い呼び出し

メモリ安全性の脆弱性を見る

コードパターンを選ぶと、何が起きるか、どの防御が効くかが表示される。

組み込みでは、PC より状況が悪い.

要因内容
MMU がないプロセス分離がない。1 つの脆弱性で全メモリが触れる
ASLR がないアドレスが固定なので、攻撃コードを書きやすい
スタックとヒープが近いオーバーフローが他の重要データを踏む
クラッシュが見えにくい「たまに再起動する」で片付けられる
W^X が徹底されていないRAM 上のデータを実行できてしまうことがある

代表的な攻撃対象

対象なぜ危険か
ネットワークスタック(TCP/IP)攻撃者が任意のパケットを送れる。認証前に処理される
BLE / Wi-Fi スタック同上。近接すれば誰でも送れる
パーサ全般(JSON、XML、Protobuf、画像、フォント)複雑な入力を扱う。バグが入りやすい
ブートローダの引数処理起動時に外部入力を受ける
USB スタック物理的に接続されるだけで動く

「認証前に処理されるコード」が最も危険である.

TLS ハンドシェイクの前、ペアリングの前、ログインの前に動くコードは、 誰からでも攻撃できる。ここに脆弱性があると、認証機構が意味をなさない。

この範囲のコードは、特に厳しくレビュー・テストすること。

2. 防御 — コンパイラとツールチェーン

まず、無料でできることを全部やる。

# GCC / Clang で必ず有効にすべきフラグ
-Wall -Wextra -Werror              # 警告を全部出し、エラーにする
-Wformat=2 -Wformat-security       # フォーマット文字列
-Wconversion -Wsign-conversion     # 暗黙の型変換(組み込みでは重要)
-Wshadow                           # 変数の隠蔽
-fstack-protector-strong           # スタックカナリア
-D_FORTIFY_SOURCE=2                # 標準関数の境界チェック(最適化と併用)
-fstack-usage                      # スタック使用量の静的解析
-fno-common                        # 暫定定義を禁止

# リンカ
-Wl,--gc-sections                  # 未使用コードの除去(攻撃面の削減)
機能効果組み込みでの注意
スタックカナリアスタックオーバーフローを検出わずかな性能低下。乱数が要る(08 章)
_FORTIFY_SOURCEmemcpy 等の境界チェックサイズが静的に分かる場合のみ有効
W^X(書き込みと実行の排他)RAM 上のデータを実行させないMPU で設定する(07 章)
ASLRアドレスをランダム化組み込みでは実質不可能なことが多い
CFI(制御フロー完全性)不正なジャンプを検出Armv8.1-M の BTI、PACBTI

Armv8.1-M の PACBTI

Cortex-M85 / M55(一部)などが対応する、ハードウェアによる制御フロー保護。

機能内容
PAC (Pointer Authentication)戻りアドレスに署名(認証コード)を付ける。改ざんすると検出される
BTI (Branch Target Identification)間接分岐の飛び先が正当な landing pad かを検証する

ROP(Return-Oriented Programming)攻撃への直接的な対策である.

ROP は「既存のコード断片を戻りアドレスの改ざんで繋いで、 任意の処理を実行する」攻撃で、W^X を回避できる。

PAC があると、戻りアドレスを書き換えても署名が合わないので検出される。 これは組み込みにとって大きな進歩である。

Cortex-A では Armv8.3-A から PAC、Armv8.5-A から BTI と MTE (Memory Tagging Extension、メモリ安全性のハードウェア支援)が使える。

3. 防御 — 言語とライブラリ

メモリ安全な言語

言語組み込みでの状況
Rust急速に普及中。no_std で組み込み可。Zephyr・embassy・RTIC などのエコシステム
Ada / SPARK航空宇宙・鉄道で実績。形式検証ができる
C++ (modern)スマートポインタ・std::span などで安全性を上げられるが、C 互換部分が残る
MicroPython / Lua上位ロジック向け。実行環境自体は C

Rust は「一部だけ置き換える」ことができる.

全部を書き直す必要はない。 最も危険な部分——パーサ、プロトコル処理——だけを Rust で書き、 C から呼ぶという段階的な移行ができる。

米国の CISA・NSA も「メモリ安全な言語への移行」を推奨する文書を出している。 新規開発では、少なくとも検討する価値がある。

コーディング規約

規約用途
MISRA C自動車・産業。安全性重視。静的解析ツールが対応
CERT Cセキュリティ重視。CWE との対応が明確
AUTOSAR C++14自動車の C++
BARR-C組み込み C の実務的な規約

MISRA C を「全部守る」のは現実的でないことが多い.

だが、セキュリティに直結する規則だけを選んで適用するのは有効である。

CERT C のほうが、セキュリティ目的には直接的である。

4. テスト

手法内容効果
静的解析 (SAST)ソースを解析してバグを見つける網羅的。誤検出も多い
動的解析 (Sanitizer)実行時に検出(ASan / UBSan / MSan)強力。ホスト上でのテストに
ファジングランダム/変異させた入力を大量に投げるプロトコル実装に極めて有効
ペネトレーションテスト実機に対する攻撃実際の脆弱性が見つかる
形式検証数学的に性質を証明する高コストだが確実

ファジングは組み込みでも有効

  1. プロトコル処理の関数を、ホスト(PC)でビルドできるように切り出す
  2. AFL++ / libFuzzer のハーネスを書く
  3. ASan / UBSan と組み合わせてビルドする
  4. 数時間〜数日走らせる
  5. クラッシュした入力を最小化して、バグを特定する
/* libFuzzer のハーネスの例 */
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
    parse_protocol_packet(data, size);   /* 実機と同じコードを呼ぶ */
    return 0;
}

「実機でしか動かない」を理由にテストを諦めないこと.

プロトコル解析、パケット処理、設定ファイルの読み込み—— これらはハードウェアに依存しないことが多い。

HAL をモックに差し替えれば、ホスト上でファジングできる。 ホストなら 1 秒に数千〜数万回実行できるので、実機の比ではない効率で見つかる。

CI に組み込むこと。 コミットのたびに数分走らせるだけでも効果がある。

5. SBOM — ソフトウェア部品表

CRA が明示的に要求する項目である。

SBOM とは、 「この製品には、どのソフトウェア部品が、どのバージョンで入っているか」の一覧である。

形式特徴
SPDX (ISO/IEC 5962)Linux Foundation。ライセンス管理から発展
CycloneDXOWASP。セキュリティ用途に強い。脆弱性情報と組み合わせやすい
SWID タグISO/IEC 19770-2

なぜ必要か

SBOM があるかないかで、事故のときの速度が変わるSBOM がない「Log4j に重大な脆弱性が見つかった」↓「うちの製品に入っているか?」↓★ 調べるのに数週間かかる。調べきれないSBOM がある同じ知らせを受け取る↓SBOM を検索する↓★ 該当製品が数分で分かり、対応を開始できる
SBOM は平時には役に立たない。価値が出るのは事故が起きた日で、そのときに作り始めても間に合わない

組み込みで実際に入っているもの:

部品例
RTOSFreeRTOS、Zephyr、ThreadX、RT-Thread
TCP/IP スタックlwIP、uIP、FreeRTOS+TCP、ベンダ独自
TLS ライブラリMbed TLS、wolfSSL
ファイルシステムLittleFS、FatFs、SPIFFS
BLE / Wi-Fi スタックベンダ提供(中身が見えないことがある)
ブートローダMCUboot
ユーティリティzlib、cJSON、Protobuf-c
標準ライブラリnewlib、picolibc

BLE / Wi-Fi スタックが最大の盲点である.

ベンダ提供のバイナリブロブになっていて、中身が分からないことがある。 だが過去に複数のチップベンダの BLE スタックで、 リモートコード実行を含む脆弱性が公表されている。

選定時に「ベンダの脆弱性開示ポリシーと、更新の提供期間」を確認すること。 これは 23 章の選定基準に含めるべき項目である。

SBOM の生成

方法内容
ビルドシステムから生成CMake / West / Yocto などが対応しつつある
バイナリ解析binwalk、cve-bin-tool などで既存バイナリから推定
手動小規模なら現実的。だが維持が困難

Yocto / Buildroot ベースの Linux 組み込みでは、 ビルド時に SPDX を出力する機能が整備されている。

6. 脆弱性の追跡

SBOM を作っただけでは意味がない。継続的に照合する必要がある。

脆弱性管理の運用ループSBOM(部品と版の一覧)脆弱性データベースNVD・OSV・ベンダのアドバイザリ影響評価本当に自社製品に影響するか修正版の作成 → テスト → OTA 配信(13 章)顧客への通知、当局への報告CRA では 24 時間以内の早期警告更新
これは製品を出したあと 10 年間まわし続ける仕組み。人と手順を決めておかないと、必ず止まる
情報源内容
NVD (NIST National Vulnerability Database)CVE の中央データベース
OSV (Open Source Vulnerabilities)Google 主導。機械可読で使いやすい
GitHub Security AdvisoriesOSS の脆弱性
ベンダのセキュリティアドバイザリチップベンダのものを必ず購読する
ICS-CERT / JPCERT産業制御系
ツール内容
cve-bin-toolバイナリから使用部品を推定して CVE と照合
Dependency-TrackSBOM を登録して継続的に監視する(OWASP)
Trivy / Grypeコンテナ・ファイルシステムのスキャン

「影響評価」の工程が実務では最も重い.

CVE が出ても、自社製品では該当機能を使っていないことが多い。 全部に対応していたら、リソースが持たない。

VEX(Vulnerability Exploitability eXchange)という仕組みがある。 「この CVE は、当製品では影響しない(該当コードを呼んでいない、等)」 を機械可読な形で表明するものである。

CycloneDX や CSAF が VEX に対応している。 CRA 対応では、この「影響しない理由の記録」が重要になる。

7. 脆弱性開示ポリシー

PSTI・CRA・EN 303 645 すべてが要求する。

要素内容
窓口security@example.com、または Web フォーム。見つけやすい場所に
security.txtRFC 9116。/.well-known/security.txt に連絡先を置く
応答時間の約束「3 営業日以内に受領確認」など
開示の方針「修正後 90 日で公開」など
報告者への対応法的措置を取らないことの明示(セーフハーバー)
謝辞報告者のクレジット。バグバウンティ(任意)

「報告しても無視される」「訴えられる」と思われたら、 研究者は報告せずに公開するか、闇市場に流す.

報告しやすい窓口を作ることは、それ自体がセキュリティ対策である。

ISO/IEC 29147(脆弱性開示)と ISO/IEC 30111(脆弱性処理プロセス)が 参考になる。CRA の要求もこれらと整合している。

8. セキュア開発ライフサイクル(SDL)

段階やること章
要件セキュリティ目標、脅威モデリング02
設計アーキテクチャレビュー、信頼境界の確認02, 07
実装安全なコーディング規約、コードレビュー本章
検証静的解析、ファジング、ペネトレーションテスト本章
リリース最終レビュー、SBOM 作成、鍵の管理本章, 12
運用脆弱性監視、更新の配信本章, 13
廃止EOL の通知、最終更新14

標準:

標準内容
IEC 62443-4-1産業用製品のセキュア開発ライフサイクル
ISO/SAE 21434自動車のサイバーセキュリティエンジニアリング
NIST SSDF (SP 800-218)セキュアソフトウェア開発フレームワーク
BSIMM / OWASP SAMM成熟度モデル

CRA 対応の実質は、SDL の導入である.

CRA が要求するのは、個々の技術的機能というより、 「そういうプロセスが回っていること」とその文書化である。

IEC 62443-4-1 の認証を取っておくと、CRA 対応の大部分が済むという関係にある (03 章)。

9. この章のまとめ

ポイント内容
なぜ必要かセキュアブートは脆弱なファームウェアを止めない。CRA の法的要件でもある
組み込みの不利MMU なし・ASLR なし・W^X が甘い・クラッシュが見えにくい
最も危険な箇所認証前に処理されるコード(TCP/IP、BLE、TLS ハンドシェイク、USB)
無料でできること警告を全部有効化、スタックカナリア、_FORTIFY_SOURCE、未使用コード除去
ハードウェア支援Armv8.1-M の PACBTI(ROP 対策)、Cortex-A の PAC/BTI/MTE
言語Rust を危険な部分だけに導入する段階的移行が現実的
テストファジングをホスト上で回す。CI に組み込む
SBOMCRA の要求。BLE/Wi-Fi スタックが最大の盲点
脆弱性追跡SBOM × 脆弱性 DB を毎日照合。VEX で「影響しない」を記録
開示ポリシーsecurity.txt、応答の約束、セーフハーバー。報告しやすさ自体が対策
CRA の実質SDL の導入と文書化。IEC 62443-4-1 が近道

次章では、第 V 部の残り——通信のセキュリティを扱う。