Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15613] ファイルの概要

このコミットは、Go言語の標準ライブラリである net/http パッケージにおけるUser-Agent文字列の変更に関するものです。具体的には、デフォルトのUser-Agent文字列が「Go http package」から「Go 1.1 package http」へと更新されました。この変更は、一部の侵入検知システム(IDS)が旧来のUser-Agent文字列を誤ってウイルスとして検知する問題に対処するために行われました。

コミット

commit 48c1db4003a3d002b8eada06b8b4c451b7d8d40f
Author: Russ Cox <rsc@golang.org>
Date:   Wed Mar 6 16:48:20 2013 -0500

    net/http: change user agent string
    
    Some IDS somewhere thinks "Go http package" is a virus.
    Make it something else for Go 1.1. Dumb but easy.
    
    R=golang-dev, bradfitz, minux.ma
    CC=golang-dev
    https://golang.org/cl/7532043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/48c1db4003a3d002b8eada06b8b4c451b7d8d40f

元コミット内容

net/http パッケージのUser-Agent文字列を変更します。

どこかのIDS(侵入検知システム)が「Go http package」をウイルスだと考えているようです。 Go 1.1向けに、これを別のものに変更します。馬鹿げた話ですが、簡単な解決策です。

変更の背景

この変更の背景には、Go言語の net/http パッケージがHTTPリクエストを送信する際にデフォルトで付与するUser-Agentヘッダの値が、一部のネットワークセキュリティ製品(特に侵入検知システム、IDS)によって誤って悪意のあるトラフィックとしてフラグ付けされるという問題がありました。

当時のGo 1.0の net/http パッケージは、デフォルトのUser-Agent文字列として「Go http package」を使用していました。この文字列が、特定のIDSのシグネチャと偶然一致してしまい、Goアプリケーションからの正当なHTTPリクエストがブロックされたり、セキュリティアラートを発生させたりする事態が発生していました。これは、Go言語で開発されたアプリケーションが外部のHTTPサービスと通信する際に、予期せぬ接続障害や運用上の問題を引き起こす可能性がありました。

開発チームは、この問題を解決するために、User-Agent文字列を変更するという実用的なアプローチを選択しました。これは、IDSのシグネチャが特定の文字列に依存している場合、その文字列を変更するだけで問題を回避できるという、比較的単純かつ効果的な方法でした。Go 1.1のリリースを控えていた時期であったため、この変更はGo 1.1の一部として導入されることになりました。コミットメッセージにある「Dumb but easy.(馬鹿げた話だが簡単だ)」という表現は、この問題が技術的な脆弱性ではなく、単なる文字列の誤認識によるものであり、その解決策も単純な文字列変更で済むという状況を端的に示しています。

前提知識の解説

User-Agentヘッダ

User-Agentヘッダは、HTTPリクエストのヘッダの一つで、クライアント(ウェブブラウザ、アプリケーション、ボットなど)が自身を識別するために使用されます。サーバーは、この情報に基づいて、コンテンツの最適化(例:モバイル向け表示)、統計情報の収集、特定のクライアントへの対応(例:バグのあるブラウザへの回避策)などを行います。

一般的なUser-Agentの例:

  • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 (Chromeブラウザ)
  • curl/7.64.1 (cURLコマンドラインツール)

Goの net/http パッケージは、HTTPクライアント機能を提供し、デフォルトでこのUser-Agentヘッダを自動的に付与します。

侵入検知システム (IDS)

侵入検知システム(Intrusion Detection System, IDS)は、ネットワークやシステムへの不正アクセス、悪意のある活動、ポリシー違反などを監視し、検知するセキュリティシステムです。IDSは、既知の攻撃パターン(シグネチャ)や異常な振る舞いを分析することで、脅威を特定します。

IDSの主な機能:

  1. シグネチャベースの検知: 既知の攻撃パターン(シグネチャ)とトラフィックを照合します。例えば、特定のマルウェアが使用する通信パターンや、脆弱性を悪用する特定の文字列などを検知します。
  2. 異常ベースの検知: 通常のネットワーク活動のベースラインを学習し、そこから逸脱する異常な振る舞いを検知します。
  3. アラートとロギング: 脅威を検知した場合、管理者にアラートを送信し、詳細なログを記録します。

このコミットの背景にある問題は、IDSが「Go http package」という文字列を、何らかの既知の悪意のある活動のシグネチャと誤って関連付けてしまったことに起因します。これは、IDSのシグネチャが過度に厳密であったり、あるいは偶然の一致であったりする可能性があります。

Go 1.1

