mirror of
https://github.com/gofiber/fiber.git
synced 2025-05-02 05:34:25 +00:00
* fix(middleware/cors): Handling and wildcard subdomain matching (#2915) * fix: allow origins check Refactor CORS origin validation and normalization to trim leading or trailing whitespace in the cfg.AllowOrigins string [list]. URLs with whitespace inside the URL are invalid, so the normalizeOrigin will return false because url.Parse will fail, and the middleware will panic. fixes #2882 * test: AllowOrigins with whitespace * test(middleware/cors): add benchmarks * chore: fix linter errors * test(middleware/cors): use h() instead of app.Test() * test(middleware/cors): add miltiple origins in Test_CORS_AllowOriginScheme * chore: refactor validate and normalize * test(cors/middleware): add more benchmarks * fix(middleware/cors): handling and wildcard subdomain matching docs(middleware/cors): add How it works and Security Considerations * chore: grammar * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: fix misspelling * test(middleware/cors): combine Invalid_Origins tests * refactor(middleware/cors): headers handling * docs(middleware/cors): Update AllowOrigins description * chore: merge * perf(middleware/cors): optimize handler * perf(middleware/cors): optimize handler * chore(middleware/cors): ipdate origin handling logic * chore(middleware/cors): fix header capitalization * docs(middleware/cors): improve sercuity notes * docs(middleware/cors): Improve security notes * docs(middleware/cors): improve CORS overview * docs(middleware/cors): fix ordering of how it works * docs(middleware/cors): add additional info to How to works * docs(middleware/cors): rm space * docs(middleware/cors): add validation for AllowOrigins origins to overview * docs(middleware/cors): update ExposeHeaders and MaxAge descriptions * docs(middleware/cors): Add dynamic origin validation example * docs(middleware/cors): Improve security notes and fix header capitalization * docs(middleware/cors): configuration examples * docs(middleware/cors): `"*"` --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * test(middleware/cors): improve test coverage for request types * chore(middleware/cors): fix v2 merge issues * test(middleware/cors): Add subdomain matching tests * fix(middleware/cors): Update Next function signature * test(middleware/cors): Add benchmark for CORS subdomain matching * test(middleware/cors): cover additiona test cases * refactor(middleware/cors): origin validation and normalization --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
72 lines
2.2 KiB
Go
72 lines
2.2 KiB
Go
package cors
|
|
|
|
import (
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// matchScheme compares the scheme of the domain and pattern
|
|
func matchScheme(domain, pattern string) bool {
|
|
didx := strings.Index(domain, ":")
|
|
pidx := strings.Index(pattern, ":")
|
|
return didx != -1 && pidx != -1 && domain[:didx] == pattern[:pidx]
|
|
}
|
|
|
|
// normalizeDomain removes the scheme and port from the input domain
|
|
func normalizeDomain(input string) string {
|
|
// Remove scheme
|
|
input = strings.TrimPrefix(strings.TrimPrefix(input, "http://"), "https://")
|
|
|
|
// Find and remove port, if present
|
|
if len(input) > 0 && input[0] != '[' {
|
|
if portIndex := strings.Index(input, ":"); portIndex != -1 {
|
|
input = input[:portIndex]
|
|
}
|
|
}
|
|
|
|
return input
|
|
}
|
|
|
|
// normalizeOrigin checks if the provided origin is in a correct format
|
|
// and normalizes it by removing any path or trailing slash.
|
|
// It returns a boolean indicating whether the origin is valid
|
|
// and the normalized origin.
|
|
func normalizeOrigin(origin string) (bool, string) {
|
|
parsedOrigin, err := url.Parse(origin)
|
|
if err != nil {
|
|
return false, ""
|
|
}
|
|
|
|
// Validate the scheme is either http or https
|
|
if parsedOrigin.Scheme != "http" && parsedOrigin.Scheme != "https" {
|
|
return false, ""
|
|
}
|
|
|
|
// Don't allow a wildcard with a protocol
|
|
// wildcards cannot be used within any other value. For example, the following header is not valid:
|
|
// Access-Control-Allow-Origin: https://*
|
|
if strings.Contains(parsedOrigin.Host, "*") {
|
|
return false, ""
|
|
}
|
|
|
|
// Validate there is a host present. The presence of a path, query, or fragment components
|
|
// is checked, but a trailing "/" (indicative of the root) is allowed for the path and will be normalized
|
|
if parsedOrigin.Host == "" || (parsedOrigin.Path != "" && parsedOrigin.Path != "/") || parsedOrigin.RawQuery != "" || parsedOrigin.Fragment != "" {
|
|
return false, ""
|
|
}
|
|
|
|
// Normalize the origin by constructing it from the scheme and host.
|
|
// The path or trailing slash is not included in the normalized origin.
|
|
return true, strings.ToLower(parsedOrigin.Scheme + "://" + parsedOrigin.Host)
|
|
}
|
|
|
|
type subdomain struct {
|
|
// The wildcard pattern
|
|
prefix string
|
|
suffix string
|
|
}
|
|
|
|
func (s subdomain) match(o string) bool {
|
|
return len(o) >= len(s.prefix)+len(s.suffix) && strings.HasPrefix(o, s.prefix) && strings.HasSuffix(o, s.suffix)
|
|
}
|