網(wǎng)站后臺(tái)系統(tǒng)設(shè)計(jì)

文檔修改歷史

版本號(hào) 修訂人 摘要 日期
1.0 鐘大 創(chuàng)建文檔 6.12
1.1 鐘大 完成文檔 6.13

1. 概述

1.1. 術(shù)語(yǔ)

術(shù)語(yǔ) 描述
SpringBoot 簡(jiǎn)化Spring應(yīng)用的初始搭建以及開發(fā)過(guò)程蔬顾。該框架使用了特定的方式來(lái)進(jìn)行配置,從而使開發(fā)人員不再需要定義樣板化的配置
MyBatis 基于Java的DB持久層框架
JWT Json web token文留, 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)埃儿。該token被設(shè)計(jì)為緊湊且安全的缀蹄,特別適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景
CSRF Cross Site Request Forgery攒射,跨站請(qǐng)求偽造
XSS Cross Site Scripting搁宾,跨站腳本漏洞

1.2. 需求背景

用Java完成一個(gè)網(wǎng)站的后臺(tái),實(shí)現(xiàn)注冊(cè)误证、登錄继薛、鑒權(quán)、登出的功能愈捅。

1.3. 目標(biāo)

1.3.1. 商業(yè)目標(biāo)

  • 3個(gè)月拉新用戶XX遏考,一年拉新用戶YY,MAU ZZ蓝谨;(運(yùn)營(yíng)數(shù)據(jù)待定)
  • 構(gòu)建賬號(hào)體系灌具,可以圍繞用戶賬號(hào)做運(yùn)營(yíng)活動(dòng),收集用戶數(shù)據(jù)像棘,比如手機(jī)用戶基本信息稽亏、行為習(xí)慣,為同類型用戶提供更個(gè)性缕题、定制化的內(nèi)容;
  • 有利于公司后期多條產(chǎn)品線的構(gòu)建胖腾,老帶新等產(chǎn)品整合烟零,實(shí)現(xiàn)用戶一個(gè)賬號(hào)登錄,多平臺(tái)使用咸作,節(jié)約用戶使用成本锨阿,有利于商業(yè)變現(xiàn)。

1.3.2. 系統(tǒng)目標(biāo)

  • 支持商業(yè)目標(biāo)的用戶容量记罚,通過(guò)分布式系統(tǒng)來(lái)負(fù)載均衡和動(dòng)態(tài)擴(kuò)容能力墅诡;
  • 注冊(cè)和登錄方式可橫向擴(kuò)展,比如快速支撐手機(jī)號(hào)碼桐智、郵箱末早、第三方平臺(tái)登錄等方式烟馅;
  • 后臺(tái)系統(tǒng)的安全性考慮,比如防密碼暴力破解然磷、防拖庫(kù)郑趁、不要明文傳輸存儲(chǔ)用戶密碼等。

1.4. 相關(guān)文檔

2. 業(yè)務(wù)流程和架構(gòu)分析

2.1. 整體業(yè)務(wù)流程

  • 如下圖,本期實(shí)現(xiàn)了賬密 注冊(cè)知举、登錄瞬沦、鑒權(quán)、登出 4大基礎(chǔ)功能雇锡;
  • 忘記密碼和重置密碼本次未實(shí)現(xiàn)逛钻,后一個(gè)迭代考慮加上該功能;
  • 手機(jī)號(hào)碼锰提、郵箱曙痘、第三方平臺(tái)登錄本期也未實(shí)現(xiàn),但是代碼和DB表結(jié)構(gòu)支撐快速擴(kuò)展實(shí)現(xiàn)立肘,待PD提需求边坤。
整體業(yè)務(wù)流程

2.2. 整體業(yè)務(wù)架構(gòu)

  • 用戶賬密注冊(cè)、登錄谅年、鑒權(quán)茧痒、登出等行為是賬號(hào)體系的功能反應(yīng),本文構(gòu)建基礎(chǔ)的賬號(hào)體系融蹂,支持多種賬號(hào)方式及第三方平臺(tái)的登錄方式旺订。
  • 要素包括用戶基本信息、行為習(xí)慣等超燃;
  • 我們經(jīng)常接觸到的賬號(hào)組合方式可能如下幾種区拳,本次實(shí)現(xiàn)用戶名&密碼的注冊(cè)方式,但是代碼和DB表結(jié)構(gòu)支持快速擴(kuò)展意乓。
    • 用戶名&密碼
    • 手機(jī)&密碼|驗(yàn)證碼
    • 郵箱&密碼|驗(yàn)證碼
    • 第三方平臺(tái)賬號(hào)(微信樱调、QQ、微博等)
    • 游客登錄
    • 后臺(tái)分配固定權(quán)限賬號(hào)登錄(后臺(tái)系統(tǒng)常見(jiàn))
整體業(yè)務(wù)架構(gòu)

