あぼぼーぼ・ぼーぼぼ

のんびり生きたい

Go 1.19.2 and 1.18.7 security fix の内容を読んだ

https://groups.google.com/g/golang-announce/c/xtuG5faxtaU

3つの security fix が含まれている。

  • archive/tar : ヘッダー読み込み時のメモリ消費量に制限をかけた
  • net/http/httputil : ReverseProxy でパース不可能なクエリパラメータを転送しないようにした
  • regexp/syntax : 正規表現をパースする際のメモリ使用量の制限をかけた

archive/tar : ヘッダー読み込み時のメモリ消費量に制限をかけた

Issue https://github.com/golang/go/issues/54853

Reader.Read はファイルヘッダの最大サイズに制限を設けていなかった。悪意をもって作られたアーカイブは Read に無制限のメモリを割り当て、リソースの枯渇やパニックを引き起こす可能性があった。

Reader.Read はヘッダーブロックの最大サイズを 1MiB に制限するようになった。1MiB は libarchive の仕様に合わせている

コードを見ると、1MiB を maxSpecialFileSize = 1 << 20 と定義している。 << は Arithmetic operators (算術演算子) の中の left shift と呼ばれる。左シフトは、左辺の値を右辺の値だけ左へシフトする(例 0001 => 0010)。MiB はメビ・バイトという単位。コンピューターの容量や記憶装置の大きさを表す単位のひとつとして利用される。。MB(メガバイト)は10の6乗バイト(1MB = 100万B)となるが、1MiB は2の20乗バイト(1MiB = 104万8576B)となる。

net/http/httputil : ReverseProxy でパース不可能なクエリパラメータを転送しないようにした

issue https://github.com/golang/go/issues/54663

ReverseProxy でリクエストを転送するときに、パースできないクエリパラメータも含まれていた。クエリパラメータの密輸が可能ということが脆弱性なのかセキュリティ強化策なのかは微妙なところだが、CVE を割り当て脆弱性として扱うことにした。

下位互換性を保ちつつ修正する方法として、条件付きでパースできないクエリパラメータを削除するようにした。

regexp/syntax : 正規表現をパースする際のメモリ使用量の制限をかけた

issue https://github.com/golang/go/issues/55949

解析される各正規表現は 256MB のメモリフットプリントに制限されるようになり、ネストが深い正規表現などそれ以上の容量を必要とする正規表現が拒否されるようになった。

この修正ではサイズが大きすぎる正規表現に対して syntax.ErrInternalError を返すようにしたが、Go 1.20 でこのエラーを変えるプロポーザルが出されていた。すでに Go 1.19 ではこのケースに利用できそうな syntax.ErrNestingEpth が追加されている。

http.NewRequestがerrorを返すパターン

以下のPRをマージする過程で調べる必要があったのでメモしておく。

github.com

結論http.NewRequestがerrorを返すパターンは、HTTPメソッドが不正な場合と、URLのパースに失敗した場合の2パターンある。

http.NewRequestはgodocにもあるとおりhttp.NewRequestWithContextcontext.Backgroundを指定して呼び出すラッパーになっている。

// NewRequest wraps NewRequestWithContext using context.Background.
func NewRequest(method, url string, body io.Reader) (*Request, error) {
    return NewRequestWithContext(context.Background(), method, url, body)
}

https://github.com/golang/go/blob/master/src/net/http/request.go#L835-L838

NewRequestWithContextがerrorを返すパターンは、validMethodでHTTPメソッドが不正な値だった場合と、contextがnilだった場合と、urlpkg.ParseでURLのパースに失敗した場合の3パターンある。このうち、contextがnilであるパターンはhttp.NewRequestでは起こらないので、残りの2パターンとなる。

