很多团队谈安全,喜欢先谈 WAF、JWT、HTTPS、堡垒机、验证码,但这些都只是安全体系中的"零件"。真正的系统安全架构,解决的从来不是某一个点,而是一整条系统链路上的信任建立、风险控制与故障收敛。
在现代分布式系统与云原生架构全面普及的今天,系统已经不再是一个简单的单体应用,而是由客户端、接入层、认证中心、网关、微服务、缓存、数据库、消息队列、第三方平台、运维交付链路共同组成的复杂系统。
系统一旦复杂,安全问题就不再只是"有没有 SQL 注入"这么简单,而会扩展为:身份是否可信、权限是否越界、链路是否会被篡改、内部服务是否可以互相伪造、数据是否会被拖库、业务是否会被刷穿、攻击是否能够被发现与止损。
也正因为如此,系统安全架构设计的本质,不是堆安全产品,而是在完整链路上建立一套 可认证、可授权、可保护、可审计、可恢复的信任体系 。
为什么今天的系统安全,已经不能只靠"补漏洞"来解决?
很多人理解安全,往往停留在"上线前扫一遍漏洞"、"网关前面挂个 WAF"、"登录加个验证码"这种思路上。这个思路在简单系统里也许还能勉强应付,但在现代架构下很快就会失效。
原因很简单:系统复杂度上来了,攻击面也会跟着指数级扩大。
过去单体时代,一个系统架构可能只是:一个 Web 服务、一个数据库、一个登录入口、少量内部接口,确实在这种架构体系下,通过"补漏洞思维"确实可以解决问题。
但是在分布式微服务架构时代,意味着安全问题已经从"某个接口有没有漏洞",演变成了"整条系统链路是否可信"。一旦还停留在点状补漏洞的思维里,架构迟早会在系统规模扩大后暴露出结构性风险。
系统安全架构,到底在解决哪些问题?
如果从架构第一性原理出发,安全架构并不是单纯防"黑客",而是在系统层面持续解决下面这几类问题:
-
谁可以进入系统?
-
进入系统的人或程序,是否真的是其声称的身份?
-
进入系统之后,能访问哪些资源、执行哪些动作?
-
请求在传输过程中,是否可能被窃听、篡改、伪造或重放?
-
内部服务之间,到底应不应该天然信任?
-
核心数据是否会被越权访问、批量导出、拖库泄露?
-
业务是否可能被撞库、刷券、薅羊毛、伪造回调、脚本攻击?
-
当安全事件发生后,系统能否及时发现、快速定位、有效止损并完成追责?
你会发现,这些问题其实天然覆盖了系统的完整生命周期:从用户接入、身份认证、权限控制,到服务调用、数据保护、风控拦截,再到审计追踪与事件响应。
所以,真正成熟的安全架构,并不是"有一个安全组件很强",而是:
边界层、接入层、认证层、授权层、服务层、数据层、运维层、审计层,共同组成了一套纵深防御体系。
从系统链路来看,安全到底分布在哪些位置
一个常规的系统架构设计,它的链路通常如下:
用户 / 终端 → CDN / WAF → 负载均衡 / API Gateway → 认证中心 → 业务服务 → 缓存 / MQ / 数据库 / 对象存储 → 第三方服务 → 日志审计与监控平台
系统安全架构的核心目标
很多人一谈安全,就容易把目标理解成"绝对不被攻击"。但从架构角度看,这其实是一个不现实的目标。更合理的表述应该是:安全架构的目标,不是追求"永不出事",而是让系统具备以下能力:
-
可认证:确保访问主体真实可信;
-
可授权:确保访问边界明确、最小权限;
-
可保护:确保链路、服务、数据处于受保护状态;
-
可感知:确保异常行为和攻击事件能被及时发现;
-
可恢复:确保一旦出事可以快速止损、回滚和恢复。
如果把它压缩成一句更有架构感的话:
系统安全 = 身份可信 + 权限可控 + 链路可防护 + 数据可保护 + 事件可追踪 + 风险可恢复。
边界安全层:边界安全为什么永远是第一道门?
任何系统只要暴露到公网,首先面对的都不是"业务用户",而是各种不受欢迎的流量:扫描器、爬虫、撞库脚本、CC 攻击、DDoS、恶意探测请求。
所以系统的第一步,不是先认证"这个人是谁",而是先判断:这波流量,值不值得进入系统
这就是边界防护层的使命。它的核心能力通常包括:
-
流量清洗
-
Web 攻击拦截
-
Bot 管理
-
访问控制
-
全局限流
典型技术架构或组件包括 WAF、Anti-DDoS、Bot 管理平台、接入层限流系统等。
什么是Anti - DDos?
Anti - DDos全称分布式拒绝攻击防护,用于防洪水、防人海攻击、流量清洗,核心防护DDos攻击、CC攻击
Denial of Service(Dos攻击) → 拒绝服务攻击 , 本质上就是利用单台设备,疯狂轰炸你的网站 / 服务器,它不在于偷取的信息,而是在于通过网络轰炸来让你的宽带、端口、连接等资源耗尽崩溃。
DDos是Dos攻击基础上的分布式攻击,即n台设备的联合轰炸。
通常DDos攻击分为以下几种攻击类型:
-
流量洪水攻击海量垃圾数据包灌进来,直接把宽带跑满。
-
SYN 洪水只发连接请求,不完成握手,耗尽服务器连接队列。
-
**CC 攻击(应用层 DDoS)**模拟正常用户,疯狂刷接口、刷首页,把业务服务压死。
Anti-DDoS是DDos攻击的防御系统 ,专门用来对抗万人级流量轰炸的网络层防护工具 / 服务。
通常所有用户流量,**先全部接入 Anti-DDoS 防护集群,**系统自动区分:
-
正常用户:行为规律、请求正常 → 放行
-
攻击流量:IP 杂乱、数据包畸形、高频轰炸 → 直接丢弃、清洗
过滤干净的合法流量,再转发给你的 WAF、SLB、业务服务器
通常也是直接使用云端的Anti-DDos服务,例如高仿IP
什么是WAF?
**WAF(Web Application Firewall Web应用防火墙 )**它是一种安全基础设施组件,在云厂商场景下,也可以看成一种 托管安全服务,例如阿里云 WAF、腾讯云 WAF、华为云 WAF。
传统网络防火墙更多关注的是:IP、端口是否开放、包是否异常、网络层、传输层是否可疑,它本身针对的是此次的网络传输。
但互联网业务真正暴露给外部的攻击面,往往不只是"网络端口",而是:HTTP / HTTPS 请求、URL 参数、Cookie、Header、Body、JSON / XML / Form 表单、上传的内容等等。
也就是说,攻击者打的不是"机器",而是"应用逻辑入口",例如常见的手段为:SQL注入、XSS(CSRF\XSS\CORS)、命令注入、恶意爬虫、暴力刷接口、API 参数探测、业务接口撞库等,传统网络防火墙看不懂这些"应用层语义",于是就催生了 WAF。
WAF核心的目标就是在应用前面增加一层基于应用层语义的安全防护层。
WAF防范手段也非常简单,可以简单理解为:
- 关键词 & 特征拦截
通俗的说,就是WAF会拦截所有的请求,并解析请信息,通过关键字扫描的方式来识别当前请求是否可能是一个恶意的请求。并进行拦截。
- 行为频率拦截
同一个 IP 1 秒几十次请求 → 判定爬虫 / 暴力破解,限流封禁,异常高频访问、恶意刷接口,直接限制
- 非法内容 / 文件拦截
禁止上传脚本木马、恶意压缩包,拦截畸形请求、非法请求头、伪造 Referer 等。
例如,如果请求body中的含有类似于</script> #{header} 这样的关键字请求,会被拦截

