mirror of
https://github.com/gogs/gogs.git
synced 2026-05-06 09:17:20 +02:00
Compare commits
3 Commits
dependabot
...
wh/fix-mir
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b215ba6788 | ||
|
|
e00e9af33a | ||
|
|
a6a16575d8 |
@@ -4,6 +4,10 @@ All notable changes to Gogs are documented in this file.
|
||||
|
||||
## 0.15.0+dev (`main`)
|
||||
|
||||
### Fixed
|
||||
|
||||
- _Security:_ SSRF via mirror address update bypassing clone address validation.
|
||||
|
||||
### Removed
|
||||
|
||||
- The `gogs cert` subcommand. [#8153](https://github.com/gogs/gogs/pull/8153)
|
||||
|
||||
@@ -52,12 +52,19 @@ func (f *MigrateRepo) Validate(ctx *macaron.Context, errs binding.Errors) bindin
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type ParseRemoteAddrOptions struct {
|
||||
CloneAddr string
|
||||
User *database.User
|
||||
AuthUsername string
|
||||
AuthPassword string
|
||||
}
|
||||
|
||||
// ParseRemoteAddr checks if given remote address is valid,
|
||||
// and returns composed URL with needed username and password.
|
||||
// It also checks if given user has permission when remote address
|
||||
// is actually a local path.
|
||||
func (f MigrateRepo) ParseRemoteAddr(user *database.User) (string, error) {
|
||||
remoteAddr := strings.TrimSpace(f.CloneAddr)
|
||||
func ParseRemoteAddr(options ParseRemoteAddrOptions) (string, error) {
|
||||
remoteAddr := strings.TrimSpace(options.CloneAddr)
|
||||
|
||||
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||
if strings.HasPrefix(remoteAddr, "http://") ||
|
||||
@@ -72,15 +79,15 @@ func (f MigrateRepo) ParseRemoteAddr(user *database.User) (string, error) {
|
||||
return "", database.ErrInvalidCloneAddr{IsBlockedLocalAddress: true}
|
||||
}
|
||||
|
||||
if len(f.AuthUsername)+len(f.AuthPassword) > 0 {
|
||||
u.User = url.UserPassword(f.AuthUsername, f.AuthPassword)
|
||||
if len(options.AuthUsername)+len(options.AuthPassword) > 0 {
|
||||
u.User = url.UserPassword(options.AuthUsername, options.AuthPassword)
|
||||
}
|
||||
// To prevent CRLF injection in git protocol, see https://github.com/gogs/gogs/issues/6413
|
||||
if u.Scheme == "git" && (strings.Contains(remoteAddr, "%0d") || strings.Contains(remoteAddr, "%0a")) {
|
||||
return "", database.ErrInvalidCloneAddr{IsURLError: true}
|
||||
}
|
||||
remoteAddr = u.String()
|
||||
} else if !user.CanImportLocal() {
|
||||
} else if !options.User.CanImportLocal() {
|
||||
return "", database.ErrInvalidCloneAddr{IsPermissionDenied: true}
|
||||
} else if !osx.IsDir(remoteAddr) {
|
||||
return "", database.ErrInvalidCloneAddr{IsInvalidPath: true}
|
||||
|
||||
@@ -251,7 +251,12 @@ func migrate(c *context.APIContext, f form.MigrateRepo) {
|
||||
}
|
||||
}
|
||||
|
||||
remoteAddr, err := f.ParseRemoteAddr(c.User)
|
||||
remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{
|
||||
CloneAddr: f.CloneAddr,
|
||||
User: c.User,
|
||||
AuthUsername: f.AuthUsername,
|
||||
AuthPassword: f.AuthPassword,
|
||||
})
|
||||
if err != nil {
|
||||
if database.IsErrInvalidCloneAddr(err) {
|
||||
addrErr := err.(database.ErrInvalidCloneAddr)
|
||||
|
||||
@@ -170,7 +170,12 @@ func MigratePost(c *context.Context, f form.MigrateRepo) {
|
||||
return
|
||||
}
|
||||
|
||||
remoteAddr, err := f.ParseRemoteAddr(c.User)
|
||||
remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{
|
||||
CloneAddr: f.CloneAddr,
|
||||
User: c.User,
|
||||
AuthUsername: f.AuthUsername,
|
||||
AuthPassword: f.AuthPassword,
|
||||
})
|
||||
if err != nil {
|
||||
if database.IsErrInvalidCloneAddr(err) {
|
||||
c.Data["Err_CloneAddr"] = true
|
||||
|
||||
@@ -121,7 +121,33 @@ func SettingsPost(c *context.Context, f form.RepoSetting) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := c.Repo.Mirror.SaveAddress(f.MirrorAddress); err != nil {
|
||||
|
||||
remoteAddr, err := form.ParseRemoteAddr(form.ParseRemoteAddrOptions{
|
||||
CloneAddr: f.MirrorAddress,
|
||||
User: c.User,
|
||||
})
|
||||
if err != nil {
|
||||
if database.IsErrInvalidCloneAddr(err) {
|
||||
addrErr := err.(database.ErrInvalidCloneAddr)
|
||||
switch {
|
||||
case addrErr.IsURLError:
|
||||
c.RenderWithErr(c.Tr("repo.migrate.clone_address")+c.Tr("form.url_error"), http.StatusBadRequest, tmplRepoSettingsOptions, &f)
|
||||
case addrErr.IsPermissionDenied:
|
||||
c.RenderWithErr(c.Tr("repo.migrate.permission_denied"), http.StatusForbidden, tmplRepoSettingsOptions, &f)
|
||||
case addrErr.IsInvalidPath:
|
||||
c.RenderWithErr(c.Tr("repo.migrate.invalid_local_path"), http.StatusBadRequest, tmplRepoSettingsOptions, &f)
|
||||
case addrErr.IsBlockedLocalAddress:
|
||||
c.RenderWithErr(c.Tr("repo.migrate.clone_address_resolved_to_blocked_local_address"), http.StatusForbidden, tmplRepoSettingsOptions, &f)
|
||||
default:
|
||||
c.Error(err, "unexpected error")
|
||||
}
|
||||
} else {
|
||||
c.Error(err, "parse remote address")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.Repo.Mirror.SaveAddress(remoteAddr); err != nil {
|
||||
c.Error(err, "save address")
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user