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

fix: CSRF vulnerability #44

Merged
merged 8 commits into from
Jul 18, 2023
Merged

fix: CSRF vulnerability #44

merged 8 commits into from
Jul 18, 2023

Conversation

brianchennn
Copy link
Contributor

@brianchennn brianchennn commented Jul 8, 2023

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.

@brianchennn brianchennn force-pushed the main branch 2 times, most recently from cb32912 to 565c233 Compare July 8, 2023 09:13
backend/WebUI/api_webui.go Outdated Show resolved Hide resolved
@ianchen0119
Copy link
Contributor

Hi @brianchennn
Please also help to remove the use of os.Getenv() as we discussed.

mu.Lock()

if jwtKey == "" {
rand.Seed(time.Now().UnixNano())
Copy link

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.

@@ -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"})
Copy link

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.

Copy link

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.

randomBytes := make([]byte, 128)
_, err := rand.Read(randomBytes)
if err != nil {
logger.ProcLog.Warnln("Generate JWT Private Key error.")
Copy link

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?

Copy link
Contributor Author

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.

@@ -47,6 +53,7 @@ func init() {
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
mu = new(sync.Mutex)
Copy link
Collaborator

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))
Copy link
Collaborator

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)
Copy link
Collaborator

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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    return ""

@brianchennn brianchennn force-pushed the main branch 4 times, most recently from 0adfc51 to 47120d1 Compare July 18, 2023 06:34
randomBytes := make([]byte, 256)
_, err := rand.Read(randomBytes)
if err != nil {
logger.ProcLog.Errorln("Generate JWT Private Key error.")
Copy link
Collaborator

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
Copy link
Collaborator

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

@tim-ywliu tim-ywliu merged commit 967d2d3 into free5gc:main Jul 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants