説明
/tmp などの共有ディレクトリで予測可能な名前や過剰な権限を使うと、一時ファイルが攻撃にさらされます。他のユーザーが先に同じ名前のファイルやシンボリックリンクを作り、意図しないファイルへ書き込ませる可能性があります。権限が適切でなければ、内容の読み取りや変更も許してしまいます。
想定される影響
- 先回りしたファイル作成やリンクによって、設定やログなど別のファイルへ書き込まれる可能性があります。
- 過剰な権限で一時データの機密情報が漏れるおそれがあります。
- 高い権限を持つアプリケーションが、保護されたシステムファイルの上書きに悪用される可能性があります。
対処方法
os.CreateTemp、またはそれを呼び出す従来のioutil.TempFileを使い、ランダムな名前で作成してください。/tmp/myfileのような固定名を避け、接頭辞だけを指定して残りはライブラリに生成させてください。os.CreateTempは最初から0o600(umask 適用前)で作成します。ディレクトリとファイルの権限が他のユーザーによる変更を許可しないか確認してください。- 不要になったファイルは
os.Removeで速やかに削除してください。 - パスワード、トークン、個人情報は可能なら一時ファイルに保存せず、メモリや適切な保護されたストレージで処理してください。
例
変更前
go
package main
import (
"fmt"
"os"
)
func unsafeTemp() {
// 変更前: /tmp 内で固定のファイル名を使用
path := "/tmp/report.log"
// 他のユーザーやプロセスが先に同名ファイルを作成したり
// シンボリックリンクを配置したりできる
f, err := os.Create(path)
if err != nil {
fmt.Println("failed to create temp file:", err)
return
}
defer f.Close()
// 0644 などの既定の権限で作成されると
// 他のユーザーが内容を読める可能性
if _, err := f.WriteString("user session token: abc123\n"); err != nil {
fmt.Println("failed to write:", err)
return
}
}
func main() {
unsafeTemp()
}
変更後
go
package main
import (
"fmt"
"os"
)
func safeTemp() {
// /tmp 内に report- 接頭辞で一時ファイルを作成
// ランダムな接尾辞でファイル名の衝突を減らす
f, err := os.CreateTemp("/tmp", "report-")
if err != nil {
fmt.Println("failed to create temp file:", err)
return
}
// 名前を保存し、defer で削除を予約
tempName := f.Name()
defer os.Remove(tempName)
defer f.Close()
// 機密データの権限を 0600 などに制限
if err := os.Chmod(tempName, 0o600); err != nil {
fmt.Println("failed to chmod temp file:", err)
return
}
if _, err := f.WriteString("temporary processing data\n"); err != nil {
fmt.Println("failed to write:", err)
return
}
fmt.Println("temp file created:", tempName)
}
func main() {
safeTemp()
}
説明:
- 変更前:
/tmp/report.logという固定名は、先回りした作成、リンクへの置き換え、プロセス間の衝突を許します。既定の権限によって他のユーザーに内容が見える場合もあります。 - 変更後:
os.CreateTempがランダムな一意の名前と0o600権限で作成し、例のos.Chmodは同じ権限を再指定します。使用後の削除を予約することで、機密性の高い一時データが残る可能性を減らします。