func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error) {
    if method == "" {
        // We document that "" means "GET" for Request.Method, and people have
        // relied on that from NewRequest, so keep that working.
        // We still enforce validMethod for non-empty methods.
        method = "GET"
    }
    if !validMethod(method) {
        return nil, fmt.Errorf("net/http: invalid method %q", method)
    }
    if ctx == nil {
        return nil, errors.New("net/http: nil Context")
    }
    u, err := urlpkg.Parse(url)
    if err != nil {
        return nil, err
    }
// 省略

https://github.com/golang/go/blob/f64f12f0b32eba7d49c259480e0fa0c79eb47600/src/net/http/request.go#L862-L878

今回google/go-githubに出したPRで追加したメソッドは、内部でhttp.NewRequestにPOSTを指定しているためHTTPメソッドが不正にはならないし、http.NewRequest以前の処理でベースとなるGitHub APIのURLと結合させる処理の中でURLパースをしているため、errorを返すケースは存在しないと思うが、テストカバレッジ上はカバーされていないためどうしようか?となった。起こり得なさそうとはいえ、プロダクションコードでブランク識別子でerrorを握りつぶすのは悩ましいし、errcheckのような静的解析ツールを使っている場合警告が出る。今回は、テストケースとしてはカバーしないことになったが、設計に改善の余地があるのだと思う。

『詳解Go言語Webアプリケーション開発』を読んだ

本の約半分がハンズオン形式になっていて、実際にWeb APIを開発しながら必要となる知識をインストールできる本でした。ハンズオンで作るWeb APIはBeyond the Twelve-Factor Appに準拠した形で、お題もMySQLを使ったデータ永続化、RedisとJWTを使った認証・認可といった機能を持つTODOアプリのREST APIなので、昨今のWeb開発において実用的なお題で良かったです。

ハンズオンじゃない各セクションは簡潔に短くまとまっていて、「なぜ?」に答える詳細な説明はGoの公式サイトなど外部のリンクが紹介されているので、わりとサクサク読めます。

ハンズオンは、チーム開発するうえでも役立つことが書いてあるなと思いました。例えば https://github.com/cosmtrek/air を使ってホットリロードできる構成にしたり、Makefileを用意したり、GitHub Actionsでテストや静的解析をCIしたり。ホットリロードについてはテストコードによるフィードバックサイクルとの比較から実務においては必須というわけでもない、みたいな解説がされていて結構信頼できました。ハンズオン中心の構成にするにあたっての落としどころだったのかなと想像します。

ただハンズオン部分は、結構解説が飛んでいるところも散見されました。手を動かしながら読むので気付きやすいのかもしれません。例えばディレクトリ構造とファイル名が明示されていない場合「今どのパッケージ(ディクレトリ)のどのファイル触っているんだ...?」となったり、新しいパッケージのgo getが無かったり、あとは単純に誤植というかコードがコンパイルできなかったりといった感じです。この辺りは、著者がGitHubでサンプルコード(https://github.com/budougumi0617/go_todo_app)を公開しているのでそれと照らし合わせながら読むのがいいです。正誤表もあるみたいです。

パフォーマンスチューニングや可観測性のためのロギングといった、運用していくうえで必要性が高まる領域についてはカバーしていないので、もし本書から入門した場合は『実用Go言語』や、最近発売された『Go言語による分散サービス』(まだ読んでない)などを次に読んでいくと良さそうです。

ハンズオン楽しかったです!

詳解Go言語Webアプリケーション開発 | 清水陽一郎 | 工学 | Kindleストア | Amazon

『達人が教えるWebパフォーマンスチューニング』を読んだ

明日ISUCON予選なので読みました(白目

https://github.com/catatsuy/private-isuを題材に実際にチューニングをしながら理解できる構成になっています。実際のISUCONではベンチマーカーはクリックひとつで実行するだけだと思いますが、本書ではベンチマーカーのApache Benchを使う方の説明があったり、ベンチマーカーの実装についての付録があったりします。

サンプルコードが Go で書かれているのでぼくにとっては読みやすかったです。

ISUCON、ボトルネックのみ解決するという鉄則を守りたい...けど何もできないで終わるよりは出来ることを何かして終わりたいですね。

https://www.amazon.co.jp/dp/B0B1Z9ZMY6

『UNIXという考え方』を読んだ

名著なのは知ってましたが読めておらず、ようやく読めました。

スモール・イズ・ビューティフル、できるだけ早く試作をつくる、梃子を有効に活用する、一つのことをうまくやる、あたりの考え方がとくに刺さりました。そしてUNIXコマンドはすごく考えられてるなぁと。

自分で何かツールを作ったり、課題解決のためのプログラムを書いたりする際に今後めちゃくちゃ意識しそうです。

www.amazon.co.jp

NotionのページアイコンのURLをコピーするChrome拡張をつくった

chrome.google.com

自前でアップロードした画像を色々なページのアイコンに設定するのをラクにするChrome拡張です。

Notionではアップロードした画像をページアイコンに設定できます。その画像を他のページのアイコンにも設定したければ、ページ自体を複製するしかありません。なぜかというとNotionにアップロードした画像は、はてなブログの画像とか、Slackの絵文字のように簡単に取り出せないからです。

ページ自体を複製するとプロパティや本文も全て複製されるのが厄介です。あとすでにあるページのアイコンを変えるというケースには使えません。

このChrome拡張は、アップロードした画像が保存されているS3のURLをクリップボードにコピーします。ページアイコンにはURLを設定できるので、他のページのアイコンに簡単に設定できるようになります。

コードはGitHubに置いてあります。

github.com

Chrome拡張の初歩的な実装という感じですが強いて言えばTypeScript 100%になってて気持ちいいですね ( ˙σー˙ )

『リーダーの作法』を読んだ

https://www.amazon.co.jp/dp/4873119898:site

表紙の蜂 🐝 が毛並みも見えて結構リアルでした。

ぼくにとっては参考になったり魅力的に感じる章は限られていました。今の役割や興味が、この本で登場するマネージャー・ディレクター・エグゼクティブのどれにも当てはまらないですし。ただ「リーダーシップはそういった役割に限らず全員が発揮するものである」という考えは他のいくつもの本と同様にこの本でも共有されていました。

プロフェッショナルなリーダーとして私個人が果たすべき責任は、一刻一刻をできる限りの熱意と好奇心を持って前向きに取り組むことなのです。一見価値がないように見える状況に置かれたときでも、私は何らかの価値を見出すようにしています。価値は常にそこにあるからです。 p6 1章 誰からでも学ぶことがあると考える

何からでも学べると思うこと。

管理職に就くことは昇進ではない p46 9章 新任マネージャーのデス・スパイラル

別のページでキャリアラダー(はしご:上下に昇り降りするもの)ではなくキャリアパス(旅)である、と書かれていて、そうだよなぁと。

ほめ言葉とは、無欲で、うまく表現された、タイムリーな成果の承認のことです。 p82 14章 素敵なほめ言葉

改めて大事だと思いましたし、誰でも明日から意識して実践できることですね。