CodeAudit
工业级架构
浏览器
CDN(分布式缓存代理层)
内容分发网络,存储网站的静态资源,加速访问的物理距离
边缘防护系统抗DDos,分担大流量防止冲垮源站
隐藏Nginx负载均衡服务器的真实IP地址
DNS智能调度中心(GSLB,全局负载均衡)
运维需要把网站的主域名做一条CNAME别名记录指向CDN厂商提供的调度域名
智能决策,CDN厂商会根据DNS请求的IP来源,分析地理位置和网络运营商,将最适合的边缘节点IP返回
边缘缓存机制(Cache)
缓存命中(Cache Hit),如果CDN已经下载过该用户请求的该网站的静态资源,就会直接返回
缓存过期(TTL),CDN会根据HTTP响应头中的Cache-Control、Expires或者运维在CDN后台配置的规则定时刷新静态资源
回源策略(Fetch)
如果未发生缓存命中或者资源过期,就会触发回源
此时CDN边缘节点化身客户端向源站请求静态资源,然后作为服务端将静态资源返回用户,同时将静态资源存入缓存,便于下一个用户访问
动静分离(Dynamic vs Static)
静态资源,尽量遵循缓存机制
动态资源,CDN会识别出这是一个动态请求,将该请求直接通过路由优化或者长连接保持直接返回源站
Cloud Flare
DNS解析权移交
CF会要求用户将在域名注册服务商使用的默认DNS服务器换成CF提供的DNS服务器
子域名
在一个顶级域名最前面加上任何前缀,形成的新域名都叫子域名
DNS解析
用户发起对目标域名的请求,这个请求先经过本地运营商的DNS,本地DNS去访问根域名服务器
根域名服务器返回顶级域名服务器,顶级域名服务器再返回CF托管的权威DNS解析服务器
最后CF的DNS解析服务器再返回本地DNS边缘节点的IP地址,用户再通过本地DNS拿到边缘节点的IP
ECS与NS服务器
ECS用于本地DNS向CF的DNS解析服务器请求边缘节点时,会带上用户的网段和物理位置,便于CF返回最适合的边缘节点
NS服务器就是DNS解析服务器
Anycast IP组(目前先记住存放了DNS服务器的IP地址)
单播(Unicast),唯一服务器绑定唯一的IP地址,当大流量访问时直接冲垮网站
**任播(Anycast)**巧妙地运用了底层的路由跳转协议,即路由器在寻路的时候总是朝着网络路径最快的地方跳转,这个最快受制于运营商和地理位置
任播就是将无数台服务器绑定同一个IP地址,所有服务器共用同一个IP地址,这些服务器的区别就在于地理位置的不同
也就是说,一台在亚洲的路由器访问目标IP的时候,只会跳转到该地理范围内的服务器,绝对不会随意跳转到欧洲的目标IP下的服务器
任播最重要的作用就是分散流量,而且是利用路由器最底层的协议,这样就可以很好的抗DDos,相当于利用全球所有的路由器来分散一次大流量的DDos攻击
TLS卸载
密钥来源:CF利用域名托管自动找权威机构签发的默认密钥,或者蓝方运维人员上传的密钥
TLS卸载的目的在于将用户发送的https密文还原成明文,再交由CF的WAF进行清洗流量,拦截攻击代码,拉黑IP,清洗完成后在进行内容分析
静态资源就直接返回,动态资源就整合成新的https请求并加密回源
Argo隧道回源
通常来说,WAF禁止入向流量,但是不禁止出向流量,此时可以通过服务器主动发起请求连接CF的边缘节点,这样就建立了一条隧道
不仅如此,隧道还会进行加密,使用底层双向SSL加密,鉴权令牌等高级加密保障通信的安全,因此想通过劫持隧道来获取信息理论上几乎不可能
由于隧道是由服务器通过出向流量发起的,也就是说完全可以关闭WAF的入向流量,不对外开发服务器的任何端口,极大地提升了防护能力
公网回源
与隧道回源截然不同,公网回源需要服务器开通端口,以便于CF的边缘节点通过公网访问到
并且公网回源时一般为未加密的报文或者加密程度低的方式,极易被拦截监听
而且既然使用的是公网回源,也就是说服务器的IP和开放的端口都会暴露在公网下,很容易被扫出来
安全永远是信任的博弈
浏览器->本地运营商DNS->根域名服务器->顶级域名服务器->CF的任播IP组->CF的权威DNS服务器->通过ECS返回边缘节点->TLS卸载清洗流量分析报文
->静态资源直接返回
->动态请求->隧道回源或公网回源->源站
WAF
网络过滤防火墙
抓包,拆包,扫描,过滤
Nginx负载均衡
隐藏真实业务服务器的IP地址
将请求分流到后端的真实业务服务器
请求会先到Redis去找缓存,找到了就直接返回,流量被挡在负载均衡这一层
如果Redis返回没有数据,请求就会直达源站,让源站调度最后的数据库
Redis
网站数据内存中心,存储临时的,时效性高的数据和登录令牌的指针
缓冲前哨所,多台Redis分摊数据请求防止过大流量冲垮后台数据库
源站
存储网站的静态资源和后端逻辑代码
处理业务请求,负责后端鉴权
使用Docker容器隔离业务和主机
运行杀毒软件实时监测
数据库
核心资产所在地,负责存储源数据
负责搜索并返回Redis未存储的缓存
容器落地
根据这套最基础的工业级架构,使用Docker进行了一套容器部署
数据流
浏览器->CDN(80)->静态资源直接根据CDN的缓存直接返回
->动态请求发送到Nginx负载均衡->Nginx作为智能网关分析动态请求->常用数据和token令牌到Redis进行查找
->Redis未存储的数据根据三七分流到后端服务器a和b->只有服务器a和b拥有查询数据库的权限
整个系统只有CDN的80端口映射到主机,后端的一切组件均处在Docker的内网中,无法直接通过外界访问,更符合现代的安全架构
鉴权流
登录阶段,登录请求根据上述数据流达到后端进行身份校验,校验成功后发放token令牌,并由服务器向Redis写入token的uuid指针
请求阶段,用户登录成功拿到token后,每次请求都会带上token,token不经过后端服务器校验,而是由网关的lua脚本查询Redis的token指针完成校验,整个流程后端服务器和数据库保持静默,缓解了后端的数据处理压力,提高响应速度
后续会继续完善防火墙的容器配置和令牌时效的校验
资源连接:https://github.com/HFUT-C1Sec/jww128-Notes/tree/main/cdn_labs
OOP
传统面向对象编程,从上到下编写业务代码,缺点就是后期维护性差,业务的耦合性过高
AOP
面向切面编程,即业务解耦分离,各自安好,鉴权的鉴权,业务的业务,互相分离
Aspect(切面)
一个专门用来放“公共重复代码”的类
Pointcut(切入点)
用来定义哪些方法需要被拦截,比如注解触发
注解本身不包含任何实际的代码逻辑,只是高市spring容器,经过这个注解的时候需要注解指向的代码的处理
Advice(通知)
拦截到方法后,具体在什么时候干什么事
具体实例(若依的鉴权流程)
设定java序列化后的版本号,出现这个也就意味着这个地方存在与数据库或Redis的数据交流
1 | |
excel注入和XSS
1 | |
random伪随机数
硬编码默认密钥
1 | |
首先硬编码的后期维护性很差,需要修改密钥的时候要重新编译代码,但是安全问题严重的是使用了默认密钥,这是使用开源项目会出错的地方,一旦密钥泄露就可以伪造令牌实现未授权登录
Redis加UUID
这个UUID其实是token的指针存放在Redis中,由于token自带信息,且存在颁发时效,用户下线了,token仍然可以被利用进行登录,此时就会颁发一个指向token的指针存在Redis里,一旦用户下线,Redis里的指针也会同步销毁,即使在后端校验token过了,但是在Redis里找不到这个已登录的token依然会被踹回
实际环境中会先进性后端token密钥校验,然后再去Redis校验指针
token:
Base64哈希算法
eyJhbGciOiJIUzUxMiJ9
Base64用户信息
eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6Ijg4M2FmYmJlLTE3ZDYtNDRmZi04MjlmLWIwNzdhMDgzOWJjMSIsInVzZXJuYW1lIjoiYWRtaW4ifQ
密钥签名
ruk_PXDmS4IKupbBcYNH9334y8ZlhFEmhQh4diFSgkay8wKbxmE7Qz2byITg3GEKurpBAxcUH9sqVCNMV7UO4g
完整鉴权路径
post请求发到后端->filter剥离url过白名单,查看是否合法访问->验请求里的token是否为空->校验token里的签名密钥->校验token的时效->到Redis校验token指针的登录状态
Redis越权登录
Redis设计之初便不具备身份校验功能,因此极度依赖架构的保护
Redis的端口6379被暴露,并且没有设置密码就会被越权登录
FastJSON 缓存反序列化打击
完整数据流
请求->鉴权->token剥离,请求转换为明文->后端处理->json返回前端渲染
RE
说实话,和ai聊了真的受益匪浅,网安从来不是打CTF做题,会真正的工业级架构,懂流量的流向,才是真正有用的东西,时代在发展,技术不断进步,从一开始的生成式ai,到最近的小龙虾,agent,哎做题的能力一直在提升,这种情况下CTF衰落是必然的,再加上CTF从一开始就脱离生产实际,所以我觉得应该有所侧重,只会做题是没有未来的,所以接下来我将先从Docker轻量化组件部署开始,一步一步到物理机部署,争取最后完成一个完整的工业级的真机架构,平时兼顾agent开发,CTF就当扩展面