什么是Bot 管理?
Bot是自动化机器人程序,用于识别不是真人手动操作,是脚本、爬虫、外挂、批量工具、恶意脚本自动发请求。
真人操作有间隔、鼠标滑动、页面停留,Bot 毫秒级连续请求、无停留、请求节奏极度规律。例如:
-
恶意爬虫:扒商品、扒用户数据、爬文案
-
注册 / 登录薅羊毛机器人:批量注册、刷券、刷单
-
暴力破解 Bot:撞库、猜密码
通常阿里云 / 腾讯云 WAF 一般内置「Bot 管理模块」。
Anti-DDoS: 防超大流量洪水(万人暴力堵门)
WAF: 防漏洞攻击、注入、XSS(带凶器偷偷入侵)
**Bot 管理:**防机器脚本、爬虫、外挂、黑产自动化薅羊毛
传输安全层
系统安全继续往内走,就一定会碰到传输链路安全问题。因为只要数据在网络中传输,就可能面临三类典型风险:
-
被窃听
-
被篡改
-
被冒充
这也是 HTTPS / TLS 出现的根本原因。
为什么HTTP不安全?
因为HTTP 本质上是无状态明文协议,因此需要应用层补充状态信息,例如Session、Token、JTW等,而"明文"则意味着:如果不做保护,链路上的数据理论上是可以被看到和篡改的。例如:浏览器和服务器之间发的数据:账号、密码、Token、参数
HTTP 无状态:指的是协议本身不会记住前一次请求是谁发起的,也不会天然知道"这个用户刚刚已经登录过"。 这会直接引出后面的 Session、Token、JWT 等机制,因为如果协议层不帮你记状态,应用层就必须自己补状态。
这就引出了:HTTPS = HTTP + 加密安全层 (SSL/TLS)
通俗的说,HTTP 是裸聊;HTTPS 是加密私聊,全程看不懂、改不了、冒充不了。(HTTP:默认 80 端口 , HTTPS:默认 443 端口)
HTTPS 到底解决什么?
-
防窃听(加密) :传输内容全部加密,别人看不懂内容。运营商、黑客、局域网其他人抓包,全是乱码,看不懂密码和数据。
-
防篡改(完整性):数据包带校验,中途被人改一个字,后端直接识别、拒绝响应。
-
防冒充(身份认证) :依靠SSL 证书 证明:你访问的
api.xxx.com就是官方正品服务器,杜绝钓鱼网站、域名劫持、假服务器诈骗。
TLS 的设计非常经典,它不是单纯"上了一个加密算法",而是把几类技术组合起来:
其核心的目的就是,在建立TCP握手后,客户端和服务端达成共识,形成对称密钥,然后加密数据后传输。
-
用**SSL证书 + 非对称加密(RSA)**解决身份认证与密钥交换;
-
后续两端通信都是通过用对称加密AES解决高性能数据传输;
-
用MAC / AEAD保证完整性。
大概的原理如下,HTTP请求时客户端会和服务端通过TCP3此握手完成连接,而HTTPS协议就是在建立连接之后的进一步的安全验证行为:

