Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Getでのchecksum不一致に遭遇した話とその対応

natsumi
December 01, 2023

Go Getでのchecksum不一致に遭遇した話とその対応

Go Conference mini 2023 Winter IN KYOTOで発表したLTの資料

natsumi

December 01, 2023
Tweet

Other Decks in Technology

Transcript

  1. Go Getでのchecksum不一致
    に遭遇した話とその対応
    Go Conference mini 2023 Winter, DEC 02 2023
    Natsumi Kojima
    ANDPAD Inc.
    @replu5

    View full-size slide

  2. 小島 夏海
    ● 株式会社アンドパッド
    ○ 最近は社内向けの通知プラットフォームの開発・運用
    : replu
    : replu5
    自己紹介

    View full-size slide

  3. go getでのchecksum不一致

    View full-size slide

  4. go get コマンドでモジュールを取得する時にchecksumの
    不一致のエラーに遭遇したことある人いますか?
    遭遇したことがない人は下記コマンドで確認できます
    GOPROXY=direct go get github.com/replu/[email protected]

    View full-size slide

  5. 遭遇したエラーについて
    checksum server の checksum と一致してないのは
    わかるがここからどうすればいいのかわからなかった

    View full-size slide

  6. go get時にどういう動作をしているか
    モジュール配布元
    checksum server
    go get xxx
    1 : モジュールダウンロード
    2 : checksum ダウンロード
    3 : 計算したchecksum
    とダウンロードした
    checksumと比較
    4 : go.modとgo.sum更新

    View full-size slide

  7. go get時にどういう動作をしているか
    モジュール配布元
    checksum server
    go get xxx
    1 : モジュールダウンロード
    2 : checksum ダウンロード
    3 : 計算したchecksum
    とダウンロードした
    checksumと比較
    4 : go.modとgo.sum更新

    View full-size slide

  8. エラーの原因
    エラーメッセージに考えられる理由が2つ書かれている
    ● オリジンサーバが上書きされている
    (The bits may have been replaced on the origin server)
    ● ダウンロードが攻撃者に傍受された可能性がある
    (An attacker may have intercepted the download attempt)
    オリジンサーバが上書きされているかがわかればよさそう

    View full-size slide

  9. checksumを確認する
    オリジンサーバで上書きがあったならダウンロードして
    checksumを計算し、checksum serverのchecksumと比較した
    時に異なるはずなので、実際に比較してみる
    checksumは
    https://pkg.go.dev/golang.org/x/mod/sumdb/dirhash
    を使用することで計算可能

    View full-size slide

  10. fileのハッシュを求める
    open := func(fn string) (io.ReadCloser, error) { return os.Open(fn) }
    filePath := "go.mod"
    s, err := dirhash.Hash1([]string{filePath}, open)
    if err != nil { fmt.Println(err.Error()) }
    fmt.Println(s)
    https://go.dev/play/p/7aEARvckJjD

    View full-size slide

  11. directoryのハッシュを求める
    dir := "[email protected]"
    prefix := "github.com/replu/[email protected]"
    s, err := dirhash.HashDir(dir, prefix, dirhash.DefaultHash)
    if err != nil { fmt.Println(err.Error()) }
    fmt.Println(s)
    https://go.dev/play/p/UofHVjffeuy

    View full-size slide

  12. ツールを使ってchecksumを求める
    ツールを利用してもchecksumを確認できる
    https://github.com/vikyd/go-checksum
    ディレクトリのchecksumを求める例

    View full-size slide

  13. checksum serverのchecksumを取得する
    checksum serverに保存されているchecksumは
    $base/lookup/$module@version
    で取得でき、デフォルトのchecksum serverの場合
    $base = sum.golang.org

    View full-size slide

  14. checksumが一致しないことが確認できたら
    ● checksum serverのchecksumは更新できない
    ○ そのバージョンは利用しないようにする
    ■ GONOSUMDB を指定することで checksum の確認をしない
    ようにできるが、攻撃を受けた時に気付けないのでおすすめは
    しない
    ○ 開発者に連絡して、新バージョンをリリースしてもらう
    ■ そのライブラリを利用している他ライブラリが新バージョンを
    使っていないなら、そちらも更新してもらう必要がある
    自分の場合は新バージョンがでていたが、他ライブラリが
    新バージョンを使ってなかったので、そちらにissueを作成して連絡
    した

    View full-size slide

  15. どうして発生するのか

    View full-size slide

  16. go get時の動作(再喝)
    モジュール配布元
    checksum server
    go get xxx
    1 : モジュールダウンロード
    2 : checksum ダウンロード
    3 : 計算したchecksum
    とダウンロードした
    checksumと比較
    4 : go.modとgo.sum更新

    View full-size slide

  17. go get時の動作(再喝)
    モジュール配布元
    checksum server
    go get xxx
    1 : モジュールダウンロード
    2 : checksum ダウンロード
    3 : 計算したchecksum
    とダウンロードした
    checksumと比較
    4 : go.modとgo.sum更新
    この2つの仕様の違いが原因

    View full-size slide

  18. ダウンロード元とchecksum serverの指定
    ● GOPROXY
    ○ モジュールのダウンロード元を指定する
    ○ デフォルトだと proxy.golang.org,direct
    ■ directを指定した場合は直接アクセスになる
    ■ カンマ区切りまたはパイプ区切りで指定し、前のものから
    使用される
    ● GOSUBDB
    ○ checksum serverを指定する
    ■ デフォルトではsum.golang.org
    ○ offを指定した場合は検証を無効化できる

    View full-size slide

  19. proxy.golang.orgとsum.golang.org
    ● proxy.golang.org
    ○ 明示的にキャッシュを削除することはできない
    ■ 無限に保存されるわけではなく適切なライセンスを
    検出できない場合などは一定時間でキャッシュが削除される
    ● sum.golang.org
    ○ 一度記録されたら更新・削除されることはない
    sum.golang.orgに記録された後にオリジンサーバが上書き
    された場合、proxy.golang.orgのキャッシュが更新される
    or directでアクセスしているとchecksumが不一致になる

    View full-size slide

  20. まとめ
    ● checksum不一致のエラーに遭遇したらchecksumを確認
    して、オリジンサーバに上書きがあったのか確認する
    ○ 上書きがあった場合は新バージョンをリリースして
    もらう必要ある
    ● sum.golang.orgに記録された後で上書きすると問題が
    発生するので、一度公開した後は上書きしないように
    すべき
    ● checksumは
    https://pkg.go.dev/golang.org/x/mod/sumdb/dirhash
    を用いることで計算できる

    View full-size slide

  21. 参考文献
    ● Go Module Mirror, Index, and Checksum Database :
    https://sum.golang.org/
    ● Go Modules Reference : https://go.dev/ref/mod

    View full-size slide

  22. アクセス制限しているモジュールの場合
    ● GOPRIVATE環境変数を設定する
    ○ GOPRIVATEに設定されているモジュールの場合
    ■ モジュールプロキシは利用されず、直接アクセス
    (GOPROXY=direct相当)
    ■ checksumの確認は実施されない

    View full-size slide

  23. 環境変数に設定する値まとめ
    ● GOPRIVATE
    ○ プライベートモジュールのパスの接頭辞を指定
    ● GOPROXY
    ○ 公式のプロキシサーバを使いたくない理由がない限り
    デフォルトで問題なし
    ● GOSUMDB
    ○ 公式のchecksum serverを使いたくない理由がない限り
    デフォルト値で問題なし

    View full-size slide

  24. ご清聴ありがとうございました

    View full-size slide