トップ «前の日記(2018年07月27日) 最新 次の日記(2018年07月29日)» 編集

KeN's GNU/Linux Diary


2018年07月28日

_ [debian] secure apt、再掲

常時SSL化が普及する中、Chromeの新しいバージョンでhttpsでないと「保護されていない」と怒られることが多くなったそうで、そういえばftp.jp.debian.orgなどのDebianのミラーで「保護されていない」と出ると心配になる人が多そうだな、と思った。

Debianのミラーは商業CDNで配布されているわけではなく、有志のHTTP/FTPサーバで運用されている都合上、IPアドレスもサーバ設定もバラバラで、すべてをDebianプロジェクトのメンバーが直接管理しているわけでもない。そのため、「Let's Encrypt使えばいいじゃん」と簡単にはいかないし、おそらくTLSの仕組み的にもできないのではと思う。

そこで、どうDebianではパッケージの整合性を保護しているか、ということについて2006年に別の日記に書いていた古い記事を拾い出して書き直してみた。以下はJoey HessがDebian Wikiに記したSecureAPTを参考にしている。

まずは基本概念から。Debianミラーには大量のパッケージがあるが、悪意を持つ者によって改変されるのを防ぐ必要がある。信頼できる組織のミラーを使うというのも1つだが、Debianプロジェクトがすべてのミラーに目を光らせるというわけにもいかない。

Debianの各パッケージは、パッケージメンテナがビルドした時点で、そのメタ情報ファイルにパッケージ内のファイルのMD5ハッシュ値が記載される。MD5自体には同じ値で中身が異なる「コリジョン」が発見されている弱いアルゴリズムだが、メンテナが悪意を持っているのでもない限りはパッケージの範囲内でコリジョンが起こることはまずないので、ここでは特に問題にならない。

このメタ情報ファイルと展開したファイルを比較すれば、パッケージファイルの破損、あるいは何らかの不正加工は発見できる(パッケージインストール時にこれが行われる)。インストールしたときに/var/lib/dpkg/info/に「〜.md5sums」というファイルがあるはずだ。たとえばapt.md5sumsは以下のようになる。

 71b58009120db0e61412f7610f27e8db  lib/systemd/system/apt-daily-upgrade.service
 6f1973de70bf3594436cc1a68adc441b  lib/systemd/system/apt-daily-upgrade.timer
 563ce75e507e1f6cc3f413e285651af5  lib/systemd/system/apt-daily.service
 57b964b4d70e49baf77ca7c971358acf  lib/systemd/system/apt-daily.timer
 724928d79215b0e199085bbcc04ddb4d  usr/bin/apt
 ...

次に、Packagesファイルがある。これは、大雑把に言えば、各パッケージのメタ情報ファイル内の情報(パッケージ名など)とパッケージファイル(.deb)のハッシュ値を合わせ、一覧にしてローカル側のデータベースとして使えるようにしたものだ(ソース用はSources)。通常は圧縮されているが「dists/{RELEASE}/{main/contrib/non-free}/binary-{ARCH}/Packages」という単位で存在する。

Packagesファイルは基幹となるデータベースのため、ハッシュ値に脆弱なMD5だけでは甚だ心許ない。そこで、異なるアルゴリズムでのハッシュ値も記載されている(通常ミラー側はMD5とSHA256、security.debian.orgはMD5、SHA1、SHA256)。

 Package: apt
 Version: 1.4.8
 Installed-Size: 3539
  ...
 Size: 1231676
 MD5sum: 4963240f23156b2dda3affc9c0d416a3
 SHA256: bc319a3abaf98d76e7e13ac97ab0ee7c238a48e2d4ab85524be8b10cfd23d50d

apt-get updateを実行すると、このPackagesがローカルにダウンロードされ、APTデータベースによって参照されるようになる。このPackagesが「信頼できるならば」、その情報にある各パッケージのハッシュ値をもとにパッケージが「信頼できる」ことを証明できる。