2.3. 登錄注冊(cè)常見(jiàn)的漏洞和攻擊分析

本次需求分析了常見(jiàn)的漏洞攻擊,將在下面的“4. 業(yè)務(wù)用例分析”一節(jié)重點(diǎn)解決笆凌。

2.3.1. 常見(jiàn)漏洞

  • 賬戶密碼明文傳輸
  • 驗(yàn)證碼重復(fù)使用
  • 任意用戶注冊(cè)
  • 登錄賬號(hào)泄露
  • 弱賬號(hào)和密碼

2.3.2. 上述漏洞容易引發(fā)的攻擊方式

  • 撞庫(kù)
  • 中間人劫持賬戶密碼
  • 密碼定向破解
  • 批量注冊(cè)賬戶
  • 弱密碼
  • 驗(yàn)證碼爆破和繞過(guò)

2.3.3. 漏洞解決方案

  • 賬戶密碼明文傳輸 —— 密碼在前端通過(guò)公鑰加密傳輸圣猎,服務(wù)端用私鑰解碼后消費(fèi);
  • 驗(yàn)證碼重復(fù)使用 —— 每個(gè)驗(yàn)證碼使用后菩颖,在redis刪除样漆,防止重復(fù)使用;
  • 任意用戶注冊(cè) —— 每次注冊(cè)都要驗(yàn)證圖片驗(yàn)證碼晦闰,后續(xù)采用手機(jī)號(hào)碼和郵箱注冊(cè)放祟,解決方案更徹底;
  • 弱賬號(hào)和密碼 —— 限制賬號(hào)和密碼長(zhǎng)度呻右,密碼必須大小寫+數(shù)字跪妥。

2.4. 用例

用例圖

3. 系統(tǒng)架構(gòu)和領(lǐng)域模型

3.1. 系統(tǒng)整體架構(gòu)

  • 本次只使用mysql和redis來(lái)實(shí)現(xiàn)賬號(hào)密碼注冊(cè)和登錄,后續(xù)第三方平臺(tái)登錄可以接入微信和QQ声滥。
  • 比如 AccountController 依賴 AccountService眉撵,AccountService再依賴數(shù)據(jù)庫(kù)Mapper、Redis封裝類落塑、util類等纽疟。
系統(tǒng)架構(gòu)圖.png

3.2. 關(guān)鍵技術(shù)及第三方框架依賴

3.2.1. 開發(fā)框架

  • 引入SpringBoot搭建Java Web框架,簡(jiǎn)化Spring應(yīng)用的初始搭建以及開發(fā)過(guò)程憾赁。該框架使用了特定的方式來(lái)進(jìn)行配置污朽,從而使開發(fā)人員不再需要定義樣板化的配置。
  • MyBatis基于Java的DB持久層框架龙考,封裝底層Mapper訪問(wèn)DB蟆肆。

3.2.2. 數(shù)據(jù)庫(kù)技術(shù)

  • MySQL,通過(guò)關(guān)系數(shù)據(jù)庫(kù)持久化存儲(chǔ)用戶信息晦款、賬戶密碼等炎功。

3.2.3. 緩存技術(shù)

  • Redis緩存圖片驗(yàn)證碼,防止黑客暴力破解密碼缓溅。同時(shí)緩存登出token蛇损,解決token過(guò)期時(shí)效性問(wèn)題。

3.2.4. BCrypt密碼加密

Bcrypt加密原理:

  • 加密時(shí)坛怪,對(duì)于同一個(gè)密碼州藕,每次生成的hash是不同的,但是hash中包含了salt(hash產(chǎn)生過(guò)程:先隨機(jī)生成salt酝陈,salt跟password進(jìn)行hash)
  • 校驗(yàn)時(shí),從hash中取出salt毁涉,salt跟password進(jìn)行hash沉帮,得到的結(jié)果跟數(shù)據(jù)庫(kù)中提取的的hash進(jìn)行比對(duì)返回Boolean類型:true/false

Bcrypt與MD5進(jìn)行對(duì)比:

  • 首先MD5加密后存儲(chǔ)為32位,Bcrypt為60位。
  • 相對(duì)來(lái)說(shuō)BCrypt比MD5更安全穆壕,但是加密更慢待牵。(簡(jiǎn)單MD5加密后密碼一樣,數(shù)據(jù)庫(kù)當(dāng)中不同用戶存儲(chǔ)了相同的密碼值喇勋,那么當(dāng)知道其中一個(gè)用戶的密碼后就可以窺探出相同密碼的用戶缨该,BCrypt加密每次生成的密文是不一樣的。如:10dH/eH7tuzPCkaFSfm44QXePkTxbfuhguLwC.hPmZ2Sp81bcdWbL1W 即使得到了原文密碼川背,破譯其他用戶密碼的機(jī)率是很小的)贰拿。
  • Bcrypt加密有利也有弊,優(yōu)點(diǎn)是安全性較高熄云,弊端就是如果存儲(chǔ)量比較大膨更,性能消耗也是非常大的。但是用戶登錄注冊(cè)并不是一個(gè)高并發(fā)的接口缴允,所以影響并不會(huì)特別大荚守。