为什么 TLS 不直接全程使用 RSA?
因为**非对称加密太慢,**TLS在握手过程中通过RAS的核心是为了更安全的将预主密钥秘密的给到服务端,双方达成一致生成同样的对称密钥AES,后续的传输过程都是用对称加密方式,效率更快。
身份认证层
系统继续往里走,就来到了身份认证层。认证要解决的问题,其实很纯粹:
访问系统的主体,是否真的是其声称的那个主体。
当然这个主体也是多样的,可能是用户、第三方应用、服务实例等等
为什么传统的账密不够用了?
在传统的身份认证系统中,通常都是使用账密方式来进行,这种单一的认证方式,我们称为单因子认证 (SFA),而密码天然就会面临以下问题:
❌ 弱密码普遍存在
生日、手机号、123456、重复序列,暴力破解、字典攻击秒破。
❌ 静态不变,一旦被盗永久风险
密码是长期固定静态凭证,黑客拿到就能无限复用、长期登录。
❌ 无法防
密码只验证「你知道什么」,不看:是谁在用、在哪登录、什么设备。异地、陌生设备、恶意代理环境,照样直接登录。
❌暴力破解
接口无防护的前提下,批量遍历账号 + 弱密码,批量薅库、盗号。
现代认证体系
现代认证体系所以现代认证体系不会把"密码"当作唯一依赖,而是会进一步引入:
- 多因子认证MFA
除了密码一个维度因子,还引入更多维度的因子,来避免单一因子无防范能力,例如更常见的:
**登录设备因子:**检查陌生设备登录
**登录IP:**检查异地登录
**指纹、人脸等:**做多重认证因子。
- 短期一次性凭证
密码是永久的,一旦被窃取就会无限使用,因此引入了短期一次性凭证,例如手机验证码登录,人脸登录、指纹登陆等
- 令牌化登录
彻底弱化密码直接传输,首次登录后,后续通过令牌进行认证,不反复传密码。例如JWT、Session、OAuth2.0、OIDC 统一身份令牌。
- 联邦单点登录 & 第三方信任授权、
这种方式确实完全隐藏了密码的使用,黑客无法窃取的你账密信息。例如SSO、微信 / 支付宝 / 企业微信登录
JWT、Session、OAuth2.0、OIDC 统一身份令牌
回到上面的内容,HTTP是无状态的,令牌化登录目的是为了实现一次登录,通过令牌认证,避免重复登录,来弱化密码传输。
Session、JTW都是用于解决用户登录成功后,服务器怎么知道"这个请求是刚才那个已经登录过的用户"?
🟥Session令牌
Session是服务端维护登录状态的最经典方案,流程如下:
1. 用户输入账号密码,前端发起 /login 请求 2. 请求抵达服务器,由 Tomcat 接收、解析 HTTP 请求。但是此时: - 浏览器无当前站点 JSESSIONID Cookie(因为是首次请求,还未鉴权) - Tomcat 服务端,没有该用户任何 Session 会话 3. 登录接口中通过HttpSession session = request.getSession()读取Session信息 - Tomcat 检查当前请求有没有 JSESSIONID Cookie(首次)则创建一个会话HttpSession对象, 并生成唯一会话ID:JSESSIONID,最终将 该Session对象存储到内存中 4. 登录服务做登录检查,成功后将用户信息通过session.setAttribute("user",loginUser); 设定到当前Session对象中 5. 请求返回,此时Tomcat 自动往响应头添加:Set-Cookie: JSESSIONID=xxxx 6. 浏览器拿到响应后,识别到Cookie:JSESSIONID=xxxx,于是缓存到Cookie中 (隔离存储,即JS无法读取)与当前网站域名进行绑定 7. 下一次请求时,浏览器通过域名读取该cookie进行传递。
❌ 但是Session令牌,存在致命缺点:
-
服务端要存会话Session,集群 / 分布式需要共享 Session,导致水平扩展困难
-
浏览器 Cookie会自动传递,存在CSFR攻击风险
-
Cookie 是浏览器特殊受控机制,跨域支持差
对于普通的跨域问题,只需要服务端配置CORS,对跨域地址或者*放行就行。但是 浏览器默认禁止跨域写入 / 读取 Cookie,就算后端开了 CORS,跨域 Cookie 还要额外满足,支持差: - 前端请求必须配置 withCredentials: true - 后端必须配置 Access-Control-Allow-Credentials: true- 不能用 * 通配符放行域名,必须写死具体域名
于是引出了JWT令牌机制
🟥JWT令牌
JWT是一个字符串,但是它不是一个普通的字符串,它包含、加密签名的字符串令牌。正是因为这样,服务端不需要存储会话,通过令牌自身携带的用户信息。
它一种自包含、可签名验证的 Token 格式标准,通常用于无状态身份信息传递。用户信息直接编码在 Token 里,服务器不需要查存储,只要验签就能信任。
大概使用流程如下:
用户登录 → 服务器验证账号密码 → 生成 JWT,返回给客户端 → 客户端存储(LocalStorage / Memory / Cookie)→ 后续请求 Header 携带:Authorization: Bearer <token> → 服务器验签 + 检查过期 → 取出 Payload 信息确认身份
它的优点是:
-
因为JWT是手动传输的,天然避免了CSFR攻击
-
同时天然支持分布式,也不依赖服务端存活。
-
不可篡改、自带信息、无状态
-
JWT 跨域友好:Header 传输,不依赖 Cookie,简单CORS配置即可
缺点是:
-
当如浏览器对于JWT是存储在内存中的,会被JS读取,因此会面临XSS攻击的风险。
-
一旦签发,服务端无法主动作废(短期过期设计),因此服务端并不会管理它
🟥Oauth2(第三方授权协议)
Session和JWT都是用户认证。而Oauth2核心是针对第三方授权协议,也就是另一种安全认证方式。例如微信登录 B 站、抖音登录小程序、Github 登录后台
它解决的问题是:你是否被允许以某个用户的名义,访问某个资源。
例如:
你在使用一个第三方 App,它想读取你 GitHub 上的仓库列表。 没有 OAuth2 之前,唯一的方式是把 GitHub 账号密码告诉这个 App。
❌ 这极其危险: - App可能存储你密码 - 你没办法精细控制 App 能访问哪些东西 - 你无法随时撤回权限
OAuth2 出现后,解决方案是:
你去 GitHub 授权页面确认授权,GitHub 给第三方 App 一个有限权限的 AccessToken,App 拿这个 Token 访问资源,而不需要你的密码。
这就是 OAuth2 的核心:授权委托。
♦️四大核心角色
-
资源所有者(Resource Owner) 就是用户本人,拥有微信 / 抖音 / 阿里云账号与数据的人。
-
**客户端(Client)**第三方应用,需要拿你数据的一方;例:用微信登录的「知乎、B 站、小游戏」。
-
**授权服务器(Authorization Server)**账号原厂的认证授权服务;例:微信授权中心、抖音开放平台、阿里云 IAM。
-
**资源服务器(Resource Server)**存放用户数据的业务服务;例:微信用户信息接口、相册接口、通讯录接口。
架构本质:授权服务器 与 资源服务器 做职责拆分,解耦登录、授权、数据查询。
♦️OAuth2 核心产物(2个令牌)
- Access Token 访问令牌
核心作用:访问资源服务器,拿用户数据、调用授权接口,它是短期有效(分钟 / 小时级)
- Refresh Token 刷新令牌
核心作用:Access Token 过期后,无需用户重新授权,自动换新 Token。长期有效
♦️四种标准授权模式
- 模式 1:授权码模式 Authorization Code(企业 / 互联网 95% 首选)
以下以QQ的第三方登录Oauth2实现来说明
-
前提:我们系统**(客户端)** 需要在QQ的授权服务器完成应用注册,因为QQ需要确保我们是一个合法的应用,此时会拿到一个APPID
-
在客户端 中用户(资源所有者 )点击QQ登录,调用QQ授权服务器授权码服务,此时用户会跳转到QQ第三方登录授权页面。
-
用户完成QQ登录授权后,QQ授权服务器 会返回我们一个Authorization Code
-
我们通过Authorization Code, 继续调用QQ授权服务器 获取access_token,同时返回refesh_token
-
该access_token就是用于用户信息读取的令牌,我们可以该令牌取QQ授权服务器获取用户信息,其内部就是去资源服务器读取信息。
-
拿到用户信息后,就可以在我们系统中进行认证授权,完成登录
注意:后两步并不是Oauth2协议的内容,只是授权后的业务处理,即在读取到token后,我们就可以通过token再次去拿到各种信息,例如读取用户基本信息