次に登場するのがReleaseファイルだ。実はReleaseファイルには2種あり、dists/{RELEASE}/Releaseと、dists/{RELEASE}/{main/contrib/non-free}/binary-{ARCH}/Releaseがある。後者はそのアーカイブがstable/testing/unstableのうちどれかやリリースバージョンなどが書かれているだけだが、前者はこれ以外に配下にあるPackagesファイル(圧縮したものやSources/Releaseも含む)のハッシュ値(Packages同様に通常ミラーではMD5とSHA256、security.debian.orgではMD5、SHA1、SHA256)とサイズを記述している。だんだんややこしくなってきたが、このReleaseファイルが「信頼できるならば」、Packagesファイルを「信頼でき」、その中に書かれているパッケージも「信頼できる」ということになるわけだ。

 Origin: Debian
 Label: Debian
 Suite: stable
 Version: 9.4
 Codename: stretch
 Changelogs: http://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_change
 log
 Date: Sat, 10 Mar 2018 10:21:19 UTC
 Acquire-By-Hash: yes
 Architectures: amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x
 Components: main contrib non-free
 Description: Debian 9.4 Released 10 March 2018
 MD5Sum:
  00216699f7cd377bd5532d38c2c4a390  1181375 contrib/Contents-amd64
  ...
  4c8923dcd9d71154f8eb067edcd2ec25  7121632 main/binary-amd64/Packages.xz
  ...
 SHA256:
  ...
  987a992a471a92af2bcdff2447e7604203d8b8568289edd25c34adb0486140a6  7121632 main/binary-amd64/Packages.xz

ということで、ようやくテーマであるRelase.gpgにたどりついた。dists/{RELEASE}/Release.gpgファイルは、Debianの自動FTPマネージャのGnuPG(PGP鍵暗号方式の実装の1つ)の秘密鍵を使って、dists/{RELEASE}/Releaseファイルを電子署名した結果値だ。

このGnuPG秘密鍵は、DebianプロジェクトのFTP管理者によって作成されたもので、Debianプロジェクトの極めて限定的なアクセス環境(ごく一部の選ばれたDebianプロジェクトメンバーだけがアクセスできる)の下、純粋にRelaseファイル署名のためだけに使われている。この秘密鍵に対応するGnuPG公開鍵、Releaseファイル、Release.gpgファイルの3つが揃っていれば、Releaseファイルが改ざんの行われていない、正当にFTPマネージャに署名されたものであることを証明できる。署名時から1ビットでもReleaseファイルが加工されていれば、Release.gpgの署名に対して不整合となり、エラーになる。Release.gpgを加工したらGnuPG公開鍵での署名検証に失敗し、やはりエラーとなる。