3.2.5. JWT實(shí)現(xiàn)鑒權(quán)

相比Session 的以下缺點(diǎn),JWT(Json Web Token)有很大優(yōu)勢(shì)练般,本次鑒權(quán)方案采用JWT矗漾。

3.2.5.1. Session的缺點(diǎn)
    1. cookie + session 在跨域場(chǎng)景表現(xiàn)不好。
    1. 如果是分布式部署, 需要做多機(jī)共享 session 機(jī)制薄料。
    1. 基于 cookie 的機(jī)制很容易被 CSRF敞贡。
    1. 查詢 session 信息可能會(huì)有數(shù)據(jù)庫(kù)查詢操作
3.2.5.2. JWT 工作原理
  • 瀏覽器端通過(guò) POST 請(qǐng)求傳遞用戶名和密碼給服務(wù)端, 服務(wù)端校驗(yàn)后, 如果成功將用戶 id 等其他信息作為 jwt 的有效載荷和頭部進(jìn)行 base64 編碼之后形成了一個(gè) jwt, 這段 jwt 就像以點(diǎn)分割的亂碼字符串。
  • 然后后端將這個(gè)字符串作為登錄成功的返回結(jié)果和 200 狀態(tài)碼返回給前端, 前端將其保存在 localstorage 和 sessionstorage 中, 每次請(qǐng)求都把這個(gè) jwt 字符串作為 http 頭里的 Authorization 加上 Bearer 和 jwt 字符串, 發(fā)送給后端, 后端檢查是否存在和有效性(例如檢查簽名正確與否, 令牌過(guò)期與否等), 驗(yàn)證通過(guò)后后端使用 jwt 中包含的用戶信息, 這段用戶信息保存在 jwt 的有效載荷中, 驗(yàn)證解密后就拿到用戶信息, 進(jìn)行其他業(yè)務(wù)邏輯, 返回業(yè)務(wù)結(jié)果。
  • 退出登錄的時(shí)候就刪除這段 jwt字符串即可。
JWT 工作原理
3.2.5.3. JWT vs. Session

可拓展性

session 多以redis,數(shù)據(jù)庫(kù)等保存在服務(wù)器中, 水平拓展方案下需要?jiǎng)?chuàng)建一個(gè)獨(dú)立中心的存儲(chǔ)店雅。所以 jwt 要比 session 要好一點(diǎn), jwt 可以無(wú)縫接入拓展, 因?yàn)榛趖oken 令牌的驗(yàn)證是無(wú)狀態(tài)的, 所以不需要在 session 中存儲(chǔ)用戶信息咆霜。

安全性

對(duì)于XSS跨站腳本攻擊. js 可以修改 JWT, 因?yàn)?JWT 通常放在 localstorage 或 cookie 中, js 可以修改這些變量, 所以也可以修改 JWT, 此時(shí)就會(huì)出現(xiàn) xss 攻擊, 比如壞人把代碼注入頁(yè)面中.
如何防范呢?可以通過(guò)簽名, 加密兩種方式. 還有不要把敏感信息放在 jwt 中, 防止密鑰泄露導(dǎo)致信息泄露。

RESTful API 方面

RESTful 架構(gòu)要求程序應(yīng)該是無(wú)狀態(tài)的盖淡。因此 session 這種有狀態(tài)的認(rèn)證方式, 顯然違反了 RESTful 的基本限制。

性能

jwt 性能不太好。因?yàn)樵诳蛻舳讼蚍?wù)端發(fā)出請(qǐng)求的時(shí)候, 可能有大量的用戶信息在 jwt 中, 那么每個(gè) http 請(qǐng)求都產(chǎn)生大量的開銷, 而 session 只用少量的開銷, 因?yàn)?session-id 比較小. jwt 是json, 而且包含了完整的信息, 所以可能是它的好幾倍大. jwt 是空間換時(shí)間啦桌,完整信息都在字符串里, 不需要查詢。而 session的缺點(diǎn)是每一個(gè)請(qǐng)求都要在服務(wù)器上查找 session, 因?yàn)槟玫降氖?session-id, 沒(méi)有完整的信息, 要用 id 查完整信息. 所以要消耗性能及皂。

有效期

