-
Notifications
You must be signed in to change notification settings - Fork 46
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
fix: CSRF vulnerability #44
Conversation
cb32912
to
565c233
Compare
Hi @brianchennn |
backend/WebUI/api_webui.go
Outdated
mu.Lock() | ||
|
||
if jwtKey == "" { | ||
rand.Seed(time.Now().UnixNano()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are using math/rand
here, which is not cryptographically secure (especially when seeded with the current time). Since this is supposed to be a secret, it should not be guessable. I recommend to use crypto/rand
here.
backend/WebUI/api_webui.go
Outdated
@@ -530,7 +551,7 @@ func GetTenants(c *gin.Context) { | |||
setCorsHeader(c) | |||
|
|||
if !CheckAuth(c) { | |||
c.JSON(http.StatusNotFound, bson.M{}) | |||
c.JSON(http.StatusNotFound, gin.H{"cause": "Illegal Token"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think http.StatusUnauthorized
would be more appropriate here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or http.StatusForbidden
, but that depends on why exactly CheckAuth
failed. If it failed because the token is expired or invalid, it should be http.StatusUnauthorized
. If it failed because the token does not include the required claims, it should be http.StatusForbidden
.
backend/WebUI/api_webui.go
Outdated
randomBytes := make([]byte, 128) | ||
_, err := rand.Read(randomBytes) | ||
if err != nil { | ||
logger.ProcLog.Warnln("Generate JWT Private Key error.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that if creating a random key fails, the signature is done with an empty string as key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but I think that it would not happened. This err checking scope is added to pass the golangci-lint.
backend/WebUI/api_webui.go
Outdated
@@ -47,6 +53,7 @@ func init() { | |||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | |||
}, | |||
} | |||
mu = new(sync.Mutex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generate jwtKey here and no need mu
@@ -401,7 +411,7 @@ func JWT(email, userId, tenantId string) string { | |||
claims["email"] = email | |||
claims["tenantId"] = tenantId | |||
|
|||
tokenString, err := token.SignedString([]byte(os.Getenv("SIGNINGKEY"))) | |||
tokenString, err := token.SignedString([]byte(jwtKey)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if jwtKey == "" {
return ""
}
"username:", login.Username, | ||
", userid:", userId, | ||
", tenantid:", tenantId, | ||
"}") | ||
|
||
token := JWT(login.Username, userId, tenantId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check if token is "", and return error rsp
@@ -401,7 +411,7 @@ func JWT(email, userId, tenantId string) string { | |||
claims["email"] = email | |||
claims["tenantId"] = tenantId | |||
|
|||
tokenString, err := token.SignedString([]byte(os.Getenv("SIGNINGKEY"))) | |||
tokenString, err := token.SignedString([]byte(jwtKey)) | |||
if err != nil { | |||
logger.ProcLog.Errorf("JWT err: %+v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return ""
0adfc51
to
47120d1
Compare
backend/WebUI/api_webui.go
Outdated
randomBytes := make([]byte, 256) | ||
_, err := rand.Read(randomBytes) | ||
if err != nil { | ||
logger.ProcLog.Errorln("Generate JWT Private Key error.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return errors.Wrap(err, "Init JWT key error")
@@ -80,6 +80,10 @@ func (a *WebuiApp) Start(tlsKeyLogPath string) { | |||
logger.InitLog.Infoln("Server started") | |||
|
|||
router := WebUI.NewRouter() | |||
WebUI.SetAdmin() | |||
if err := WebUI.InitJwtKey(); err != nil { | |||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logger.InitLog.Errorln(err)
return
This PR resolve the CSRF vulnerability by JWT (Json Web Token).
Now, if clients want to request the RESTful API, they could not use "admin" as token.
The only way to get the JWT token is to login through Webconsole's Login page.