Skip to content

Commit 4b45ec9

Browse files
chore(middleware): add hostauthorization to README, fix lint issues
1 parent a96d0e8 commit 4b45ec9

File tree

3 files changed

+49
-35
lines changed

3 files changed

+49
-35
lines changed

.github/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ Here is a list of middleware that are included within the Fiber framework.
739739
| [favicon](https://github.com/gofiber/fiber/tree/main/middleware/favicon) | Ignore favicon from logs or serve from memory if a file path is provided. |
740740
| [healthcheck](https://github.com/gofiber/fiber/tree/main/middleware/healthcheck) | Liveness and Readiness probes for Fiber. |
741741
| [helmet](https://github.com/gofiber/fiber/tree/main/middleware/helmet) | Helps secure your apps by setting various HTTP headers. |
742+
| [hostauthorization](https://github.com/gofiber/fiber/tree/main/middleware/hostauthorization) | Validates the Host header against a configurable allowlist, protecting against DNS rebinding attacks. |
742743
| [idempotency](https://github.com/gofiber/fiber/tree/main/middleware/idempotency) | Allows for fault-tolerant APIs where duplicate requests do not erroneously cause the same action performed multiple times on the server-side. |
743744
| [keyauth](https://github.com/gofiber/fiber/tree/main/middleware/keyauth) | Adds support for key based authentication. |
744745
| [limiter](https://github.com/gofiber/fiber/tree/main/middleware/limiter) | Adds Rate-limiting support to Fiber. Use to limit repeated requests to public APIs and/or endpoints such as password reset. |

middleware/hostauthorization/config.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@ type Config struct {
1717
// Optional. Default: nil
1818
Next func(c fiber.Ctx) bool
1919

20-
// AllowedHosts is the list of permitted host values.
21-
// Supports three match types:
22-
// - Exact: "api.myapp.com"
23-
// - Subdomain: ".myapp.com" (leading dot matches any subdomain, NOT the bare domain)
24-
// - CIDR: "10.0.0.0/8" (matches hosts that are IPs in the range)
25-
//
26-
// Required if AllowedHostsFunc is nil.
27-
AllowedHosts []string
28-
2920
// AllowedHostsFunc is a dynamic validator called when static AllowedHosts
3021
// don't match. Receives the hostname (port stripped, lowercased).
3122
// Return true to allow.
@@ -38,6 +29,15 @@ type Config struct {
3829
//
3930
// Optional. Default: returns 403 Forbidden with "Forbidden" body.
4031
ErrorHandler fiber.ErrorHandler
32+
33+
// AllowedHosts is the list of permitted host values.
34+
// Supports three match types:
35+
// - Exact: "api.myapp.com"
36+
// - Subdomain: ".myapp.com" (leading dot matches any subdomain, NOT the bare domain)
37+
// - CIDR: "10.0.0.0/8" (matches hosts that are IPs in the range)
38+
//
39+
// Required if AllowedHostsFunc is nil.
40+
AllowedHosts []string
4141
}
4242

4343
// ConfigDefault is the default config.

middleware/hostauthorization/hostauthorization_test.go

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package hostauthorization
22

33
import (
4+
"net/http"
45
"net/http/httptest"
56
"testing"
67

@@ -215,7 +216,7 @@ func Test_HostAuthorization_AllowedHost(t *testing.T) {
215216
return c.SendString("OK")
216217
})
217218

218-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
219+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
219220
req.Host = "example.com"
220221

221222
resp, err := app.Test(req)
@@ -235,7 +236,7 @@ func Test_HostAuthorization_RejectedHost(t *testing.T) {
235236
return c.SendString("OK")
236237
})
237238

238-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
239+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
239240
req.Host = "evil.com"
240241

241242
resp, err := app.Test(req)
@@ -255,7 +256,7 @@ func Test_HostAuthorization_EmptyHost(t *testing.T) {
255256
return c.SendString("OK")
256257
})
257258

258-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
259+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
259260
req.Host = ""
260261

261262
resp, err := app.Test(req)
@@ -275,7 +276,7 @@ func Test_HostAuthorization_HostWithPort(t *testing.T) {
275276
return c.SendString("OK")
276277
})
277278

278-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
279+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
279280
req.Host = "example.com:8080"
280281

281282
resp, err := app.Test(req)
@@ -298,7 +299,7 @@ func Test_HostAuthorization_Next(t *testing.T) {
298299
return c.SendString("OK")
299300
})
300301

301-
req := httptest.NewRequest(fiber.MethodGet, "/healthz", nil)
302+
req := httptest.NewRequest(fiber.MethodGet, "/healthz", http.NoBody)
302303
req.Host = "evil.com"
303304

304305
resp, err := app.Test(req)
@@ -319,15 +320,15 @@ func Test_HostAuthorization_SubdomainWildcard(t *testing.T) {
319320
})
320321

321322
// Subdomain should be allowed
322-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
323+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
323324
req.Host = "api.myapp.com"
324325

325326
resp, err := app.Test(req)
326327
require.NoError(t, err)
327328
require.Equal(t, fiber.StatusOK, resp.StatusCode)
328329

329330
// Bare domain should be rejected
330-
req2 := httptest.NewRequest(fiber.MethodGet, "/", nil)
331+
req2 := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
331332
req2.Host = "myapp.com"
332333

333334
resp2, err := app.Test(req2)
@@ -347,15 +348,15 @@ func Test_HostAuthorization_CIDR(t *testing.T) {
347348
return c.SendString("OK")
348349
})
349350

350-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
351+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
351352
req.Host = "10.0.50.3"
352353

353354
resp, err := app.Test(req)
354355
require.NoError(t, err)
355356
require.Equal(t, fiber.StatusOK, resp.StatusCode)
356357

357358
// Cloud metadata IP should be rejected
358-
req2 := httptest.NewRequest(fiber.MethodGet, "/", nil)
359+
req2 := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
359360
req2.Host = "169.254.169.254"
360361

361362
resp2, err := app.Test(req2)
@@ -377,14 +378,14 @@ func Test_HostAuthorization_AllowedHostsFunc(t *testing.T) {
377378
return c.SendString("OK")
378379
})
379380

380-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
381+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
381382
req.Host = "dynamic.com"
382383

383384
resp, err := app.Test(req)
384385
require.NoError(t, err)
385386
require.Equal(t, fiber.StatusOK, resp.StatusCode)
386387

387-
req2 := httptest.NewRequest(fiber.MethodGet, "/", nil)
388+
req2 := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
388389
req2.Host = "evil.com"
389390

390391
resp2, err := app.Test(req2)
@@ -408,7 +409,7 @@ func Test_HostAuthorization_CustomErrorHandler(t *testing.T) {
408409
return c.SendString("OK")
409410
})
410411

