CVE-2021-21403: Improper Authentication (CWE-287)
value: In github.com/kongchuanhujiao/server before version 1.3.21 there is an authentication Bypass by Primary Weakness vulnerability. All users are impacted. This is fixed in version 1.3.21.
CWE description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
CVSS v3 base score: 9.8
Published: 2021-03-26T18:15Z
Repository: https://github.com/kongchuanhujiao/server
Language: Go
Files changed: internal/app/datahub/pkg/account/memory.go, internal/app/kongchuanhujiao/account/apis.go, internal/app/kongchuanhujiao/account/utils.go
Commit date: 2021-03-16 19:18:48 +0800
Commit message: 重构：优化验证码生成逻辑，最小化权责

Diff: diff --git a/internal/app/datahub/pkg/account/memory.go b/internal/app/datahub/pkg/account/memory.go
index cca1457..1e89024 100644
--- a/internal/app/datahub/pkg/account/memory.go
+++ b/internal/app/datahub/pkg/account/memory.go
@@ -1,15 +1,39 @@
 package account
 
-import "github.com/kongchuanhujiao/server/internal/app/datahub/internal/memory"
+import (
+	"math/rand"
+	"strconv"
+	"time"
 
-func GetCode(id string) string {
-	return memory.Code[id]
-}
+	"github.com/kongchuanhujiao/server/internal/app/datahub/internal/memory"
+)
+
+// GenerateCode 写入验证码返回一个验证码
+func GenerateCode(id string) (c string) {
+
+	rand.Seed(time.Now().UnixNano())
+	c = strconv.FormatFloat(rand.Float64(), 'f', -1, 64)[2:6]
 
-func WriteCode(id string, code string) {
-	memory.Code[id] = code
+	memory.Code[id] = c
+
+	go func() {
+		timer := time.NewTimer(5 * time.Minute)
+		defer timer.Stop()
+		<-timer.C
+		deleteCode(id)
+	}()
+
+	return
 }
 
-func DeleteCode(id string) {
-	delete(memory.Code, id)
+// VerifyCode 验证验证码
+func VerifyCode(id string, code string) (ok bool) {
+	if code == memory.Code[id] {
+		ok = true
+		deleteCode(id)
+	}
+	return
 }
+
+// deleteCode 删除验证码
+func deleteCode(id string) { delete(memory.Code, id) }
diff --git a/internal/app/kongchuanhujiao/account/apis.go b/internal/app/kongchuanhujiao/account/apis.go
index c1e53d3..272b259 100644
--- a/internal/app/kongchuanhujiao/account/apis.go
+++ b/internal/app/kongchuanhujiao/account/apis.go
@@ -39,11 +39,11 @@ type PostLoginReq struct {
 
 // PostLogin 登录验证 APIs。
 // 调用方法：POST apis/accounts/login
 func (a *APIs) PostLogin(v *PostLoginReq) *kongchuanhujiao.Response {
 
-	if v.Code != account.GetCode(v.ID) || v.Code == "" { // FIXME datahub 鉴权
+	if account.VerifyCode(v.ID, v.Code) || v.Code == "" {
 		return kongchuanhujiao.GenerateErrResp(1, "验证码有误")
 	}
 
 	now := time.Now()
 	t, err := jwt.NewTokenWithClaims(jwt.SigningMethodES256, jwt.MapClaims{
diff --git a/internal/app/kongchuanhujiao/account/utils.go b/internal/app/kongchuanhujiao/account/utils.go
index da6574c..364432e 100644
--- a/internal/app/kongchuanhujiao/account/utils.go
+++ b/internal/app/kongchuanhujiao/account/utils.go
@@ -1,13 +1,9 @@
 package account
 
 import (
 	"errors"
-	"math/rand"
-	"strconv"
-	"time"
-
 	"github.com/kongchuanhujiao/server/internal/app/client"
 	"github.com/kongchuanhujiao/server/internal/app/client/message"
 	"github.com/kongchuanhujiao/server/internal/app/datahub/pkg/account"
 	"github.com/kongchuanhujiao/server/internal/pkg/logger"
 
@@ -20,29 +16,16 @@ func sendCode(id string) (err error) {
 	a, err := account.SelectAccount(id, 0)
 	if err != nil {
 		logger.Error("发送验证码失败", zap.Error(err))
 		return
 	}
-
 	if len(a) == 0 {
 		return errors.New("账号不存在")
 	}
 
-	rand.Seed(time.Now().UnixNano())
-	c := strconv.FormatFloat(rand.Float64(), 'f', -1, 64)[2:6]
-
 	client.GetClient().SendMessage(
-		message.NewTextMessage("您的验证码是：" + c + "，请勿泄露给他人。有效期5分钟").
+		message.NewTextMessage("您的验证码是：" + account.GenerateCode(id) + "，请勿泄露给他人。有效期5分钟").
 			SetTarget(&message.Target{ID: a[0].QQ}),
 	)
 
-	account.WriteCode(id, c)
-
-	go func() {
-		timer := time.NewTimer(5 * time.Minute)
-		defer timer.Stop()
-		<-timer.C
-		account.DeleteCode(id)
-	}()
-
 	return
 }

Vulnerable code: import "github.com/kongchuanhujiao/server/internal/app/datahub/internal/memory"
func GetCode(id string) string {
	return memory.Code[id]
}
func WriteCode(id string, code string) {
	memory.Code[id] = code
func DeleteCode(id string) {
	delete(memory.Code, id)
	if v.Code != account.GetCode(v.ID) || v.Code == "" { // FIXME datahub 鉴权
	"math/rand"
	"strconv"
	"time"


	rand.Seed(time.Now().UnixNano())
	c := strconv.FormatFloat(rand.Float64(), 'f', -1, 64)[2:6]

		message.NewTextMessage("您的验证码是：" + c + "，请勿泄露给他人。有效期5分钟").
	account.WriteCode(id, c)

	go func() {
		timer := time.NewTimer(5 * time.Minute)
		defer timer.Stop()
		<-timer.C
		account.DeleteCode(id)
	}()

Fixed code: import (
	"math/rand"
	"strconv"
	"time"
	"github.com/kongchuanhujiao/server/internal/app/datahub/internal/memory"
)

// GenerateCode 写入验证码返回一个验证码
func GenerateCode(id string) (c string) {

	rand.Seed(time.Now().UnixNano())
	c = strconv.FormatFloat(rand.Float64(), 'f', -1, 64)[2:6]
	memory.Code[id] = c

	go func() {
		timer := time.NewTimer(5 * time.Minute)
		defer timer.Stop()
		<-timer.C
		deleteCode(id)
	}()

	return
// VerifyCode 验证验证码
func VerifyCode(id string, code string) (ok bool) {
	if code == memory.Code[id] {
		ok = true
		deleteCode(id)
	}
	return

// deleteCode 删除验证码
func deleteCode(id string) { delete(memory.Code, id) }
	if account.VerifyCode(v.ID, v.Code) || v.Code == "" {
		message.NewTextMessage("您的验证码是：" + account.GenerateCode(id) + "，请勿泄露给他人。有效期5分钟").