Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

security: bump npm and fix host attack #895

Merged
merged 2 commits into from Jan 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .example.env
Expand Up @@ -3,7 +3,7 @@ LOG_LEVEL=DEBUG
DATABASE_URL=postgres://fider:fider_pw@localhost:5555/fider?sslmode=disable
JWT_SECRET=hsjl]W;&ZcHxT&FK;s%bgIQF:#ch=~#Al4:5]N;7V<qPZ3e9lT4'%;go;LIkc%k

CDN_HOST=dev.assets-fider.io:3000
CDN_HOST=dev.fider.io:3000

# MAINTENANCE=true
# MAINTENANCE_MESSAGE=Sorry, we're down for scheduled maintenance right now.
Expand Down
4 changes: 4 additions & 0 deletions app/middlewares/tenant.go
Expand Up @@ -33,6 +33,10 @@ func SingleTenant() web.MiddlewareFunc {

if firstTenant.Result != nil {
c.SetTenant(firstTenant.Result)

if c.Request.URL.Hostname() != env.Config.HostDomain {
return c.NotFound()
}
}

return next(c)
Expand Down
28 changes: 26 additions & 2 deletions app/middlewares/tenant_test.go
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/getfider/fider/app/models/query"
. "github.com/getfider/fider/app/pkg/assert"
"github.com/getfider/fider/app/pkg/bus"
"github.com/getfider/fider/app/pkg/env"
"github.com/getfider/fider/app/pkg/mock"
"github.com/getfider/fider/app/pkg/web"
)
Expand Down Expand Up @@ -216,14 +217,37 @@ func TestSingleTenant_WithTenants_ShouldSetFirstToContext(t *testing.T) {
server := mock.NewSingleTenantServer()
server.Use(middlewares.SingleTenant())

status, response := server.WithURL("http://somedomain.com").Execute(func(c *web.Context) error {
status, response := server.WithURL("http://test.fider.io").Execute(func(c *web.Context) error {
return c.String(http.StatusOK, c.Tenant().Name)
})

Expect(status).Equals(http.StatusOK)
Expect(response.Body.String()).Equals("MyCompany")
}

func TestSingleTenant_HostMismatch(t *testing.T) {
RegisterT(t)
host := env.Config.HostDomain
defer func() {
env.Config.HostDomain = host
}()
env.Config.HostDomain = "yoursite.com"

bus.AddHandler(func(ctx context.Context, q *query.GetFirstTenant) error {
q.Result = &models.Tenant{Name: "MyCompany", Status: enum.TenantActive}
return nil
})

server := mock.NewSingleTenantServer()
server.Use(middlewares.SingleTenant())

status, _ := server.WithURL("http://someothersite.com").Execute(func(c *web.Context) error {
return c.String(http.StatusOK, c.Tenant().Name)
})

Expect(status).Equals(http.StatusNotFound)
}

func TestBlockPendingTenants_Active(t *testing.T) {
RegisterT(t)

Expand Down Expand Up @@ -372,7 +396,7 @@ func TestRequireTenant_SingleHostMode_ValidTenant(t *testing.T) {
server.Use(middlewares.SingleTenant())
server.Use(middlewares.RequireTenant())

status, response := server.WithURL("http://demo.test.fider.io").Execute(func(c *web.Context) error {
status, response := server.WithURL("http://test.fider.io").Execute(func(c *web.Context) error {
return c.String(http.StatusOK, c.Tenant().Name)
})

Expand Down
23 changes: 9 additions & 14 deletions app/pkg/env/env.go
Expand Up @@ -14,16 +14,16 @@ import (
)

type config struct {
Environment string `env:"GO_ENV,default=production"`
Environment string `env:"GO_ENV,default=production"`
SignUpDisabled bool `env:"SIGNUP_DISABLED,default=false"`
AutoSSL bool `env:"SSL_AUTO,default=false"`
SSLCert string `env:"SSL_CERT"`
SSLCertKey string `env:"SSL_CERT_KEY"`
Port string `env:"PORT,default=3000"`
HostMode string `env:"HOST_MODE,default=single"`
HostDomain string `env:"HOST_DOMAIN"`
JWTSecret string `env:"JWT_SECRET,required"`
Rendergun struct {
AutoSSL bool `env:"SSL_AUTO,default=false"`
SSLCert string `env:"SSL_CERT"`
SSLCertKey string `env:"SSL_CERT_KEY"`
Port string `env:"PORT,default=3000"`
HostMode string `env:"HOST_MODE,default=single"`
HostDomain string `env:"HOST_DOMAIN,required"`
JWTSecret string `env:"JWT_SECRET,required"`
Rendergun struct {
URL string `env:"RENDERGUN_URL"`
}
Database struct {
Expand Down Expand Up @@ -107,11 +107,6 @@ func Reload() {
panic(errors.Wrap(err, "failed to parse environment variables"))
}

//Environment validations
if Config.HostMode != "single" {
mustBeSet("HOST_DOMAIN")
}

if Config.Email.Mailgun.APIKey != "" {
mustBeSet("EMAIL_MAILGUN_DOMAIN")
} else {
Expand Down
7 changes: 7 additions & 0 deletions app/pkg/jwt/jwt.go
@@ -1,6 +1,9 @@
package jwt

import (
"fmt"

"github.com/dgrijalva/jwt-go"
jwtgo "github.com/dgrijalva/jwt-go"
"github.com/getfider/fider/app/pkg/env"
"github.com/getfider/fider/app/pkg/errors"
Expand Down Expand Up @@ -68,6 +71,10 @@ func DecodeOAuthClaims(token string) (*OAuthClaims, error) {

func decode(token string, claims jwtgo.Claims) error {
jwtToken, err := jwtgo.ParseWithClaims(token, claims, func(t *jwtgo.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", t.Header["alg"])
}

return []byte(jwtSecret), nil
})

Expand Down
17 changes: 17 additions & 0 deletions app/pkg/jwt/jwt_test.go
Expand Up @@ -4,6 +4,7 @@ import (
"testing"
"time"

jwtgo "github.com/dgrijalva/jwt-go"
. "github.com/getfider/fider/app/pkg/assert"
"github.com/getfider/fider/app/pkg/jwt"
)
Expand Down Expand Up @@ -40,6 +41,22 @@ func TestJWT_Decode(t *testing.T) {
Expect(decoded.UserEmail).Equals(claims.UserEmail)
}

func TestJWT_Decode_DifferentSignMethod(t *testing.T) {
RegisterT(t)

jwtToken := jwtgo.NewWithClaims(jwtgo.GetSigningMethod("none"), &jwt.FiderClaims{
UserID: 424,
UserName: "Jon Snow",
UserEmail: "jon.snow@got.com",
})
token, err := jwtToken.SignedString(jwtgo.UnsafeAllowNoneSignatureType)
Expect(err).IsNil()

decoded, err := jwt.DecodeFiderClaims(token)
Expect(err.Error()).ContainsSubstring("Unexpected signing method: none")
Expect(decoded).IsNil()
}

func TestJWT_DecodeExpired(t *testing.T) {
RegisterT(t)

Expand Down