とにかく方法だけ知りたい人 → ## 偽装を防ぐために
とにかく時間がない人 → ## まとめ
はじめに
日々作られる,あなたの Git コミット.
それは果たして,本当にあなたが作ったものでしょうか ?
当たり前だ,と思われるかもしれませんが,それを 証明するのは難しい です.
今回は,実際にコミット作成者を偽装する方法と,その対策として有効な PGP 署名付きコミットの作り方を紹介します.
偽装してみよう
まずは Git リポジトリがないと何も始まらないので,初期化しておきます.
$ git init
$ git commit --allow-empty -m "Initial commit"
今作ったコミットを確認してみます.
Author と Committer を別々に表示させるため, --format=full
を付けておきます.
$ git show HEAD --format=full
commit d8231e29def93f3c325661fe39929ae069a1721e (HEAD -> master)
Author: Naoki Ikeguchi <root@siketyan.dev>
Commit: Naoki Ikeguchi <root@siketyan.dev>
Initial commit
さて,皆さんは覚えているでしょうか.
Git を使えるようにしたときに,以下のようなコマンドを実行したことを.
$ git config --global user.name "Your Name"
$ git config --global user.email "name@example.com"
ここで設定した user.name
と user.email
が Author と Committer に設定されています.
(ちなみにこの設定の実体は ~/.gitconfig
にあります.)
Author の偽装
まずはこの二つのうち Author を偽装してみましょう.
(ここで使用する名前とメールアドレスは架空のものです.実在の人物とは関係ありません.)
$ git commit --allow-empty --amend --author="Shinzo Abe <s-abe@cao.go.jp>"
先程と同様に確認します.
$ git show HEAD --format=full
commit 7905a6b067821d5dc4f31883af015f98f1f801be (HEAD -> master)
Author: Shinzo Abe <s-abe@cao.go.jp>
Commit: Naoki Ikeguchi <root@siketyan.dev>
Initial commit
Author を偽装することができました ね.
しかし,これでは周りの人が偽装に気づくことはとても簡単です.
GitHub 上では あなたの名前も表示されてしまう からです.
Committer の偽装
では,周りの人にバレないようにするために, Committer も偽装してしまいましょう.
こちらは,先程のようにコミット時のコマンドでは行えないため,一時的に Git の設定を変更します.
$ git config --local user.name "Shinzo Abe"
$ git config --local user.email "s-abe@cao.go.jp"
同様にコミットして確認します.
$ git commit --allow-empty --amend
$ git show HEAD --format=full
commit 74079831eaa4f6a1163b14d1e9ca5c176cf4020d (HEAD -> master)
Author: Shinzo Abe <s-abe@cao.go.jp>
Commit: Shinzo Abe <s-abe@cao.go.jp>
Initial commit
Committer まで偽装できました !
GitHub でも確認してみましょう.
このように,完全に偽装をすることができてしまいました.
既存の GitHub ユーザへの偽装
ここで一つの疑問が生まれます.
「さすがに既存の GitHub ユーザへ偽装しても GitHub が弾いてくれるよな…?」
実際にやってみましょう.
まずは同様に偽装コミットを作ります.
今回は 学校の後輩 に名前を貸してもらいました,ありがとうございます.
$ git config --local user.name "Chahaaaaan"
$ git config --local user.email "chahaaaaan@gmail.com"
$ git commit --allow-empty --amend
$ git show --format=full
commit 8b59585af8dc1305350078934be0ab821e2dd4f9 (HEAD -> master)
Author: Chahaaaaan <chahaaaaan@gmail.com>
Commit: Chahaaaaan <chahaaaaan@gmail.com>
Initial commit
では, GitHub にプッシュしてみます.
$ git push -f # 既存のコミットを書き換えたので強制プッシュ
Enumerating objects: 2, done.
Counting objects: 100% (2/2), done.
Writing objects: 100% (2/2), 345 bytes | 345.00 KiB/s, done.
Total 2 (delta 0), reused 0 (delta 0)
To github.com:Siketyan/Repo.git
+ 7407983...8b59585 master -> master (forced update)
なんと 無事に偽装できてしまいました .
GitHub でも確認してみます.
私が作ったコミットにも関わらず, あたかも当人が作ったかのように 偽装できてしまいました.
何が問題なの?
GitHub 上でアクセス権限を正しく設定していれば知らない人はリポジトリに書き込めません.
しかし,前章で実践したようにアクセス権限を持つ他の人がしたコミットに偽装することができてしまいます.
新しいコミットなら強制プッシュする必要もありません.
このままでは, 同僚などになりすますことができてしまいます .
極めて重大な問題ではありませんが,責任を問われるような重大なコードミスが見つかったときに,
その変更が偽装コミットによるものだったら…
など,様々な影響が考えられるでしょう.
偽装を防ぐために
長くなりましたが,いよいよ本題です.
PGP 署名を使って本人であることを主張していきましょう.
PGP (OpenPGP) とは?
Pretty Good Privacy の略で,電子メールなどに使われるデジタル署名のプロトコルです.
OpenPGP はそれをオープンに規格化したもので, RFC 4880 などで標準化されています.
署名する人は秘密鍵と公開鍵(証明書)のペアを持ちます.
秘密鍵を使ってメッセージに署名し,受け取った人は署名した人の公開鍵で署名を検証します.
この説明は間違っているかもしれないので, IPA による解説 を参考にどうぞ.
OpenPGP は規格に過ぎないので,それに沿えば自由に実装することができます.
GNU による実装が GnuPG (GPG) です.
これが有名なので GPG 署名と呼ばれることも多いです.
ステープラのことをホッチキスと呼ぶ人がいるのと同じ です.
PGP 鍵の生成
この記事では先述した GnuPG を用います.
(Windows 環境なので GPG4Win を使っていますがコマンド等は同じだと思います.)
$ gpg --generate-key
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Note: Use "gpg --full-generate-key" for a full featured key generation dialog.
GnuPG needs to construct a user ID to identify your key.
Real name: Naoki Ikeguchi
Email address: root@siketyan.dev
You selected this USER-ID:
"Naoki Ikeguchi <root@siketyan.dev>"
Change (N)ame, (E)mail, or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key D88ED59EBA88F15B marked as ultimately trusted
gpg: directory 'C:/Users/Siketyan/AppData/Roaming/gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as 'C:/Users/Siketyan/AppData/Roaming/gnupg/openpgp-revocs.d\C6E58267D8785108F1408B4BD88ED59EBA88F15B.rev'
public and secret key created and signed.
pub rsa2048 2020-04-17 [SC] [expires: 2022-04-17]
C6E58267D8785108F1408B4BD88ED59EBA88F15B
uid Naoki Ikeguchi <root@siketyan.dev>
sub rsa2048 2020-04-17 [E] [expires: 2022-04-17]
Windows では途中で以下のようにプロンプトが出るのでパスフレーズ(空白も可)を決めます.
PGP 鍵は自分のアイデンティティなので 大切に保管しておきましょう .
$ gpg --export-secret-keys C6E58267D8785108F1408B4BD88ED59EBA88F15B > privkey.gpg
Git で PGP を使うには
という見出しにしましたが Git で使えるのは GnuPG のみみたいです.
必要な設定は以下の 3 つです.
- GnuPG のパス
- 署名に使う鍵の ID
- コミット時に既定で署名する(任意)
まずは GnuPG のパスを設定します.
お使いの環境に合わせて設定しましょう.
which
/ where
コマンドを使うと絶対パスがわかります.
$ git config --global gpg.program "/usr/bin/gpg"
PS> git config --global gpg.program "C:/Program Files (x86)/GnuPG/bin/gpg.exe"
残り二つの設定は OS 非依存です.
$ git config --global user.signingkey "C6E58267D8785108F1408B4BD88ED59EBA88F15B"
$ git config --global commit.gpgsign true
実際に署名付きコミットをしてみよう
ここまで設定すればあとは簡単で,コミット時に -S
を付けるだけです.
(commit.gpgsign
を true
にしておけば不要です!)
$ git commit --allow-empty -S -m "Signed commit"
$ git push
Unverified と表示されてしまっています.
これは GitHub に 公開鍵を登録していないから です.
本人ではない署名で偽装コミットを作ろうとしたときも,このように表示されます.
GitHub へ公開鍵を登録しよう
GitHub へ登録するために,公開鍵をエクスポートします.
$ gpg --armor --export C6E58267D8785108F1408B4BD88ED59EBA88F15B > pubkey.gpg
SSH and GPG keys を開き, New GPG Key をクリックします.
先程エクスポートした pubkey.gpg の中身を Key に貼り付け, Add GPG Key をクリックします.
再認証を求められる場合があります.
(重要な操作を行う場合によくあります.)
Email address と Key ID が登録したものに一致していることを確認しましょう.
ちなみに GPG 鍵のメールアドレスは GitHub にも登録されている必要があります.
Email settings を確認しておきましょう.
すると,先ほどのコミットが Verified になっているはずです.
これであなたのコミットであることが証明できました!
偽装コミットでないことを確認するしくみ
PGP についての項で述べたとおり,署名したコミットを受け取る GitHub では,
登録した公開鍵を使って本人によるコミットであることを検証できます.
もしその検証に失敗すれば先ほどのように Unverified と表示されるため, 偽装の疑いを持つことができます .
偽装を防ぐためにもう一つ重要なこと
複数人がコミットしていくリポジトリで偽装を防ぐためには, 全員にこの準備を行ってもらうことが大切 です.
また, 署名のない / 署名が不正なコミットは信頼できない ので, Branch protection rules で禁止しておくといいでしょう.
まとめ
- Git のコミットは Author / Committer ともに 偽装ができてしまう
- 署名をしておくと 本人によるコミットであることを確認 できる
- GitHub には 公開鍵を登録 しておこう
- 署名付きでないコミットを弾くための ブランチ保護ルールを忘れずに !