無(wú)狀態(tài)是JWT的特點(diǎn)甫男,JWT是一次性的。想修改里面的內(nèi)容验烧,比如token續(xù)期板驳,就必須簽發(fā)一個(gè)新的JWT。最簡(jiǎn)單的一種方式是每次請(qǐng)求刷新JWT碍拆,即每個(gè)HTTP請(qǐng)求都返回一個(gè)新的JWT若治。這個(gè)方法不僅暴力不優(yōu)雅慨蓝,而且每次請(qǐng)求都要做JWT的加密解密,會(huì)帶來(lái)性能問(wèn)題端幼。另一種方法是在redis中單獨(dú)為每個(gè)JWT設(shè)置過(guò)期時(shí)間礼烈,每次訪問(wèn)時(shí)刷新JWT的過(guò)期時(shí)間,本文采用方法二婆跑。

3.3. 系統(tǒng)依賴關(guān)系

  • 前端實(shí)現(xiàn)注冊(cè)此熬、登錄、會(huì)員中心等頁(yè)面功能滑进,同時(shí)調(diào)用后端API進(jìn)行功能交互邏輯犀忱;
  • 后臺(tái)系統(tǒng)采用SpringBoot+Mybatis框架實(shí)現(xiàn)注冊(cè)、登錄等邏輯處理郊供;
  • MySQL的關(guān)系數(shù)據(jù)庫(kù)存儲(chǔ)用戶的賬號(hào)峡碉、密碼、用戶信息驮审;
  • Redis保存圖片驗(yàn)證碼和校驗(yàn)鲫寄,同時(shí)保存失效后的JWT token。
應(yīng)用系統(tǒng)依賴關(guān)系圖.png

3.4. 領(lǐng)域模型

3.4.1. MySQL數(shù)據(jù)庫(kù)模型

MySQL數(shù)據(jù)庫(kù)模型

