internal/oauthex: address URL attacks in PRM (#539)
Fix Protected Resource Metadata to prevent URL attacks, as described in the issue. For #526
This commit is contained in:
parent
af4bddf3ea
commit
fd0dc9d741
3 changed files with 31 additions and 5 deletions
|
|
@ -65,3 +65,21 @@ func getJSON[T any](ctx context.Context, c *http.Client, url string, limit int64
|
|||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// checkURLScheme ensures that its argument is a valid URL with a scheme
|
||||
// that prevents XSS attacks.
|
||||
// See #526.
|
||||
func checkURLScheme(u string) error {
|
||||
if u == "" {
|
||||
return nil
|
||||
}
|
||||
uu, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scheme := strings.ToLower(uu.Scheme)
|
||||
if scheme == "javascript" || scheme == "data" || scheme == "vbscript" {
|
||||
return fmt.Errorf("URL has disallowed scheme %q", scheme)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,11 +159,11 @@ func GetProtectedResourceMetadataFromHeader(ctx context.Context, header http.Hea
|
|||
|
||||
// getPRM makes a GET request to the given URL, and validates the response.
|
||||
// As part of the validation, it compares the returned resource field to wantResource.
|
||||
func getPRM(ctx context.Context, url string, c *http.Client, wantResource string) (*ProtectedResourceMetadata, error) {
|
||||
if !strings.HasPrefix(strings.ToUpper(url), "HTTPS://") {
|
||||
return nil, fmt.Errorf("resource URL %q does not use HTTPS", url)
|
||||
func getPRM(ctx context.Context, purl string, c *http.Client, wantResource string) (*ProtectedResourceMetadata, error) {
|
||||
if !strings.HasPrefix(strings.ToUpper(purl), "HTTPS://") {
|
||||
return nil, fmt.Errorf("resource URL %q does not use HTTPS", purl)
|
||||
}
|
||||
prm, err := getJSON[ProtectedResourceMetadata](ctx, c, url, 1<<20)
|
||||
prm, err := getJSON[ProtectedResourceMetadata](ctx, c, purl, 1<<20)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -171,6 +171,12 @@ func getPRM(ctx context.Context, url string, c *http.Client, wantResource string
|
|||
if prm.Resource != wantResource {
|
||||
return nil, fmt.Errorf("got metadata resource %q, want %q", prm.Resource, wantResource)
|
||||
}
|
||||
// Validate the authorization server URLs to prevent XSS attacks (see #526).
|
||||
for _, u := range prm.AuthorizationServers {
|
||||
if err := checkURLScheme(u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return prm, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
// Package oauthex implements extensions to OAuth2.
|
||||
package oauthex
|
||||
|
||||
import "github.com/modelcontextprotocol/go-sdk/internal/oauthex"
|
||||
import (
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/oauthex"
|
||||
)
|
||||
|
||||
// ProtectedResourceMetadata is the metadata for an OAuth 2.0 protected resource,
|
||||
// as defined in section 2 of https://www.rfc-editor.org/rfc/rfc9728.html.
|
||||
|
|
|
|||
Loading…
Reference in a new issue