さて、残るはGnuPG公開鍵の信頼性である。ここが一番難しいところで、これが破綻したらここまでに築いてきたものが全部ダメになってしまう。公開鍵は、ftp-master.debian.org(ここはhttpsだ!)のWebサイト、およびPGPサーバーで配布されている(Stretch向けはE0B11894F66AEC98)。Debianプロジェクトの(本当に信頼できる)FTP管理者に直に話して、鍵が本物かどうか聞くのがベストではあるけれども、それは難しいので、こちらにせいぜいできるのはそのGnuPG鍵に付けられているsign(「署名」と語が似てしまうけど「この鍵は確かにこの人のものですよ」ということを示すもの。対面で会う機会にキーサインパーティなどをやる目的はこれで、友人関係を表すものではない)を見て、DebianプロジェクトFTP管理者のものだからまぁOKだろう、という判断になるだろう。自分で試すならこんな感じ。

 $ gpg --keyserver pgp.mit.edu --recv-keys E0B11894F66AEC98 ←鍵をPGPサーバーから取り込み
 gpg: 鍵E0B11894F66AEC98: 公開鍵"Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>"をインポートしました
 gpg: marginals needed: 3  completes needed: 1  trust model: classic
 gpg: 注意: アルゴリズム MD5 を用いた署名は拒否されました
 gpg: 深さ: 0  有効性:   1  署名: 149  信用: 0-, 0q, 0n, 0m, 0f, 1u
 gpg: 深さ: 1  有効性: 149  署名: 530  信用: 149-, 0q, 0n, 0m, 0f, 0u
 gpg: 次回の信用データベース検査は、2019-03-08です
 gpg:           処理数の合計: 1
 gpg:             インポート: 1

 $ gpg --list-sigs E0B11894F66AEC98 ←signを見てみる
 elemental{kmuto}% gpg --list-sigs E0B11894F66AEC98
 pub   rsa4096 2017-05-22 [SC] [有効期限: 2025-05-20]
       E1CF20DDFFE4B89E802658F1E0B11894F66AEC98
 sig    R     E0B11894F66AEC98 2017-05-22  Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sig    R     E0B11894F66AEC98 2017-05-22  Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sig    R     E0B11894F66AEC98 2017-05-22  Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 uid           [  不明  ] Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sig          E7F6F29ECED41113 2018-06-08  [ユーザIDが見つかりません]
 sig          F14E580128030B19 2018-03-07  [ユーザIDが見つかりません]
 sig          11B4E5FF15B0FD82 2017-05-24  [ユーザIDが見つかりません]
 sig 3        7638D0442B90D010 2017-05-25  [ユーザIDが見つかりません]
 sig 3        9D6D8F6BC857C906 2017-05-25  [ユーザIDが見つかりません]
 sig          25ADF665CD2D5AEB 2017-08-05  [ユーザIDが見つかりません]
 sig          BB0E4759B633D17C 2018-02-18  [ユーザIDが見つかりません]
 sig          B0FBE415662EF139 2017-08-04  [ユーザIDが見つかりません]
 sig          E553E8B2DB568A08 2018-03-26  [ユーザIDが見つかりません]
 sig          BC372252CA1CF964 2017-05-23  [ユーザIDが見つかりません]
 sig 3        E0B11894F66AEC98 2017-05-22  Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sig     P    DB16CF5BB12525C4 2017-05-23  [ユーザIDが見つかりません]
 sub   rsa4096 2017-05-22 [S] [有効期限: 2025-05-20]
 sig          E0B11894F66AEC98 2017-05-22  Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>

 $ gpg --keyserver keyring.debian.org --recv-keys BC372252CA1CF964 ←署名者の鍵をDebianの鍵サーバ(Debianプロジェクトの人のみが登録)から1つ取ってきてみる
 pg: 鍵BC372252CA1CF964: 公開鍵"Ansgar Burchardt <ansgar@debian.org>"をインポートしました
 gpg: marginals needed: 3  completes needed: 1  trust model: classic
 gpg: 注意: アルゴリズム MD5 を用いた署名は拒否されました
 gpg: 深さ: 0  有効性:   1  署名: 149  信用: 0-, 0q, 0n, 0m, 0f, 1u
 gpg: 深さ: 1  有効性: 149  署名: 531  信用: 149-, 0q, 0n, 0m, 0f, 0u
 gpg: 次回の信用データベース検査は、2019-03-08です
 gpg:           処理数の合計: 1
 gpg:             インポート: 1

 $ gpg --list-sigs BC372252CA1CF964 ←FTPマスターの1人、Ansgarの鍵に署名している人を確認
 pub   rsa4096 2009-05-12 [SC] [有効期限: 2019-05-23]
       80E976F14A508A48E9CA3FE9BC372252CA1CF964
 uid           [ 未定義 ] Ansgar Burchardt <ansgar@debian.org>
 sig          DBBE9D4D99D2A004 2011-07-23  [ユーザIDが見つかりません]
  ...
 sig          3A936196C095D941 2011-07-27  Bdale Garbee <bdale@gag.com>
  ...
 sig 3        587979573442684E 2011-07-28  Steve McIntyre <steve@einval.com>
  ...
 sig          5D328D082AAAB140 2011-08-07  Hideki Yamane (private) <henrich@iijmio-mail.jp>
  ...
 sig          32247FBB40AD1FA6 2011-11-22  Nobuhiro Iwamatsu <iwamatsu@debian.org>
  ...
 sig          00B45EBD4CA7BABE 2015-09-04  NIIBE Yutaka <gniibe@fsij.org>
  ...
 (知っている人たちがちゃんと署名しているので信頼できそうだ!)