- 模式 2:简化模式 Implicit(淘汰、废弃)
相对于授权码模式,它跳过了 Code 环节,授权后直接在浏览器 URL 返回 AccessToken,前端直接拿,极易泄露。
- 模式 3:密码模式 Password(仅内网可信场景)
用户直接提交账号密码给业务端,直接换取令牌,完全违背 OAuth2 初衷。
- 模式 4:客户端模式 Client Credentials(纯服务间调用)
无用户参与,只用ClientID+ClientSecret直接拿令牌,用于两个后台系统互调接口。
为什么要code换取token?
因为code 是短期的,只能用一次,而且如果直接返回token会有泄露风险。而code 换 Token 在后端对后端完成,携带 client_secret,更安全。
🟥 OIDC(第三方授权协议)
OIDC是在Oauth2基础上授权协议,Oauth2协议本身只是进行授权,但是并不会告诉你用户信息是什么,例如我们授权拿到token就结束了,如果需要用户信息,需要通过服务调用方式获取。于是在 OAuth2 基础上,补充了一套标准:
让授权协议"也顺便认证用户身份",即通过code换取token时,其他的信息:
-
**ID Token:**一个包含用户身份信息的 JWT
-
**UserInfo Endpoint:**可以查询用户详细信息的接口
-
标准化 Claims:sub、name、email、phone 等统一字段
OIDC 流程(相比 OAuth2 多了 ID Token)
用户授权 → 获得 code → 后端换 Token 时,同时获得: - AccessToken(访问资源) - ID Token(用户身份 JWT) - RefreshToken(刷新用 Token)
ID Token 示例:
{
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"aud": "client-id-12345",
"name": "曹先生",
"email": "test@example.com",
"picture": "https://...",
"iat": 1716000000,
"exp": 1716003600
}
权限检查(授权)
很多系统在认证做完之后,就误以为安全已经完成了。实际上,真正高发的安全事故,往往出现在权限检查这一层。
因为认证解决的是"你是谁",而授权解决的是:你能做什么。
通常系统对于权限控制分为3种:
-
功能权限:能不能用某个功能;
-
数据权限:能看哪些数据;
-
字段权限:哪些字段可见、可编辑。
常见的授权模型如下,不同的授权模式适用于不同的业务场景:
🟥 RBAC:基于角色的访问控制
最直观,例如管理员、运营、财务、普通用户。
🟥 ABAC:基于属性的访问控制
通过主体属性、资源属性、环境属性综合判断,例如:
-
用户所属部门
-
数据归属人
-
当前访问时间
-
当前访问网络环境
🟥 ReBAC:基于关系的访问控制
强调"你和资源之间是什么关系",例如:
-
是否是文档拥有者
-
是否属于项目成员,或者协作者
-
是否被共享给当前用户
常用的认证、授权框架
Shiro
-
简单、轻量、老项目最爱
-
不依赖 Spring,可独立用
-
认证、授权、会话、加密、拦截 全都支持
-
上手快、API 简单、学习成本低
Spring Security
-
Spring 官方亲儿子,功能极强
-
深度绑定 Spring/SpringBoot
-
认证、授权、OAuth2.0、OIDC、SAML、微服务安全 全都支持
-
功能比 Shiro 多得多,但配置更复杂
简单的认证、授权架构设计
通常企业落地认证、授权,并不会在所有的服务都会进行认证和授权,而是通过认证中心和授权中心来进行分布式管理。

当然,一个完备的系统安全设计,还包括数据安全存储、数据审计追踪等。