Skip to main content

GoのSSRF脆弱性を軽減する方法

著者
GoLang Logo

2024年12月10日

0 分で読めます

Goアプリケーションの開発では、SSRF(サーバーサイドリクエストフォージェリ)などの脆弱性を防ぐため、HTTPリクエストを安全に処理することが重要です。SSRFとは、攻撃者がサーバーを操作して意図しないリクエストを送信させ、内部サービスや機密データにアクセスする可能性のある攻撃です。

URLの解析と検証によってHTTPリクエストを安全に処理する方法を解説し、http.Get HTTP GETリクエストハンドラーを強化するサンプルコードをご紹介します。

ユーザー自身のドメインにHTTPリクエストを送信して画像を取得するHTTPルートハンドラーのコードは、簡潔にするため一部を省略すると、downloadAndResizeという関数で次のようになります。

func downloadAndResize(tenantID, fileID, fileSize string) error {
	// ...

	downloadResp, err := http.Get(info.Download)
	if (err != nil) {
		panic(err)
	}

	// ...
}

GoコードでSSRF脆弱性を軽減する

GoアプリケーションのSSRF脆弱性を軽減するには、入力値の検証とサニタイズに重点を置き、生成されるドメインが意図せず操作されないよう、安全にURLを構築する方法を理解する必要があります。

SSRF攻撃では、不十分な入力検証が悪用されることがよくあります。攻撃者はURLを操作し、リクエストを意図しない宛先にリダイレクトできます。堅牢な入力検証とサニタイズを実装することで、SSRF攻撃のリスクを大幅に軽減できます。

tenantIDとfileIDの入力検証を実装する

脆弱なGoアプリケーションでは、tenantIDとfileIDをクエリ文字列から検証せずに取得しています。この検証の欠如が、SSRF攻撃の侵入口になります。

これらのパラメーターを安全に使用できるよう、入力検証を実装した次のGoコードを見てみましょう。

func isValidTenantID(tenantID string) bool {
	// Implement a regex pattern to validate tenantID format
	// Example: only allow alphanumeric characters
	validTenantIDPattern := `^[a-zA-Z0-9]+$`
	matched, _ := regexp.MatchString(validTenantIDPattern, tenantID)
	return matched
}

func isValidFileID(fileID string) bool {
	// Implement a regex pattern to validate fileID format
	// Example: only allow alphanumeric characters and hyphens
	validFileIDPattern := `^[a-zA-Z0-9-]+$`
	matched, _ := regexp.MatchString(validFileIDPattern, fileID)
	return matched
}

送信先を信頼できるホストに制限する重要性

SSRF脆弱性を軽減するもう一つの効果的な方法は、送信リクエストの宛先を信頼できるホストに制限することです。許可するホストの許可リストを管理し、各リクエストの宛先ホストがリストに含まれていることを確認します。

downloadAndResize関数でホスト制限を実装する方法の例を示します。

func isTrustedHost(host string) bool {
	// Define a list of trusted hosts
	trustedHosts := []string{"localtest.me", "example.com"}
	for _, trustedHost := range trustedHosts {
		if host == trustedHost {
			return true
		}
	}
	return false
}

func downloadAndResize(tenantID, fileID, fileSize string) error {
	urlStr := fmt.Sprintf("http://%s.%s/storage/%s.json", tenantID, baseHost, fileID)
	parsedURL, err := url.Parse(urlStr)
	if err != nil {
		panic(err)
	}

	if !isTrustedHost(parsedURL.Hostname()) {
		return fmt.Errorf("untrusted host: %s", parsedURL.Hostname())
	}

	// Proceed with the rest of the function
	// ...
}

セキュリティ対策として許可ホストを制限することで、Goアプリケーションが事前に定義した信頼できるホストのリストに含まれる宛先にのみHTTPリクエストを送信するようにし、SSRF攻撃の影響をさらに軽減できます。

開発においてセキュリティを最優先する姿勢の重要性

堅牢で安全なアプリケーションを構築するには、開発者がセキュリティを最優先する姿勢を持つことが重要です。Goも例外ではありません。設計からデプロイまで、ソフトウェア開発ライフサイクルのあらゆる段階でセキュリティを考慮する必要があります。

セキュリティを優先することで、次のことが可能になります。

  • セキュリティ侵害やデータ漏えいのリスクを軽減する。

  • ユーザーデータを保護し、信頼を維持する。

  • 業界の規制や標準に準拠する。

  • セキュリティインシデントのコストと影響を最小限に抑える。

こうしたベストプラクティスに従い、Goセキュリティチートシートなどのリソースを活用することで、Goアプリケーションのセキュリティを強化し、SSRFなどの脅威から保護できます。

Snyk Codeを活用したセキュリティ対策

SSRF脆弱性への対策と、ユーザー入力の検証・サニタイズ、信頼できるホストへの送信リクエストの制限、アクセス可能なドメインを制御する許可リストの使用が重要であることを解説しました。さらに、Snyk Codeなどのセキュリティツールを活用すれば、開発プロセスの早い段階でこうした脆弱性を特定し、修正できます。

アプリケーションのセキュリティをさらに強化するには、静的解析にSnyk Codeをご活用ください。Snyk Codeは、デプロイ前にGoコード内のSSRF脆弱性やその他のセキュリティ問題を特定できます。SnykをIDEやリポジトリに統合すれば、脆弱性を早期に検出し、アプリケーションの安全性を維持できます。

Goのセキュリティに関するベストプラクティスについては、Go security cheatsheetをご覧ください。また、Dockerを使ってアプリケーションを安全にコンテナ化する方法もご紹介しています。

これらの手法を実践し、Snykなどのツールを活用することで、GoアプリケーションをSSRF攻撃やその他のセキュリティ脅威から保護できます。

Snykは他のプログラミング言語にも対応していますか?

Snykは幅広いプログラミング言語に対応した汎用性の高いツールで、多様な技術スタックを扱う開発者にとって欠かせない存在です。JavaScript、Python、Java、Ruby、PHPなど、さまざまな言語での開発に対応し、それぞれのエコシステムに合わせた包括的なセキュリティソリューションを提供します。

対応言語には次のものがあります。

  • JavaScriptとTypeScript:Snykを使えば、Node.jsアプリケーションのコードと依存関係にある脆弱性をスキャンできます。

  • Python:SnykはPythonパッケージの脆弱性を特定し、具体的な修正方法を提示します。

  • Java:MavenやGradleとの連携により、Java開発者は依存関係にある脆弱性を特定・修正し、アプリケーションを保護できます。

  • Ruby:Ruby開発者はSnykを活用して、GemfileやGemfile.lockに含まれる既知の脆弱性をスキャンできます。

PHP:SnykはComposerに対応しており、PHP開発者は依存関係にある脆弱性を特定してプロジェクトを保護できます。

Snykとともに、コーディングアシスタントの未来を切り拓く

コーディングアシスタントについて学び、開発ワークフローに取り入れる方法をご紹介します。