Go 1.1は、Go言語の重要なマイルストーンとなるリリースの一つです。2013年5月にリリースされ、パフォーマンスの向上、標準ライブラリの改善、ツールチェインの強化など、多くの新機能と改善が含まれていました。このコミットは、Go 1.1のリリースに向けた準備の一環として行われたものです。

技術的詳細

このコミットは、Go言語の net/http パッケージにおけるデフォルトのUser-Agent文字列の定義と、それを使用するテストコードの変更に焦点を当てています。

Goの net/http パッケージでは、HTTPリクエストを送信する際に、明示的にUser-Agentヘッダが設定されていない場合、デフォルトのUser-Agent文字列が自動的に追加されます。このデフォルト文字列は、request.go ファイル内の定数 defaultUserAgent で定義されていました。

変更前は、この定数が const defaultUserAgent = "Go http package" と定義されていました。 変更後は、const defaultUserAgent = "Go 1.1 package http" と変更されています。

この変更に伴い、以下のファイルが修正されています。

  1. src/pkg/net/http/request.go:

    • defaultUserAgent 定数の値が変更されました。これがUser-Agent文字列の実際の変更点です。
  2. src/pkg/net/http/export_test.go:

    • テスト目的で、内部の defaultUserAgent 定数にアクセスできるように、DefaultUserAgent というエクスポートされた変数(var DefaultUserAgent = defaultUserAgent)が追加されました。これにより、テストコードが変更後の新しいUser-Agent文字列を参照できるようになります。
  3. src/pkg/net/http/header_test.go:

    • HTTPヘッダのテストケース testHeader 内で、"Server" ヘッダの値がハードコードされた文字列 "Go http package" から、新しくエクスポートされた DefaultUserAgent 変数を参照するように変更されました。これは、サーバー側のテストでUser-Agent文字列が使用される場合にも、変更が反映されるようにするためです。
  4. src/pkg/net/http/request_test.go:

    • リクエストの書き込みテスト TestRequestWriteBufferedWriter 内で、期待されるUser-Agent文字列がハードコードされた "User-Agent: Go http package\\r\\n" から、"User-Agent: " + DefaultUserAgent + "\\r\\n" に変更されました。これにより、テストが新しいUser-Agent文字列の変更に追従できるようになります。
  5. src/pkg/net/http/requestwrite_test.go:

    • 多数のリクエスト書き込みテストケース reqWriteTests 内で、期待されるUser-Agent文字列のハードコードされた値が、すべて "Go http package" から "Go 1.1 package http" に変更されました。これは、テストが実際のHTTPリクエストの出力と一致するようにするための修正です。

これらの変更は、User-Agent文字列の定義を一つ変更するだけで済むように、定数として定義されていたこと、そしてその定数を参照する形でテストコードが書かれていたため、比較的少ない変更で対応できたことを示しています。

コアとなるコードの変更箇所

このコミットの最も核となる変更は、src/pkg/net/http/request.go ファイル内の defaultUserAgent 定数の定義です。

--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -283,7 +283,7 @@ func valueOrDefault(value, def string) string {
 	return def
 }
 
-const defaultUserAgent = "Go http package"
+const defaultUserAgent = "Go 1.1 package http"
 
 // Write writes an HTTP/1.1 request -- header and body -- in wire format.
 // This method consults the following fields of the request:

コアとなるコードの解説

上記の差分が示すように、request.go ファイル内で定義されている defaultUserAgent という定数の値が変更されています。

  • 変更前: const defaultUserAgent = "Go http package"

    • これは、Go 1.0およびそれ以前のバージョンで、net/http パッケージが生成するHTTPリクエストのデフォルトUser-Agentヘッダとして使用されていた文字列です。
  • 変更後: const defaultUserAgent = "Go 1.1 package http"

    • この新しい文字列は、Go 1.1以降のバージョンで使用されるデフォルトのUser-Agentヘッダです。この変更は、前述の通り、一部のIDSが旧来の文字列を誤って悪意のあるものとして検知する問題を回避するために行われました。バージョン番号("1.1")を含めることで、将来的にGoのバージョンアップに伴ってUser-Agent文字列を区別する必要が生じた場合にも対応しやすくなっています。

この定数は、net/http パッケージ内のHTTPリクエストを構築するロジック(特に Request.Write メソッドなど)によって参照され、User-Agentヘッダが明示的に設定されていない場合に、このデフォルト値がリクエストに追加されます。したがって、この定数の変更は、Goアプリケーションが外部に送信するHTTPリクエストのUser-Agentヘッダに直接影響を与えます。

その他の変更は、この defaultUserAgent 定数の変更に追従するためのテストコードの修正であり、この定数自体がUser-Agent文字列の「真のソース」であるため、この部分が最も重要な変更箇所となります。

関連リンク

参考にした情報源リンク