テック技報最新号へ →
コード

Go: JSON を r.Body から直接デコードする前に http.MaxBytesReader で上限を付ける

json.NewDecoder(r.Body).Decode(&v) はクライアントが送ってきた分だけ読もうとする。先に r.Body = http.MaxBytesReader(w, r.Body, 1<<20) で上限をかけ、超えたら 413 を返す。

@amitsinha__07 · 投稿 2026-10-22
#go#http#security#json

何が困るか

net/http のサーバーはリクエストボディのサイズを既定では制限しない。巨大なボディを送られると、デコード中にメモリを食い続ける(悪意がなくても、誤ったアップロードで起きる)。

書き方

go
func handler(w http.ResponseWriter, r *http.Request) {
    r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MiB

    var in Input
    if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
        var mbe *http.MaxBytesError
        if errors.As(err, &mbe) {
            http.Error(w, "request body too large", http.StatusRequestEntityTooLarge) // 413
            return
        }
        http.Error(w, "bad request", http.StatusBadRequest)
        return
    }
    // ...
}
  • 上限を超えて読もうとすると *http.MaxBytesError が返る(Go 1.19 以降)。errors.As で見分けて 413 にできる。
  • MaxBytesReader は上限超過時にサーバーへ「この接続は閉じてよい」と伝えるので、残りのボディを読み続けずに済む。

注意点

  • 全ハンドラに付けるならミドルウェアにまとめる。ファイルアップロードなど大きいボディを受けるルートだけ別の上限にする。
  • リバースプロキシ(nginx の client_max_body_size など)にも上限があれば二重で守れるが、アプリ側の上限は残しておく。

出典

X の元の投稿を開く