表DDL如下疯淫,user表維護(hù)用戶基本信息地来,local_auth支持賬密、手機(jī)號(hào)熙掺、郵箱驗(yàn)證碼等多種本地實(shí)現(xiàn)的登錄方式未斑,oauth支持微信、QQ币绩、微博等開放平臺(tái)的第三方登錄蜡秽。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `nickname` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用戶昵稱',
  `gender` varchar(2) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '性別',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_nickname` (`nickname`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `local_auth`;
CREATE TABLE `local_auth`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `user_id` int(11) NOT NULL COMMENT 'user表主鍵id',
  `login_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '登錄id',
  `login_type` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '登錄id類型,用戶名缆镣、手機(jī)號(hào)碼芽突、郵箱',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用戶hash密碼',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_user_id` (`user_id`) USING BTREE,
  UNIQUE KEY `idx_login_id` (`login_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `oauth`;
CREATE TABLE `oauth`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `user_id` int(11) NOT NULL COMMENT 'user表主鍵id',
  `oauth_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '第三方平臺(tái)id',
  `oauth_type` varchar(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '第三方平臺(tái)標(biāo)識(shí)(qq、wechat董瞻、weibo)',
  `access_token` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '第三方獲取的access_token,校驗(yàn)使用',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_user_id` (`user_id`) USING BTREE,
  UNIQUE KEY `idx_oauth_id_type` (`oauth_id`, `oauth_type`) USING BTREE,
  KEY `idx_access_token` (`access_token`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;

3.4.2. Redis模型

  • 賬密登錄的圖片驗(yàn)證碼校驗(yàn)通過(guò)Redis 的key-value的String實(shí)現(xiàn)寞蚌,支持set/get/del/getExpire等。
Redis K-V模型

3.4.3. 代碼結(jié)構(gòu)UML

  • 展示層的Controller 通過(guò)聚合引入業(yè)務(wù)層的Service服務(wù)钠糊;
  • 業(yè)務(wù)層登錄和注冊(cè)的驗(yàn)證碼和密碼校驗(yàn)通過(guò)接口 VerificationService 來(lái)繼承 賬密挟秤、手機(jī)號(hào)、郵箱地址等多種方式的快速擴(kuò)展抄伍。
登錄注冊(cè)登出UML

3.4.4. 狀態(tài)機(jī)

不涉及

4. 業(yè)務(wù)用例分析

4.1. 賬密注冊(cè)

4.1.1. 用例描述

支持賬號(hào)和密碼注冊(cè)艘刚,使用圖片驗(yàn)證碼防止批量注冊(cè)。

4.1.2. 接口說(shuō)明

4.1.2.1. 獲取圖片驗(yàn)證碼接口說(shuō)明
  • 獲取圖片驗(yàn)證碼API: /api/code/genImageCode截珍, Class/Method: VerificationCodeController#genImageCode
  • 不能鑒權(quán)昔脯,GET請(qǐng)求返回Content-Type: image/jpeg啄糙,前端直接展示圖片。
4.1.2.2. 獲取公鑰接口說(shuō)明
  • 獲取公鑰API: /api/account/getPublicKey云稚, Class/Method: AccountController#getPublicKey

輸入?yún)?shù):
無(wú)入?yún)?/p>

輸出參數(shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
code Integer 結(jié)果處理碼,200成功沈堡,其他code表示多種失敗場(chǎng)景
message String 結(jié)果碼的文案描述
data String 公鑰字符串

錯(cuò)誤碼:

code錯(cuò)誤碼 對(duì)客文案 解釋
550 系統(tǒng)異常 系統(tǒng)處理未知異常

響應(yīng)結(jié)果樣例:

{
    "code": 200,
    "message": "獲取公鑰成功",
    "data": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCf5nUMwxDdYiVtfpYCfkNzxuh5ASHoRLpCQjdWoZmnpaBOK9pwPT3knhLGXYTLMUZNRMgvn81dzJz4HCgNVH1m8tYtvhdwOUSw4V82LcpwYVE2mnWPkrmf3uSy+kzxWZnZjgSptk7YmaHQByfgv+ZyJKPKkmGLXclrhmxqsl5alQIDAQAB"
}
4.1.2.3. 賬密注冊(cè)接口說(shuō)明
  • 注冊(cè)API: /api/account/register 静陈, Class/Method:AccountController#register

輸入?yún)?shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
loginId String 登錄賬號(hào),可能是賬號(hào)诞丽、手機(jī)號(hào)鲸拥、郵箱地址
loginType String 登錄類型,username/mobile/email
password String 公鑰加密的用戶密碼
verificationCode String 圖片碼 or 短信驗(yàn)證碼 or 郵箱驗(yàn)證碼

入?yún)永?/strong>

{
    "loginId": "aa123456",
    "loginType": "username",
    "password": "ewD+yhHSWpmqfbh/zbLKGEu70rJWdF8Fo6c4roajzUUhk8DqKmcrAhzh+NokKMUw3TZhN4ejo7huXFsIUuUy5D6AY1SrqkFTh5mmsQjyJ3UsCAuQZSYwNWVpwjbl/XZDbq1BMeyA0nD1hIHcZY5dqEqOqu3P4bN5WdZa1nMLM64=",
    "verificationCode": "GSMB"
}

輸出參數(shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
code Integer 結(jié)果處理碼僧免,200成功刑赶,其他code表示多種失敗場(chǎng)景
message String 結(jié)果碼的文案描述
data UserResponseDTO 公鑰字符串

UserResponseDTO

參數(shù)名稱 類型 是否必傳 說(shuō)明
userId Long user id
nickname String 用戶昵稱
token String 鑒權(quán)token

響應(yīng)結(jié)果樣例:

{"code":200,"data":{"nickname":"wechat_abc123456","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiNiIsImYzZDgwNDYxLTRlMDItNDRjMy05NzhlLWM3ZDQ4MGVhNGViMSJdLCJleHAiOjE2MjM2NTY1MzIsImlhdCI6MTYyMzU3MDEzMn0.mYo0Tk9Pd0E4xYP0SOWKAbuugg2ao5pmIbvCOx-ewQM","userId":6},"message":"登錄成功"} 

錯(cuò)誤碼:

code錯(cuò)誤碼 對(duì)客文案 解釋
550 系統(tǒng)異常 系統(tǒng)處理未知異常
452 用戶已存在,不能注冊(cè) 數(shù)據(jù)庫(kù)已存在該loginId
551 注冊(cè)失敗 插入user入庫(kù)失敗

4.1.3. 外部依賴接口

  • MySQL: insert/update/select
  • Redis:set/get/del

4.1.4. 業(yè)務(wù)流程說(shuō)明

4.1.4.1. 交互時(shí)序圖
  • 前端獲取服務(wù)端的公鑰加密 賬戶密碼懂衩,防止明文傳輸被竊取撞叨,更加安全辦法再啟用HTTPS防止竊聽(tīng)和篡改加密的密碼。
  • 用戶提交賬密時(shí)浊洞,前端賬號(hào)長(zhǎng)度和密碼長(zhǎng)度牵敷,要求密碼必須大小寫+數(shù)字,后端二次校驗(yàn)法希。
  • 不能明文密碼入庫(kù)枷餐,防止密碼泄露,通過(guò)加鹽hash后入庫(kù)苫亦,再次防止彩虹表等方式的暴力破解毛肋。
  • 提交注冊(cè)的賬號(hào)密碼需要輸入驗(yàn)證碼,防止機(jī)器批量注冊(cè)賬號(hào)或者破解密碼屋剑。
賬密注冊(cè)時(shí)序圖

4.1.5. 非功能點(diǎn)分析

4.1.5.1. 冪等性設(shè)計(jì)
  • 1润匙、第一次校驗(yàn) 圖片驗(yàn)證碼成功,刪除redis驗(yàn)證碼饼丘,如果重復(fù)提交驗(yàn)證碼趁桃,系統(tǒng)報(bào)錯(cuò),防止重復(fù)注冊(cè)肄鸽;
  • 2卫病、注冊(cè)賬號(hào)在數(shù)據(jù)庫(kù)的表是唯一鍵,不能重復(fù)插入典徘,初步達(dá)到冪等效果蟀苛。
  • 3、更好的方案是token機(jī)制逮诲,防止頁(yè)面重復(fù)提交帜平,但是囿于工作量幽告,本文暫未實(shí)現(xiàn)。
4.1.5.2. 安全性分析

SQL注入攻擊

  • SQL注入會(huì)造成拖庫(kù)裆甩,原因絕大多數(shù)是直接使用輸入?yún)?shù)拼接SQL語(yǔ)句造成冗锁,防范方法:使用預(yù)編譯語(yǔ)句(PreparedStatement):可以加速SQL執(zhí)行,也可以防止SQL注入嗤栓。

數(shù)據(jù)庫(kù)權(quán)限配置

  • 防止越權(quán)入侵服務(wù)器冻河,同時(shí)也要安裝入侵檢測(cè)系統(tǒng),監(jiān)控告警茉帅。

公私鑰保存好

  • 防止密碼加密的公私鑰泄露導(dǎo)致用戶密碼被破解泄露叨叙。

4.2. 賬密登錄

4.2.1. 用例描述

支持賬號(hào)和密碼登錄,使用圖片驗(yàn)證碼防止登錄密碼的暴力破解堪澎。

4.2.2. 接口說(shuō)明

4.2.2.1. 獲取圖片驗(yàn)證碼接口說(shuō)明
  • 同 4.1.2.1
4.2.2.2. 獲取公鑰接口說(shuō)明
  • 同4.1.2.2
4.2.2.3. 賬密登錄接口說(shuō)明
  • 注冊(cè)API: /api/account/login擂错, Class/Method:AccountController#login

輸入?yún)?shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
loginId String 登錄賬號(hào),可能是賬號(hào)樱蛤、手機(jī)號(hào)钮呀、郵箱地址
loginType String 登錄類型,username/mobile/email
password String 公鑰加密的用戶密碼
verificationCode String 圖片碼 or 短信驗(yàn)證碼 or 郵箱驗(yàn)證碼

入?yún)永?/strong>

{
    "loginId": "aa123456",
    "loginType": "username",
    "password": "ewD+yhHSWpmqfbh/zbLKGEu70rJWdF8Fo6c4roajzUUhk8DqKmcrAhzh+NokKMUw3TZhN4ejo7huXFsIUuUy5D6AY1SrqkFTh5mmsQjyJ3UsCAuQZSYwNWVpwjbl/XZDbq1BMeyA0nD1hIHcZY5dqEqOqu3P4bN5WdZa1nMLM64=",
    "verificationCode": "GSMB"
}

輸出參數(shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
code Integer 結(jié)果處理碼刹悴,200成功行楞,其他code表示多種失敗場(chǎng)景
message String 結(jié)果碼的文案描述
data UserResponseDTO 公鑰字符串

UserResponseDTO

參數(shù)名稱 類型 是否必傳 說(shuō)明
userId Long user id
nickname String 用戶昵稱
token String 鑒權(quán)token

響應(yīng)結(jié)果樣例:

{"code":200,"data":{"nickname":"wechat_abc123456","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiNiIsImYzZDgwNDYxLTRlMDItNDRjMy05NzhlLWM3ZDQ4MGVhNGViMSJdLCJleHAiOjE2MjM2NTY1MzIsImlhdCI6MTYyMzU3MDEzMn0.mYo0Tk9Pd0E4xYP0SOWKAbuugg2ao5pmIbvCOx-ewQM","userId":6},"message":"登錄成功"} 

錯(cuò)誤碼:

code錯(cuò)誤碼 對(duì)客文案 解釋
550 系統(tǒng)異常 系統(tǒng)處理未知異常
452 用戶已存在,不能注冊(cè) 數(shù)據(jù)庫(kù)已存在該loginId
551 注冊(cè)失敗 插入user入庫(kù)失敗

4.2.3. 外部依賴接口

  • MySQL: insert/update/select
  • Redis:set/get/del

4.2.4. 業(yè)務(wù)流程說(shuō)明

4.2.4.1. 交互時(shí)序圖
  • 前端獲取服務(wù)端的公鑰加密 賬戶密碼土匀,防止明文傳輸被竊取子房,更加安全辦法再啟用HTTPS防止竊聽(tīng)和篡改加密的密碼。
  • 用戶提交賬密時(shí)就轧,前端賬號(hào)長(zhǎng)度和密碼長(zhǎng)度证杭,要求密碼必須大小寫+數(shù)字,后端二次校驗(yàn)妒御。
  • 不能明文密碼入庫(kù)解愤,防止密碼泄露,通過(guò)加鹽hash后入庫(kù)乎莉,再次防止彩虹表等方式的暴力破解送讲。
  • 提交登錄的賬號(hào)密碼需要輸入驗(yàn)證碼,防止機(jī)器批量注冊(cè)賬號(hào)或者破解密碼惋啃。
賬密登錄時(shí)序圖

4.2.5. 非功能點(diǎn)分析

4.2.5.1. 冪等性設(shè)計(jì)
  • 登錄接口主要是校驗(yàn)密碼和驗(yàn)證碼哼鬓,無(wú)冪等性風(fēng)險(xiǎn)。
4.2.5.2. 安全性分析
  • 同 4.2.5.1. 的安全性分析边灭。

4.3. 鑒權(quán)

4.3.1. 用例描述

沒(méi)有在Controller方法打注解@PassToken异希,一律鑒權(quán)jwt token。

4.3.2. 接口說(shuō)明

無(wú)對(duì)外API

4.3.3. 外部依賴接口

  • MySQL: insert/update/select
  • Redis:set/get/del

4.3.4. 業(yè)務(wù)流程說(shuō)明

4.3.4.1. JWT組成

JWT 由三部分組成绒瘦,分別是 header(頭部)称簿,payload(載荷)扣癣,signature(簽證) 這三部分以小數(shù)點(diǎn)連接起來(lái)。

例如使用名為 jwt-token 的cookie來(lái)存儲(chǔ) JWT 例如:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiMTIzNDU2IiwiMDI5ZDdlNDItZDAxYy00ZjQ4LTk3ZTgtNGE2NzNhZDQ4M2Y4Il0sImV4cCI6MTYyMzYzOTU5NSwiaWF0IjoxNjIzNTUzMTk1fQ.gG7QRGPCnOY0pyRbHPcULwXY0duh2YdIR-HHMFDbM1Q

使用.分割值可以得到三部分組成元素憨降,按照順序分別為:

header:

  • 值:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
  • Base64 解碼:
{"typ":"JWT","alg":"HS256"}

payload:

  • eyJhdWQiOlsiMTIzNDU2IiwiMDY3MDEzZDEtOWU2ZS00ZmQ4LWE3MTMtMmMyOTcyNzQzNTQxIl0sImV4cCI6MTYyMzYzOTg3OSwiaWF0IjoxNjIzNTUzNDc5fQ
  • Base64 解碼:
{
    "aud": ["123456", "067013d1-9e6e-4fd8-a713-2c2972743541"],
    "exp": 1623639879,
    "iat": 1623553479
}

signature:

  • 值:gG7QRGPCnOY0pyRbHPcULwXY0duh2YdIR-HHMFDbM1Q
  • 服務(wù)端根據(jù)header和payload計(jì)算出 signature父虑,和要校驗(yàn)的JWT中的 signature 部分進(jìn)行對(duì)比,如果 signature 部分相等則是一個(gè)有效的 JWT券册。
4.3.4.2. 交互時(shí)序圖
  • 使用SpringBoot攔截器技術(shù) AuthenticationInterceptor 來(lái)實(shí)現(xiàn)频轿;
  • 在redis中單獨(dú)為每個(gè)JWT設(shè)置過(guò)期時(shí)間,每次訪問(wèn)時(shí)如果過(guò)期時(shí)間短于30分鐘烁焙,刷新JWT的過(guò)期時(shí)間。
鑒權(quán)時(shí)序圖

4.3.5. 非功能點(diǎn)分析

4.3.5.1. 冪等性設(shè)計(jì)
  • 不涉及
4.3.5.2. 安全性分析
  • 不要把敏感信息放在 jwt 中耕赘。
  • 防止密鑰泄露導(dǎo)致信息泄露骄蝇。

4.4. 退出登錄

4.4.1. 用例描述

支持用戶主動(dòng)登出賬號(hào),系統(tǒng)清除登錄態(tài)token操骡。

4.4.2. 接口說(shuō)明

4.4.2.1. 登出接口說(shuō)明
  • 登出API: /api/account/logout九火, Class/Method:AccountController#logout

輸入?yún)?shù):
無(wú)入?yún)?/p>

輸出參數(shù):

參數(shù)名稱 類型 是否必傳 說(shuō)明
code Integer 結(jié)果處理碼,200成功册招,其他code表示多種失敗場(chǎng)景
message String 結(jié)果碼的文案描述

響應(yīng)結(jié)果樣例:

{"code":200,"message":"登出成功"} 

錯(cuò)誤碼:

code錯(cuò)誤碼 對(duì)客文案 解釋
550 系統(tǒng)異常 系統(tǒng)處理未知異常

4.4.3. 外部依賴接口

  • Redis:set/get/del

4.4.4. 業(yè)務(wù)流程說(shuō)明

4.4.4.1. 交互時(shí)序圖
  • 登出用戶需要到redis清除userId保存的jwt token岔激。
退出登錄時(shí)序圖

4.4.5. 非功能點(diǎn)分析

4.4.5.1. 冪等性設(shè)計(jì)
  • 退出登錄會(huì)清除redis的key,支持冪等性是掰。
4.4.5.2. 安全性分析
  • 登出用戶需要到redis清除userId保存的jwt token虑鼎。

5. 配置類專項(xiàng)分析

5.1. 秘鑰配置

  • 用戶密碼的加密公私鑰需要安全保存,比如阿里采用KMI系統(tǒng)保存键痛;
  • JWT Token生成的秘鑰也要安全保存炫彩。

5.2. 數(shù)據(jù)庫(kù)鏈接配置

datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/wechat?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
    username: root
    password:

5.3. Redis鏈接配置

redis:
    database: 0   # Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0)
    host: 127.0.0.1  # Redis服務(wù)器地址
    port: 6379         # Redis服務(wù)器連接端口
    password:    # Redis服務(wù)器連接密碼(默認(rèn)為空)
    max-wait: 30000    # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)
    max-active: 100   # 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
    max-idle: 20     # 連接池中的最大空閑連接
    min-idle: 0     # 連接池中的最小空閑連接
    timeout: 5000  # 連接超時(shí)時(shí)間(毫秒)

6. 兼容性分析

全部新增功能,無(wú)兼容性風(fēng)險(xiǎn)絮短。

7. 對(duì)周邊系統(tǒng)影響分析

新增功能江兢,無(wú)原有功能影響。

8. 后續(xù)計(jì)劃

8.1. 運(yùn)營(yíng)

  • 注冊(cè)送紅包丁频,定期登錄送積分杉允,拉新促活。
  • 開放給更多公司的業(yè)務(wù)線使用席里,作為通用的注冊(cè)登錄平臺(tái)叔磷,用戶一個(gè)賬號(hào),多個(gè)業(yè)務(wù)使用胁勺。

8.2. 功能增強(qiáng)

  • 支持主動(dòng)修改密碼 和 忘記密碼的充值密碼世澜;
  • 手機(jī)號(hào)碼、郵箱署穗、第三方平臺(tái)登錄寥裂。

8.3. 安全加固

  • 異地登錄的安全風(fēng)險(xiǎn)管控嵌洼;
  • 登錄設(shè)備的更換風(fēng)險(xiǎn);
  • 限制用戶當(dāng)日密碼登錄次數(shù)封恰,防止攻擊者定向破解該用戶的密碼麻养;
  • 引入高性能設(shè)備防止DDoS攻擊;

8.4. 分布式系統(tǒng)

  • 入口負(fù)載均衡诺舔,比如引入Nginx鳖昌;
  • 增加熔斷、限流低飒、降級(jí)等分布式管控能力许昨;
  • 分庫(kù)分表;
  • 異步消費(fèi)設(shè)計(jì):登錄注冊(cè)等操作后褥赊,異步記錄用戶操作日志糕档,通知下游發(fā)積分或者紅包等;
  • 靈活多樣的監(jiān)控告警:業(yè)務(wù)層拌喉、系統(tǒng)層速那、機(jī)器性能等。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尿背,一起剝皮案震驚了整個(gè)濱河市端仰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌田藐,老刑警劉巖荔烧,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異坞淮,居然都是意外死亡茴晋,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門回窘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诺擅,“玉大人,你說(shuō)我怎么就攤上這事啡直∷赣浚” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵酒觅,是天一觀的道長(zhǎng)撮执。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舷丹,這世上最難降的妖魔是什么抒钱? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上谋币,老公的妹妹穿的比我還像新娘仗扬。我一直安慰自己,他們只是感情好蕾额,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布早芭。 她就那樣靜靜地躺著,像睡著了一般诅蝶。 火紅的嫁衣襯著肌膚如雪退个。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天调炬,我揣著相機(jī)與錄音语盈,去河邊找鬼。 笑死缰泡,一個(gè)胖子當(dāng)著我的面吹牛黎烈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匀谣,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼资溃!你這毒婦竟也來(lái)了武翎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤溶锭,失蹤者是張志新(化名)和其女友劉穎宝恶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趴捅,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垫毙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拱绑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片综芥。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖猎拨,靈堂內(nèi)的尸體忽然破棺而出膀藐,到底是詐尸還是另有隱情,我是刑警寧澤红省,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布额各,位于F島的核電站,受9級(jí)特大地震影響吧恃,放射性物質(zhì)發(fā)生泄漏虾啦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望傲醉。 院中可真熱鬧蝇闭,春花似錦、人聲如沸需频。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昭殉。三九已至苞七,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挪丢,已是汗流浹背蹂风。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乾蓬,地道東北人惠啄。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像任内,于是被迫代替她去往敵國(guó)和親撵渡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容