From 08675bd99fbce3fcc9e704c7f9644a43643c1411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Mon, 25 May 2020 21:42:45 +0200 Subject: [PATCH] feat: use bcrypt with salts instead of md5 for hashing password (resolve #21) --- .env.example | 3 ++- config.ini | 2 +- go.mod | 1 + middlewares/authenticate.go | 2 +- models/config.go | 3 +++ routes/public.go | 2 +- services/user.go | 15 +++++++-------- utils/auth.go | 22 +++++++++++++--------- version.txt | 2 +- 9 files changed, 30 insertions(+), 22 deletions(-) diff --git a/.env.example b/.env.example index 009ac70..25fd402 100644 --- a/.env.example +++ b/.env.example @@ -5,5 +5,6 @@ WAKAPI_DB_USER=myuser WAKAPI_DB_PASSWORD=shhh WAKAPI_DB_HOST=localhost WAKAPI_DB_PORT=3306 +WAKAPI_PASSWORD_SALT=shhh WAKAPI_DEFAULT_USER_NAME=admin -WAKAPI_DEFAULT_USER_PASSWORD=admin # CHANGE! \ No newline at end of file +WAKAPI_DEFAULT_USER_PASSWORD=admin123 # CHANGE! \ No newline at end of file diff --git a/config.ini b/config.ini index 85e0f9b..7f3fc25 100644 --- a/config.ini +++ b/config.ini @@ -4,7 +4,7 @@ port = 3000 base_path = / [app] -cleanup = true +cleanup = false [database] max_connections = 2 diff --git a/go.mod b/go.mod index 9fce9b0..dab7aec 100644 --- a/go.mod +++ b/go.mod @@ -16,5 +16,6 @@ require ( github.com/rubenv/sql-migrate v0.0.0-20200402132117-435005d389bc github.com/satori/go.uuid v1.2.0 github.com/t-tiger/gorm-bulk-insert v0.0.0-20191014134946-beb77b81825f + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c gopkg.in/ini.v1 v1.50.0 ) diff --git a/middlewares/authenticate.go b/middlewares/authenticate.go index d2461de..ade864c 100644 --- a/middlewares/authenticate.go +++ b/middlewares/authenticate.go @@ -101,7 +101,7 @@ func (m *AuthenticateMiddleware) tryGetUserByCookie(r *http.Request) (*models.Us if err != nil { return nil, err } - if !utils.CheckPassword(user, login.Password) { + if !utils.CheckPassword(user, login.Password, m.config.PasswordSalt) { return nil, errors.New("invalid password") } } else { diff --git a/models/config.go b/models/config.go index 9b21468..20edeca 100644 --- a/models/config.go +++ b/models/config.go @@ -30,6 +30,7 @@ type Config struct { CleanUp bool DefaultUserName string DefaultUserPassword string + PasswordSalt string SecureCookieHashKey string SecureCookieBlockKey string CustomLanguages map[string]string @@ -86,6 +87,7 @@ func readConfig() *Config { dbHost := LookupFatal("WAKAPI_DB_HOST") dbName := LookupFatal("WAKAPI_DB_NAME") dbPortStr := LookupFatal("WAKAPI_DB_PORT") + passwordSalt := LookupFatal("WAKAPI_PASSWORD_SALT") defaultUserName := LookupFatal("WAKAPI_DEFAULT_USER_NAME") defaultUserPassword := LookupFatal("WAKAPI_DEFAULT_USER_PASSWORD") dbPort, err := strconv.Atoi(dbPortStr) @@ -162,6 +164,7 @@ func readConfig() *Config { DbMaxConn: dbMaxConn, CleanUp: cleanUp, SecureCookie: secureCookie, + PasswordSalt: passwordSalt, DefaultUserName: defaultUserName, DefaultUserPassword: defaultUserPassword, CustomLanguages: customLangs, diff --git a/routes/public.go b/routes/public.go index 8498efc..f4b5fc7 100644 --- a/routes/public.go +++ b/routes/public.go @@ -76,7 +76,7 @@ func (h *IndexHandler) Login(w http.ResponseWriter, r *http.Request) { return } - if !utils.CheckPassword(user, login.Password) { + if !utils.CheckPassword(user, login.Password, h.config.PasswordSalt) { respondAlert(w, "invalid credentials", "", "", http.StatusUnauthorized) return } diff --git a/services/user.go b/services/user.go index d94b17f..749340c 100644 --- a/services/user.go +++ b/services/user.go @@ -1,10 +1,9 @@ package services import ( - "crypto/md5" - "encoding/hex" "github.com/jinzhu/gorm" "github.com/muety/wakapi/models" + "github.com/muety/wakapi/utils" uuid "github.com/satori/go.uuid" ) @@ -47,14 +46,14 @@ func (srv *UserService) GetAll() ([]*models.User, error) { } func (srv *UserService) CreateOrGet(signup *models.Signup) (*models.User, bool, error) { - pw := md5.Sum([]byte(signup.Password)) - pwString := hex.EncodeToString(pw[:]) - apiKey := uuid.NewV4().String() - u := &models.User{ ID: signup.Username, - ApiKey: apiKey, - Password: pwString, + ApiKey: uuid.NewV4().String(), + Password: signup.Password, + } + + if err := utils.HashPassword(u, srv.Config.PasswordSalt); err != nil { + return nil, false, err } result := srv.Db.FirstOrCreate(u, &models.User{ID: u.ID}) diff --git a/utils/auth.go b/utils/auth.go index a164802..d47aaea 100644 --- a/utils/auth.go +++ b/utils/auth.go @@ -1,11 +1,10 @@ package utils import ( - "crypto/md5" "encoding/base64" - "encoding/hex" "errors" "github.com/muety/wakapi/models" + "golang.org/x/crypto/bcrypt" "net/http" "regexp" "strings" @@ -55,11 +54,16 @@ func ExtractCookieAuth(r *http.Request, config *models.Config) (login *models.Lo return login, nil } -func CheckPassword(user *models.User, password string) bool { - passwordHash := md5.Sum([]byte(password)) - passwordHashString := hex.EncodeToString(passwordHash[:]) - if passwordHashString == user.Password { - return true - } - return false +func CheckPassword(user *models.User, password, salt string) bool { + err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password+salt)) + return err == nil +} + +// inplace +func HashPassword(u *models.User, salt string) error { + bytes, err := bcrypt.GenerateFromPassword([]byte(u.Password+salt), bcrypt.DefaultCost) + if err == nil { + u.Password = string(bytes) + } + return err } diff --git a/version.txt b/version.txt index 13175fd..3e1ad72 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.4.1 \ No newline at end of file +1.5.0 \ No newline at end of file