411-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
412+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
412413
req.Host = "evil.com"
413414

414415
resp, err := app.Test(req)
@@ -428,7 +429,7 @@ func Test_HostAuthorization_CaseInsensitive(t *testing.T) {
428429
return c.SendString("OK")
429430
})
430431

431-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
432+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
432433
req.Host = "EXAMPLE.com"
433434

434435
resp, err := app.Test(req)
@@ -448,7 +449,7 @@ func Test_HostAuthorization_TrailingDot(t *testing.T) {
448449
return c.SendString("OK")
449450
})
450451

451-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
452+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
452453
req.Host = "example.com."
453454

454455
resp, err := app.Test(req)
@@ -468,7 +469,7 @@ func Test_HostAuthorization_ExactIP(t *testing.T) {
468469
return c.SendString("OK")
469470
})
470471

471-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
472+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
472473
req.Host = "127.0.0.1"
473474

474475
resp, err := app.Test(req)
@@ -493,7 +494,7 @@ func Test_HostAuthorization_OverlappingRules(t *testing.T) {
493494
})
494495

495496
// Matches both exact and wildcard
496-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
497+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
497498
req.Host = "api.myapp.com"
498499

499500
resp, err := app.Test(req)
@@ -513,7 +514,7 @@ func Test_HostAuthorization_IPv6Brackets(t *testing.T) {
513514
return c.SendString("OK")
514515
})
515516

516-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
517+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
517518
req.Host = "[fd00::1]"
518519

519520
resp, err := app.Test(req)
@@ -542,7 +543,7 @@ func Test_HostAuthorization_XForwardedHost_TrustProxy(t *testing.T) {
542543
})
543544

544545
// Allowed via X-Forwarded-Host
545-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
546+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
546547
req.Host = "proxy.internal"
547548
req.Header.Set("X-Forwarded-Host", "example.com")
548549

@@ -551,7 +552,7 @@ func Test_HostAuthorization_XForwardedHost_TrustProxy(t *testing.T) {
551552
require.Equal(t, fiber.StatusOK, resp.StatusCode)
552553

553554
// Rejected: X-Forwarded-Host is unauthorized
554-
req2 := httptest.NewRequest(fiber.MethodGet, "/", nil)
555+
req2 := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
555556
req2.Host = "example.com"
556557
req2.Header.Set("X-Forwarded-Host", "evil.com")
557558

@@ -574,7 +575,7 @@ func Test_HostAuthorization_XForwardedHost_NoTrustProxy(t *testing.T) {
574575
return c.SendString("OK")
575576
})
576577

577-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
578+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
578579
req.Host = "example.com"
579580
req.Header.Set("X-Forwarded-Host", "evil.com")
580581

@@ -594,13 +595,17 @@ func Benchmark_HostAuthorization_ExactMatch(b *testing.B) {
594595
return c.SendString("OK")
595596
})
596597

597-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
598+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
598599
req.Host = "example.com"
599600

600601
b.ReportAllocs()
601602
b.ResetTimer()
602603
for i := 0; i < b.N; i++ {
603-
_, _ = app.Test(req)
604+
resp, err := app.Test(req)
605+
if err != nil {
606+
b.Fatal(err)
607+
}
608+
resp.Body.Close() //nolint:errcheck // benchmark cleanup
604609
}
605610
}
606611

@@ -613,13 +618,17 @@ func Benchmark_HostAuthorization_CIDR(b *testing.B) {
613618
return c.SendString("OK")
614619
})
615620

616-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
621+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
617622
req.Host = "10.0.50.3"
618623

619624
b.ReportAllocs()
620625
b.ResetTimer()
621626
for i := 0; i < b.N; i++ {
622-
_, _ = app.Test(req)
627+
resp, err := app.Test(req)
628+
if err != nil {
629+
b.Fatal(err)
630+
}
631+
resp.Body.Close() //nolint:errcheck // benchmark cleanup
623632
}
624633
}
625634

@@ -637,12 +646,16 @@ func Benchmark_HostAuthorization_Mixed(b *testing.B) {
637646
return c.SendString("OK")
638647
})
639648

640-
req := httptest.NewRequest(fiber.MethodGet, "/", nil)
649+
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
641650
req.Host = "api.myapp.com"
642651

643652
b.ReportAllocs()
644653
b.ResetTimer()
645654
for i := 0; i < b.N; i++ {
646-
_, _ = app.Test(req)
655+
resp, err := app.Test(req)
656+
if err != nil {
657+
b.Fatal(err)
658+
}
659+
resp.Body.Close() //nolint:errcheck // benchmark cleanup
647660
}
648661
}

0 commit comments

Comments
 (0)