まとめると、FTP GnuPG公開鍵を信頼できる→Release.gpg署名を検証できる→Releaseファイルを信頼できる→Packages/Sourcesを信頼できる→Packagesのハッシュ値を信頼できる→パッケージを信頼できる→パッケージ内のファイルを信頼できる、となる。

secure APT

やれやれ。ともかく、APTでの各パッケージの正当性の検証はハッシュ値とGnuPG署名にある、ということだ。

なお、apt-getなどは内部でGnuPG鍵を管理している(/etc/apt/trusted.gpg、/etc/apt/trusted.gpg.d/)が、制御するフロントエンドがapt-keyだ。

 $ apt-key list
 /etc/apt/trusted.gpg
 --------------------
 /etc/apt/trusted.gpg.d/debian-archive-stretch-automatic.gpg
 -----------------------------------------------------------
 pub   rsa4096 2017-05-22 [SC] [有効期限: 2025-05-20]
       E1CF 20DD FFE4 B89E 8026  58F1 E0B1 1894 F66A EC98
 uid           [  不明  ] Debian Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sub   rsa4096 2017-05-22 [S] [有効期限: 2025-05-20]

 /etc/apt/trusted.gpg.d/debian-archive-stretch-security-automatic.gpg
 --------------------------------------------------------------------
 pub   rsa4096 2017-05-22 [SC] [有効期限: 2025-05-20]
       6ED6 F5CB 5FA6 FB2F 460A  E88E EDA0 D238 8AE2 2BA9
 uid           [  不明  ] Debian Security Archive Automatic Signing Key (9/stretch) <ftpmaster@debian.org>
 sub   rsa4096 2017-05-22 [S] [有効期限: 2025-05-20]

 /etc/apt/trusted.gpg.d/debian-archive-stretch-stable.gpg
 --------------------------------------------------------
 pub   rsa4096 2017-05-20 [SC] [有効期限: 2025-05-18]
       067E 3C45 6BAE 240A CEE8  8F6F EF0F 382A 1A7B 6500
 uid           [  不明  ] Debian Stable Release Key (9/stretch) <debian-release@lists.debian.org>

  ...

最後に、メンテナが新たなパッケージをDebianプロジェクトにアップロードするときにも、パッケージのビルド時にパッケージファイルのSHA1とSHA256のハッシュ値がアップロード用情報ファイルに記載される。これにメンテナのGnuPG鍵による署名を行ってからアップロードすれば、あとはDebianプロジェクトのサーバが署名およびハッシュ値の検証をして正当であれば取り込まれる。

これで完璧だ!と言いたいところだけれども、実際のところ問題がなくもない。

  • (悪意の有無はともかくとして)通信途中に監視者が存在する場合、どのパッケージをダウンロードした、という情報はわかってしまう。これを避けるには、ftp.jp.debian.orgといったTLS化できない抽象名ではなく、httpsを提供しているサーバを使う。たとえば「https://dennou-k.gfd-dennou.org/debian/」はいける模様。
  • Debian以外のサードパーティの鍵をapt-keyを使って登録している場合、サードパーティのリポジトリ経由でパッケージのハイジャックをされる可能性がある。たとえばサードパーティのリポジトリがクラックされて「apt」の悪意あるバージョンが配布される、という可能性はあり得る。APT pinを使えば防げなくはないけれども手間なので、信頼性に欠けるサードパーティのものはインストールを終えたらsources.listからコメントアウトしたほうがよいかもしれない。必要なパッケージのインストール時にapt-keyでの鍵登録はせず、そのときだけ「信頼しないけどインストールする」で済ませるという手もある(postinstで入れられたらどうしようもないけれども)。
  • オリジナルのソフトウェア、あるいはパッケージメンテナに悪意がある場合に防げない。これは配布の問題ではないので……。

_ [cooking] ごーやーちゃんぷるー