From 39620190d2610633c3999934b8c1ba8154ba536f Mon Sep 17 00:00:00 2001 From: chenruilong Date: Thu, 27 Oct 2022 14:59:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=86=E7=A0=81=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=20(sha256)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uni-id-co/lib/utils/login.js | 8 +- .../uni-id-co/lib/utils/password.js | 128 ++++++++++++------ .../uni-id-co/lib/utils/register.js | 10 +- .../module/account/reset-pwd-by-email.js | 11 +- .../module/account/reset-pwd-by-sms.js | 11 +- .../uni-id-co/module/account/update-pwd.js | 15 +- .../uni-id-co/module/admin/add-user.js | 8 +- .../uni-id-co/module/admin/update-user.js | 11 +- 8 files changed, 119 insertions(+), 83 deletions(-) diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js index 8ef5c40..e0ec38f 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/login.js @@ -78,16 +78,16 @@ async function preLoginWithPassword (params = {}) { } } const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret + passwordHash: userRecord.password, + passwordSecret: this.config.passwordSecret, + passwordSecretVersion: userRecord.password_secret_version }) const { success: checkPasswordSuccess, refreshPasswordInfo } = passwordUtils.checkUserPassword({ - password, - passwordHash: userRecord.password, - passwordSecretVersion: userRecord.password_secret_version + password }) if (!checkPasswordSuccess) { // 更新用户ip对应的密码错误记录 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js index 19ee920..0d6e785 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/password.js @@ -3,27 +3,62 @@ const { } = require('../../common/utils') const crypto = require('crypto') +const PasswordMethodMaps = { + A: 'hmac-sha1', + B: 'hmac-sha256' +} +const PasswordMethodFlagMaps = Object.keys(PasswordMethodMaps).reduce((res, item) => { + res[PasswordMethodMaps[item]] = item + return res +}, {}) + const PasswordHashMethod = { 'hmac-sha1': function (content, secret) { const hmac = crypto.createHmac('sha1', secret.toString('ascii')) hmac.update(content) return hmac.digest('hex') + }, + 'hmac-sha256': function (content, secret) { + const hmac = crypto.createHmac('sha256', secret) + hmac.update(content) + return hmac.digest('hex') } } class PasswordUtils { constructor ({ - passwordSecret + passwordHash = '', + passwordSecret = '', + passwordSecretVersion } = {}) { - const passwordSecretType = getType(passwordSecret) - if (passwordSecretType === 'array') { - this.passwordSecret = passwordSecret.sort((a, b) => { - return a.version - b.version - }) - } else if (passwordSecretType === 'string') { - this.passwordSecret = [{ value: passwordSecret }] - } else { - throw new Error('Invalid password secret') + this.passwordHash = passwordHash + this.passwordSecretVersion = passwordSecretVersion + + this.password = this.parsePassword() + + // 老版本会存在 passwordSecret + if (passwordSecret) { + const passwordSecretType = getType(passwordSecret) + if (passwordSecretType === 'array') { + this.passwordSecret = passwordSecret.sort((a, b) => { + return a.version - b.version + }) + } else if (passwordSecretType === 'string') { + this.passwordSecret = [{ value: passwordSecret }] + } + } + } + + parsePassword () { + const [algorithmKey = '', cost = 0, hashStr = ''] = this.passwordHash.split('$').filter(key => key) + const algorithm = PasswordMethodMaps[algorithmKey] || null + const salt = hashStr.substring(0, Number(cost)) + const hash = hashStr.substring(Number(cost)) + + return { + algorithm, + salt, + hash } } @@ -51,37 +86,34 @@ class PasswordUtils { checkUserPassword (params = {}) { const { password, - passwordHash: passwordHashToCheck, - passwordSecretVersion, autoRefresh = true } = params - const currentPasswordSecret = this.getSecretByVersion({ - version: passwordSecretVersion - }) - if (!currentPasswordSecret) { - throw new Error('Invalid password version') + + let passwordHash + + if (this.password.algorithm) { + passwordHash = PasswordHashMethod[this.password.algorithm](password, this.password.salt) + } else { + const hash = this.generatePasswordHash({ + password + }) + + passwordHash = hash.passwordHash } - const { - value: passwordSecret - } = currentPasswordSecret - const { - passwordHash - } = this.generatePasswordHash({ - password, - passwordSecret, - passwordSecretVersion - }) - if (passwordHashToCheck !== passwordHash) { + + if (passwordHash !== this.password.hash && passwordHash !== this.passwordHash) { return { success: false } } let refreshPasswordInfo - if (autoRefresh && passwordSecretVersion !== this.getLastestSecret().version) { + if (autoRefresh) { refreshPasswordInfo = this.generatePasswordHash({ - password + password, + forceUseInternal: true }) } + return { success: true, refreshPasswordInfo @@ -91,8 +123,7 @@ class PasswordUtils { generatePasswordHash (params = {}) { let { password, - passwordSecret, - passwordSecretVersion + forceUseInternal = false } = params if (getType(password) !== 'string') { throw new Error('Invalid password') @@ -101,14 +132,35 @@ class PasswordUtils { if (!password) { throw new Error('Invalid password') } - if (!passwordSecret) { - const lastestSecret = this.getLastestSecret() - passwordSecret = lastestSecret.value - passwordSecretVersion = lastestSecret.version + + // 没有 passwordSecret,使用内置算法(新版) + if (forceUseInternal || !this.passwordSecret) { + // 默认使用 sha256 加密算法 + const salt = crypto.randomBytes(10).toString('hex') + const sha256Hash = PasswordHashMethod['hmac-sha256'](password, salt) + const algorithm = PasswordMethodFlagMaps['hmac-sha256'] + // B 为固定值,对应 PasswordMethodMaps 中的 sha256算法 + // hash 格式 $[PasswordMethodFlagMapsKey]$[salt size]$[salt][Hash] + const hashStr = `$${algorithm}$${salt.length}$${salt}${sha256Hash}` + + return { + passwordHash: hashStr + } + } + + // 旧版本兼容 + let secret + if (this.passwordSecretVersion) { + secret = this.getSecretByVersion({ + version: this.passwordSecretVersion + }) + } else { + secret = this.getLastestSecret() } + return { - passwordHash: PasswordHashMethod['hmac-sha1'](password, passwordSecret), - version: passwordSecretVersion + passwordHash: PasswordHashMethod['hmac-sha1'](password, secret.value), + version: secret.version } } } diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js index 2ecd186..1683477 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/register.js @@ -53,18 +53,14 @@ async function preRegisterWithPassword(params = {}) { await preRegister.call(this, { user }) - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) + const passwordUtils = new PasswordUtils() const { - passwordHash, - version + passwordHash } = passwordUtils.generatePasswordHash({ password }) const extraData = { - password: passwordHash, - password_secret_version: version + password: passwordHash } return { user, diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js index 914a05e..42d1f12 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-email.js @@ -12,7 +12,7 @@ const { userCollection, EMAIL_SCENE, CAPTCHA_SCENE, - LOG_TYPE + LOG_TYPE, dbCmd } = require('../../common/constants') const { findUser @@ -92,17 +92,14 @@ module.exports = async function (params = {}) { } const { _id: uid } = userMatched[0] const { - passwordHash, - version - } = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }).generatePasswordHash({ + passwordHash + } = new PasswordUtils().generatePasswordHash({ password }) // 更新用户密码 await userCollection.doc(uid).update({ password: passwordHash, - password_secret_version: version, + password_secret_version: dbCmd.remove(), valid_token_date: Date.now() }) diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js index 646834f..2052277 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/reset-pwd-by-sms.js @@ -12,7 +12,7 @@ const { userCollection, SMS_SCENE, CAPTCHA_SCENE, - LOG_TYPE + LOG_TYPE, dbCmd } = require('../../common/constants') const { findUser @@ -92,17 +92,14 @@ module.exports = async function (params = {}) { } const { _id: uid } = userMatched[0] const { - passwordHash, - version - } = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }).generatePasswordHash({ + passwordHash + } = new PasswordUtils().generatePasswordHash({ password }) // 更新用户密码 await userCollection.doc(uid).update({ password: passwordHash, - password_secret_version: version, + password_secret_version: dbCmd.remove(), valid_token_date: Date.now() }) diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js index 7329b73..fa4b5cd 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/account/update-pwd.js @@ -1,5 +1,5 @@ const { - userCollection + userCollection, dbCmd } = require('../../common/constants') const { ERROR @@ -32,16 +32,18 @@ module.exports = async function (params = {}) { newPassword } = params const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret + passwordHash: userRecord.password, + passwordSecret: this.config.passwordSecret, + passwordSecretVersion: userRecord.password_secret_version }) + const { success: checkPasswordSuccess } = passwordUtils.checkUserPassword({ password: oldPassword, - passwordHash: userRecord.password, - passwordSecretVersion: userRecord.password_secret_version, autoRefresh: false }) + if (!checkPasswordSuccess) { throw { errCode: ERROR.PASSWORD_ERROR @@ -49,15 +51,14 @@ module.exports = async function (params = {}) { } const { - passwordHash, - version + passwordHash } = passwordUtils.generatePasswordHash({ password: newPassword }) await userCollection.doc(uid).update({ password: passwordHash, - password_secret_version: version, + password_secret_version: dbCmd.remove(), valid_token_date: Date.now() // refreshToken时会校验,如果创建token时间在此时间点之前,则拒绝下发新token,返回token失效错误码 }) // 执行更新密码操作后客户端应将用户退出重新登录 diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js index 6baa575..90b3293 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/add-user.js @@ -82,19 +82,15 @@ module.exports = async function (params = {}) { errCode: ERROR.ACCOUNT_EXISTS } } - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) + const passwordUtils = new PasswordUtils() const { - passwordHash, - version + passwordHash } = passwordUtils.generatePasswordHash({ password }) const data = { username, password: passwordHash, - password_secret_version: version, dcloud_appid: authorizedApp || [], nickname, role: role || [], diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js index 5dc1b29..2126466 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/admin/update-user.js @@ -5,7 +5,7 @@ const { ERROR } = require('../../common/error') const { - userCollection + userCollection, dbCmd } = require('../../common/constants') const PasswordUtils = require('../../lib/utils/password') @@ -106,18 +106,15 @@ module.exports = async function (params = {}) { } if (password) { - const passwordUtils = new PasswordUtils({ - passwordSecret: this.config.passwordSecret - }) + const passwordUtils = new PasswordUtils() const { - passwordHash, - version + passwordHash } = passwordUtils.generatePasswordHash({ password }) data.password = passwordHash - data.password_secret_version = version + data.password_secret_version = dbCmd.remove() } await userCollection.doc(uid).update(data) -- GitLab