Restrict Host-based origin fetches to Steam CDN names.
When upstream is empty the cache used the client Host as the fetch URL, so any LAN client with a spoofed Steam User-Agent could proxy to literal IPs or arbitrary names. Reject those hosts, stop following upstream redirects, and keep path-only cache keys so real Steam CDNs still share entries.
This commit is contained in:
@@ -1165,3 +1165,61 @@ func TestClientRateLimiter_BlackBox(t *testing.T) {
|
||||
t.Error("different clients must have distinct limiters")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostAllowedForDirectFetch(t *testing.T) {
|
||||
allowed := []string{
|
||||
"lancache.steamcontent.com",
|
||||
"cache1-iad1.steamcontent.com:443",
|
||||
"steamcontent.com",
|
||||
"content.steampowered.com",
|
||||
"cdn.steamstatic.com",
|
||||
}
|
||||
denied := []string{
|
||||
"",
|
||||
"127.0.0.1",
|
||||
"127.0.0.1:80",
|
||||
"[::1]:80",
|
||||
"192.168.1.1",
|
||||
"169.254.169.254",
|
||||
"evil.example",
|
||||
"example.com",
|
||||
"notsteamcontent.com",
|
||||
}
|
||||
for _, h := range allowed {
|
||||
if !hostAllowedForDirectFetch(h) {
|
||||
t.Errorf("expected allowed: %q", h)
|
||||
}
|
||||
}
|
||||
for _, h := range denied {
|
||||
if hostAllowedForDirectFetch(h) {
|
||||
t.Errorf("expected denied: %q", h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirectFetchRejectsNonSteamHost(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", td, "", "lru", "lru", 200, 5, "0", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { sc.Shutdown() })
|
||||
|
||||
req := httptest.NewRequest("GET", "/depot/ssrf/chunk", nil)
|
||||
req.Host = "127.0.0.1"
|
||||
req.Header.Set("User-Agent", "Valve/Steam HTTP Client 1.0")
|
||||
rec := httptest.NewRecorder()
|
||||
sc.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Errorf("IP Host: expected 400, got %d", rec.Code)
|
||||
}
|
||||
|
||||
req2 := httptest.NewRequest("GET", "/depot/ssrf/chunk2", nil)
|
||||
req2.Host = "evil.example"
|
||||
req2.Header.Set("User-Agent", "Valve/Steam HTTP Client 1.0")
|
||||
rec2 := httptest.NewRecorder()
|
||||
sc.ServeHTTP(rec2, req2)
|
||||
if rec2.Code != http.StatusBadRequest {
|
||||
t.Errorf("non-CDN Host: expected 400, got %d", rec2.Code)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user