fix(identity): 拒绝跨站浏览器会话端点
统一认证使用 HttpOnly SameSite=Strict 会话 Cookie。配对时若 Public Base 与 Web Base 不属于同一 schemeful site,浏览器回调会丢失事务 Cookie。新增基于 Public Suffix List 的同站校验,并在运行时重建时重复门禁,防止旧持久化数据绕过。 验证:go test ./... -count=1(apps/api)
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -205,6 +206,9 @@ func (input PairingInput) ConsumerMetadata(sessionRevocation bool, appEnv string
|
||||
if err != nil {
|
||||
return ConsumerMetadata{}, errors.New("web base URL is invalid")
|
||||
}
|
||||
if !sameSiteBaseURLs(publicBase, webBase) {
|
||||
return ConsumerMetadata{}, errors.New("public base URL and web base URL must be same-site")
|
||||
}
|
||||
if strings.TrimSpace(input.LocalTenantKey) == "" {
|
||||
return ConsumerMetadata{}, errors.New("local tenant mapping is required")
|
||||
}
|
||||
@@ -280,6 +284,9 @@ func ValidateRevisionURLs(revision Revision, appEnv string) error {
|
||||
return errors.New("identity " + candidate.label + " URL must use HTTPS in this environment")
|
||||
}
|
||||
}
|
||||
if !sameSiteBaseURLs(revision.PublicBaseURL, revision.WebBaseURL) {
|
||||
return errors.New("identity public base and web base URLs must be same-site")
|
||||
}
|
||||
if revision.SessionRevocation || revision.SecurityEventIssuer != "" || revision.SecurityEventConfigURL != "" {
|
||||
if validatePublicIdentityURL(revision.SecurityEventIssuer, appEnv) != nil ||
|
||||
validatePublicIdentityURL(revision.SecurityEventConfigURL, appEnv) != nil {
|
||||
@@ -289,6 +296,24 @@ func ValidateRevisionURLs(revision Revision, appEnv string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sameSiteBaseURLs(left, right string) bool {
|
||||
leftURL, leftErr := url.Parse(left)
|
||||
rightURL, rightErr := url.Parse(right)
|
||||
if leftErr != nil || rightErr != nil ||
|
||||
!strings.EqualFold(leftURL.Scheme, rightURL.Scheme) {
|
||||
return false
|
||||
}
|
||||
leftHost := strings.TrimSuffix(strings.ToLower(leftURL.Hostname()), ".")
|
||||
rightHost := strings.TrimSuffix(strings.ToLower(rightURL.Hostname()), ".")
|
||||
if leftHost == rightHost {
|
||||
return true
|
||||
}
|
||||
leftDomain, leftErr := publicsuffix.EffectiveTLDPlusOne(leftHost)
|
||||
rightDomain, rightErr := publicsuffix.EffectiveTLDPlusOne(rightHost)
|
||||
return leftErr == nil && rightErr == nil &&
|
||||
strings.EqualFold(leftDomain, rightDomain)
|
||||
}
|
||||
|
||||
func isLoopbackHost(host string) bool {
|
||||
if host == "localhost" {
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user