This commit is contained in:
2026-04-20 22:47:51 +08:00
commit 7b271af6ea
33 changed files with 7588 additions and 0 deletions
+553
View File
@@ -0,0 +1,553 @@
---
tags: [CS, NET, security, authorization, web, authentication-flow]
create time: 2026-04-17
---
# Web Application Authorization Flow
## 概述
**Authorization(授权)** 在 Web 应用中是 HTTP 层面的认证令牌验证机制。本文聚焦浏览器、服务器、Token 的交互流程和加密验证过程。
## HTTP Authorization 流程
### 完整授权流程
```mermaid
sequenceDiagram
participant B as Browser
participant S as Server
participant DB as Database
Note over B,S: 1. 登录获取 Token
B->>S: POST /login (username, password)
S->>DB: 验证凭证
DB-->>S: 用户数据
S->>S: HMAC-SHA256(payload, secret)
S-->>B: {access_token: "eyJhbGc...", expires_in: 3600}
Note over B,S: 2. 带授权头访问资源
B->>B: 存储 Token (LocalStorage/Memory)
B->>S: GET /api/resource
Note right of B: Authorization: Bearer eyJhbGc...
Note over S: 3. 验证 Token
S->>S: 提取 Token
S->>S: 验证签名 (HMAC)
S->>S: 检查过期时间
S->>S: 验证 Issuer/Audience
S->>DB: 根据 user_id 查询权限
Note over S: 4. 授权决策
alt Token 有效
S-->>B: 200 OK + 数据
else Token 无效
S-->>B: 401 Unauthorized
else 权限不足
S-->>B: 403 Forbidden
end
```
### JWT Token 验证过程
```mermaid
graph TD
A[接收 Authorization: Bearer <token>] --> B[解析三部分]
B --> C[Header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9]
B --> D[Payload: eyJ1c2VyX2lkIjoiMTIzIiw...]
B --> E[Signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c]
C --> F[获取签名算法 HS256]
D --> G[获取用户数据]
E --> H[签名部分]
F --> I[重新计算签名]
G --> I
H --> I
I --> J{签名匹配?}
J -->|是| K[检查过期时间 exp]
J -->|否| L[拒绝: 401 Unauthorized]
K -->|未过期| M[检查 nbf 时间]
K -->|已过期| L
M -->|有效| N[检查 iss 签发者]
M -->|无效| L
N -->|匹配| O[验证通过]
N -->|不匹配| L
O --> P[从 payload 提取 user_id]
P --> Q[查询用户权限]
Q --> R[返回受保护资源]
```
## 浏览器行为详解
### 浏览器如何处理 Authorization
```mermaid
graph LR
A[用户请求资源] --> B[检查 Token]
B --> C{Token 存在于?}
C -->|LocalStorage| D[从 LS 读取]
C -->|SessionStorage| E[从 SS 读取]
C -->|Memory| F[从变量读取]
C -->|Cookie| G[浏览器自动发送]
D --> H[构造 Authorization Header]
E --> H
F --> H
G --> I[无需手动添加<sup>*</sup>]
H --> J[发起 XHR/Fetch 请求]
I --> J
J --> K[设置 headers]
K --> L[发送到服务器]
style G fill:#ff9999
style H fill:#90EE90
style I fill:#90EE90
subgraph 注
G1[Cookie 方式需要 SameSite 属性]
G2[防止 CSRF 攻击]
end
G1 -.-> G
G2 -.-> G
```
**浏览器自动发送 Cookie,但需要手动添加 Bearer Token**
### 浏览器存储 Token 的方式
| 存储方式 | 特点 | 安全性 | 跨域访问 |
|---------|------|--------|---------|
| LocalStorage | 持久化,手动管理 | ❌ XSS 风险 | ✅ 支持 |
| SessionStorage | 会话结束清除 | ❌ XSS 风险 | ❌ 仅同源 |
| Memory | 页面刷新丢失 | ✅ 最安全 | ❌ 仅当前页面 |
| Cookie | 可设置 HttpOnly | ✅ 防 XSS | ⚠️ 需 SameSite |
### 前端实现 (JavaScript)
```javascript
// 1. 登录后存储 Token
async function login(username, password) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const { access_token } = await response.json();
localStorage.setItem('token', access_token);
}
// 2. 带认证头访问 API
async function fetchProtectedResource() {
const token = localStorage.getItem('token');
const response = await fetch('/api/resource', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.status === 401) {
// Token 过期,需要刷新或重新登录
handleTokenExpired();
}
return response.json();
}
// 3. Axios 拦截器自动添加 Token
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
```
## 加密与签名机制
### JWT 签名算法对比
| 算法类型 | 算法 | 密钥类型 | 特点 |
| ----- | ----- | ----- | ------------------- |
| HMAC | HS256 | 对称密钥 | 服务器签发和验证都 uses 同一密钥 |
| HMAC | HS512 | 对称密钥 | 更强的哈希,性能稍低 |
| RSA | RS256 | 非对称密钥 | 私钥签名,公钥验证 |
| RSA | RS512 | 非对称密钥 | 更强的签名算法 |
| ECDSA | ES256 | 椭圆曲线 | 比更短但同样安全 |
### HMAC-SHA256 签名流程
```mermaid
graph TD
A[原始数据] --> B[Base64URL 编码 Header]
A --> C[Base64URL 编码 Payload]
B --> D[拼接 Header.Payload]
C --> D
D --> E[HMAC-SHA256 拼接结果]
E --> F[使用 Secret Key]
F --> G[生成 256-bit 签名]
G --> H[Base64URL 编码签名]
H --> I[拼接 final JWT]
I --> J[Header.Payload.Signature]
style E fill:#ff9999
style F fill:#ff9999
style G fill:#lightblue
```
**签名 = HMAC-SHA256(Base64URL(Header) + "." + Base64URL(Payload), Secret)**
### Go 实现签名与验证
```go
package auth
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"strings"
)
type JWTBuilder struct {
secretKey []byte
}
// 生成签名
func (j *JWTBuilder) sign(header, payload string) string {
data := strings.Join([]string{header, payload}, ".")
h := hmac.New(sha256.New, j.secretKey)
h.Write([]byte(data))
signature := base64.RawURLEncoding.EncodeToString(h.Sum(nil))
return signature
}
// 验证签名
func (j *JWTBuilder) verify(token string) bool {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return false
}
header, payload, signature := parts[0], parts[1], parts[2]
// 重新计算签名
expectedSignature := j.sign(header, payload)
// 比较签名 (恒定时间比较,防止计时攻击)
return hmac.Equal([]byte(signature), []byte(expectedSignature))
}
```
## 服务器验证流程
### 详细的验证步骤
```go
package middleware
import (
"net/http"
"encoding/base64"
"encoding/json"
"time"
)
type Claims struct {
UserID string `json:"user_id"`
exp int64 `json:"exp"`
iat int64 `json:"iat"`
iss string `json:"iss"`
aud string `json:"aud"`
}
func (m *AuthMiddleware) validateToken(token string) (*Claims, error) {
// 步骤 1: 分割三部分
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid token format")
}
// 步骤 2: 验证签名
if !m.verifySignature(token) {
return nil, fmt.Errorf("invalid signature")
}
// 步骤 3: 解码 Payload
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("invalid payload encoding")
}
// 步骤 4: 解析 Claims
var claims Claims
if err := json.Unmarshal(payload, &claims); err != nil {
return nil, fmt.Errorf("invalid payload json")
}
// 步骤 5: 验证过期时间
if time.Now().Unix() > claims.exp {
return nil, fmt.Errorf("token expired")
}
// 步骤 6: 验证签发者
if claims.iss != "my-app" {
return nil, fmt.Errorf("invalid issuer")
}
// 步骤 7: 验证受众
if claims.aud != "api-users" {
return nil, fmt.Errorf("invalid audience")
}
return &claims, nil
}
// 验证签名
func (m *AuthMiddleware) verifySignature(token string) bool {
parts := strings.Split(token, ".")
signatureData := parts[0] + "." + parts[1]
providedSignature := parts[2]
// 计算期望的签名
expectedSignature := m.sign(signatureData)
// 恒定时间比较
return hmac.Equal(
[]byte(providedSignature),
[]byte(expectedSignature),
)
}
```
### HTTP 中间件
```go
// AuthMiddleware 验证每个请求
func (m *AuthMiddleware) Handler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. 提取 Authorization 头
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, "Missing Authorization header", http.StatusUnauthorized)
return
}
// 2. 解析 Bearer Token
if !strings.HasPrefix(authHeader, "Bearer ") {
http.Error(w, "Invalid authorization scheme", http.StatusUnauthorized)
return
}
token := strings.TrimPrefix(authHeader, "Bearer ")
// 3. 验证 Token
claims, err := m.validateToken(token)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
// 4. 将用户信息存入 Context
ctx := context.WithValue(r.Context(), "user_id", claims.UserID)
ctx = context.WithValue(ctx, "claims", claims)
// 5. 继续处理请求
next.ServeHTTP(w, r.WithContext(ctx))
})
}
```
## 常见 Authorization Scheme
### Basic Auth(基础认证)
```mermaid
sequenceDiagram
participant B as Browser
participant S as Server
participant DB as Database
B->>S: GET /resource
S-->>B: 401 Unauthorized
Note right of B: WWW-Authenticate: Basic realm="Secure Area"
B->>B: 用户输入用户名密码
B->>B: Base64("username:password")
B->>S: GET /resource
Note right of B: Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
S->>B: 解码 Base64
S->>DB: 验证用户名密码
DB-->>S: 验证结果
S-->>B: 200 OK + 资源
```
**问题**:每次请求都需要用户名密码,不安全,不推荐
### Digest Auth(摘要认证)
```mermaid
sequenceDiagram
participant C as Client
participant S as Server
C->>S: GET /resource
S-->>C: 401 Unauthorized
Note right of C: WWW-Authenticate: Digest<br/>realm="Protected",<br/>nonce="xyz123",<br/>qop="auth"
C->>C: 计算 response<br/>MD5(username:realm:password)<br/>MD5(method:uri)<br/>HA1 = MD5(username:realm:password)<br/>HA2 = MD5(method:uri)<br/>response = MD5(HA1:nonce:HA2)
C->>S: GET /resource
Note right of C: Authorization: Digest<br/>username="user",<br/>realm="Protected",<br/>nonce="xyz123",<br/>uri="/resource",<br/>response="abc123"
S->>S: 重新计算 response
S-->>C: 200 OK
```
**优点**:密码不直接传输,更安全
**缺点**:实现复杂,需要多次往返
### Bearer Token(持有者令牌)
✅ **现代 Web 应用的标准选择**
```http
# 请求示例
GET /api/user/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzIiwidXNlcm5hbWUiOiJqb2huIiwiZXhwIjoxNzI4MjQ4MDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
# 响应示例
HTTP/1.1 200 OK
Content-Type: application/json
{
"user_id": "123",
"username": "john",
"email": "john@example.com"
}
```
## Refresh Token 机制
### Access Token vs Refresh Token
```mermaid
graph LR
A[Access Token] --> B[有效期短<br/>15-30分钟]
A --> C[用于 API 访问]
A --> D[存储在浏览器]
E[Refresh Token] --> F[有效期长<br/>数天至数周]
E --> G[用于获取新 Access Token]
E --> H[存储在 HttpOnly Cookie]
style A fill:#90EE90
style E fill:#ffcc00
```
### Token 刷新流程
```mermaid
sequenceDiagram
participant B as Browser
participant S as Server
Note over B,S: Access Token 过期
B->>S: POST /api/refresh
Note right of B: Body: {refresh_token: "..."}
S->>S: 验证 Refresh Token
S->>S: 生成新的 Access Token
S-->>B: {access_token: "new_jwt..."}
Note over B,S: 使用新 Token 继续请求
B->>S: GET /api/resource
Note right of B: Authorization: Bearer new_jwt...
S-->>B: 200 OK
```
**Refresh Token 优势**:
- ✅ Access Token 短期有效,减少泄露风险
- ✅ Refresh Token 可随时撤销
- ✅ 用户无感知自动续期
## 安全最佳实践
### Token 安全传输
| 措施 | 说明 | Go 实现 |
|-----|------|---------|
| **HTTPS 强制** | 防止 Token 被窃取 | RedirectHTTPS 中间件 |
| **短期有效期** | 降低被滥用风险 | Token 15-30 分钟 |
| **签名验证** | 防止 Token 被篡改 | HMAC/RSA 签名 |
| **黑名单机制** | 主动撤销 Token | Redis 存储 revoked_tokens |
### 浏览器安全设置
```javascript
// ✅ 推荐:HttpOnly Cookie 存储 Refresh Token
document.cookie = `refresh_token=${refreshToken}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=604800`;
// ⚠️ 谨慎:LocalStorage 存储 Access Token
localStorage.setItem('access_token', accessToken);
// 需要 XSS 防护
// ❌ 避免:明文传输 Token
// 必须使用 HTTPS
```
### CORS 和 SameSite
```mermaid
graph TD
A[前端应用<br/>example.com] --> B[后端 API<br/>api.example.com]
B --> C[CORS 策略]
C --> D[Access-Control-Allow-Origin: https://example.com]
C --> E[Access-Control-Allow-Credentials: true]
B --> F[SameSite Cookie]
F --> G[Strict: 严格模式]
F --> H[Lax: 放宽模式]
style D fill:#90EE90
style G fill:#90EE90
```
**Go CORS 配置**:
```go
func setupCORS() *cors.Cors {
return cors.New(cors.Options{
AllowedOrigins: []string{"https://example.com"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowedHeaders: []string{"Authorization", "Content-Type"},
AllowCredentials: true,
MaxAge: 3600,
})
}
```
## 相关笔记
- [[金山办公作业/Week05/用户认证]] - 认证的实现方式
- [[CS/NET/HTTPS]] - SSL/TLS 加密传输
- [[CS/DB/访问控制]] - 数据库层面权限
+349
View File
@@ -0,0 +1,349 @@
---
tags: [CS, NET, algorithm, data-stream, heavy-hitter]
create time: 2026-04-17 13:45
---
# HeavyKeeper
## 概述
HeavyKeeper 是一种用于高速数据流中检测 Heavy Hitters(频繁项)的高效算法。它在保持常数内存空间的同时,能够准确地识别出出现频率超过设定阈值的数据项,广泛应用于网络流量监测、热点检测等场景。
## 算法原理
### 核心思想
HeavyKeeper 结合了 Count-Min Sketch 和守桶策略,通过多层哈希守桶机制来提高准确性。其核心目标是区分"大象流"和"老鼠流"。
#### 什么是大象流和老鼠流?
在数据流分析中,通常将数据流按频率分为两类:
| 类型 | 特征 | 频率占比 | 典型例子 |
|------|------|----------|---------|
| **大象流**(Elephant Flow) | 高频出现 | 占总流量的大部分 | 热门IP、热门搜索词、DDoS攻击流量 |
| **老鼠流**(Mouse Flow) | 低频偶发 | 数量众多但频率极低 | 少量用户访问、正常连接请求 |
**关键洞察**:在很多场景中,**80-90%的流量来自不到1%的源**,这就是大象流。HeavyKeeper 的目标就是高效识别这些大象流,过滤掉老鼠流。
### 守桶机制
#### 什么是"守桶"?
"守桶"(Keeper)是 HeavyKeeper 的核心创新。每个桶会"守护"一个特定的数据项:
- 当数据流中的一个项到来时,哈希到某个桶
- 如果这个项正好是该桶"守护"的项,就直接计数
- 如果不是,则根据概率决定是否"抢夺"守护权
**底层原理**:让大象流(高频项)能够长期占据守桶位置,而老鼠流(低频项)很难长期占用桶的资源。
#### 桶的结构
每个桶维护以下信息:
| 字段 | 类型 | 说明 |
|------|------|------|
| **item** | 数据项 | 当前守护的数据项 |
| **count** | 整数 | 守护项的精确计数 |
| **error** | 整数 | 误差估计(记录非守护项经过的次数) |
#### 守桶策略:大象流如何压制老鼠流
**替换概率公式**:
```python
替换概率 = min(1, 新项估计频率 / 当前守护项计数)
```
这个公式的直观含义:
| 情况 | 新项类型 | 替换概率 | 结果 |
|------|---------|---------|------|
| 大象流 vs 老鼠流 | 老鼠流(freq≈1) | 1/count | 极小,**老鼠流无法撼动大象流** |
| 老鼠流 vs 老鼠流 | 老鼠流(freq≈2) | 2/count | 较小,随机性强 |
| 大象流 vs 老鼠流 | 大象流(freq=50) | 50/5=1 | 必然替换,**新大象流抢占桶** |
| 大象流 vs 大象流 | 大象流(freq=98) | 98/95≈1 | 可能替换,两个大象流竞争 |
**例子**:
```
桶#100 当前守护:IP=10.0.0.1 (count=100, error=5) ← 大象流
新到来:IP=10.0.0.2 → 哈希到桶#100 ← 老鼠流
替换概率 = min(1, 1/100) = 0.01
结果:0.95(随机数)> 0.01 → 不替换
解释:大象流继续守护,老鼠流只能默默增加error
```
#### 多层哈希的作用
单层哈希可能发生冲突(多个项哈希到同一个桶),多层哈希通过冗余来解决:
- 同一个项会由L个不同的哈希函数映射到L层的不同桶
- 查询时取所有层的最小值(保守估计)
- 即使部分桶冲突,也能获得准确的下界
**最终计数** = min(所有层中该项的count值)
#### Heavy Hitters 检测流程
```mermaid
flowchart TD
A[数据流新项 x] --> B[计算L个哈希]
B --> C[访问L个桶]
C --> D{是否为守护项?}
D -->|是| E[count++]
D -->|否| F[计算替换概率]
F --> G{触发替换?}
G -->|是| H[替换并重置count=1]
G -->|否| I[error++]
E --> J[继续]
H --> J
I --> J
```
查找Top K时,只需遍历所有桶,收集 `count ≥ 阈值` 的候选项。
### 衰减机制
#### 为什么需要衰减?
**问题场景**:
```
10:00-10:05 IP=10.0.0.1 出现 1000 次 → 成为大象流,占据桶
10:06-12:00 IP=10.0.0.1 不再出现,但其count=1000依然存在
12:01 IP=10.0.0.2 频繁出现,但无法抢占count=1000的桶
```
如果不衰减,过时的大象流会持续占用资源,阻碍新大象流的检测。
#### 衰减机制的工作原理
HeavyKeeper 通过周期性衰减来解决这个问题:
**方法1:时间窗口衰减(推荐)**
```python
def periodic_decay():
每经过 Δt 时间,所有桶的 count 和 error 乘以衰减因子 α
count = count × α
error = error × α
其中 α ∈ (0, 1),通常 α = 0.9 或 0.99
```
**方法2:基于老化(Aging)**
```python
def aging(bucket, current_time):
elapsed = current_time - bucket.last_update_time
decay = exp(-λ × elapsed) # λ 是衰减速率
bucket.count = bucket.count × decay
```
#### 衰减机制的数学效果
**时间窗口视角**:
```
衰减因子 α = 0.99,窗口大小 = N
N时刻前的权重:0.99^N ≈ 0.366 ← 仅保留36.6%
2N时刻前的权重:0.99^2N ≈ 0.134 ← 只保留13.4%
```
这意味着:越久远的计数对当前统计影响越小,让算法能够"遗忘"过时的流。
#### 衰减规则示例
| 场景 | 原 count | 衰减后 count | 解析 |
|------|----------|-------------|------|
| 持续活跃的大象流 | 1000 | 990 (×0.99) | 持续补充,衰减不影响地位 |
| 最近消失的大象流 | 1000 | 366 (×0.99^100) | 100个周期后快速衰减,让出桶 |
| 新大象流 | 0 → 10 | 10 (刚开始) | 有机会竞争已衰减的桶 |
#### 衰减带来的好处
| 优势 | 说明 |
|------|------|
| **自适应流行度漂移** | 热点变化时,旧热点会自动失去守桶权 |
| **滑动窗口效果** | 只关注最近时间窗口内的频率,而非历史总和 |
| **防止资源垄断** | 过时的大象流不会长期占用桶资源 |
#### 衰减与守桶的协同
衰减机制和守桶机制协同工作,形成一个动态平衡:
```mermaid
graph LR
A[大象流活跃] --> B[count快速累积]
B --> C[占据守桶位置]
C --> D{时间流逝}
D -->|持续活跃| E[保持守桶]
D -->|停止活跃| F[衰减降低count]
F --> G{新竞争者?}
G -->|有| H[被替换,让出桶]
G -->|无| I[继续衰减直至清理]
```
## 关键参数
| 参数 | 说明 | 典型值 |
|------|------|--------|
| **m** | 每层桶的数量 | 2^15 ~ 2^20 |
| **L** | 哈希层数 | 3 ~ 5 |
| **θ** | 频率阈值 | 0.001 ~ 0.01 |
| **α** | 衰减因子 | 0.9 ~ 0.99 |
| **Δt** | 衰减周期 | 根据应用场景 |
## 性能特征
### 空间复杂度
- 空间复杂度: **O(m × L)**
- 每桶存储: item (~8字节) + count (~4字节) + error (~4字节)
### 时间复杂度
| 操作 | 时间复杂度 | 说明 |
|------|-----------|------|
| **插入** | O(L) | 对每层进行哈希和更新 |
| **查询** | O(L) | 取所有层最小值 |
| **衰减** | O(m×L) | 批量处理所有桶 |
## 优势与局限
### 优势
- **大象流识别准确**: 守桶机制确保高频项持续占据资源
- **老鼠流过滤**: 低频项很难干扰大象流统计
- **自适应流行度变化**: 衰减机制处理热点漂移
- **内存高效**: 恒定空间,不受数据流规模影响
### 局限性
- **参数敏感**: m、L、α 等参数需要根据数据特征调优
- **哈希冲突**: 极端情况下可能产生误报或漏报
- **衰减延迟**: 热点切换时需要一定时间生效
## 应用场景
### 典型用例
1. **网络流量分析**: 识别高频 IP 地址或端口(大象流)
2. **DDoS 防护**: 检测异常高频流量,过滤老鼠流
3. **实时推荐**: 发现用户偏好热点,利用衰减实现热点漂移
4. **CDN 缓存**: 识别热门内容进行预加载
5. **日志分析**: 快速定位高频错误或异常事件
### 实际部署考虑
| 场景 | 大象流示例 | 老鼠流示例 | 衰减建议 |
|------|-----------|-----------|---------|
| 网络带宽监控 | P2P下载、视频流 | 正常网页浏览 | 较慢衰减(α=0.99) |
| DDoS检测 | 攻击源IP | 正常用户IP | 快速衰减(α=0.9) |
| 搜索热门 | 热门关键词 | 长尾搜索 | 中等衰减(α=0.95) |
## 参考实现
### 伪代码
```python
class HeavyKeeper:
def __init__(self, m, L, threshold, decay_factor):
self.m = m # 每层桶数
self.L = L # 哈希层数
self.threshold = threshold
self.decay_factor = decay_factor # 衰减因子
# 初始化多层 sketch
self.buckets = [[KeeperBucket() for _ in range(m)]
for _ in range(L)]
# 初始化哈希函数
self.hash_funcs = [get_hash_func(i) for i in range(L)]
def insert(self, item, timestamp):
for layer in range(self.L):
idx = self.hash_funcs[layer](item) % self.m
bucket = self.buckets[layer][idx]
if bucket.item == item:
# 守护项匹配,直接计数(大象流强化)
bucket.count += 1
bucket.last_seen = timestamp
else:
# 计算替换概率
estimated_freq = self._estimate_freq(item)
replace_prob = min(1, estimated_freq / bucket.count)
if random.random() < replace_prob:
# 替换为新项(大象流夺权)
bucket.item = item
bucket.count = 1
bucket.error = bucket.count
bucket.last_seen = timestamp
else:
# 不替换,仅增加误差(老鼠流被阻拦)
bucket.error += 1
def apply_decay(self, current_time):
"""应用衰减机制"""
for layer in range(self.L):
for bucket in self.buckets[layer]:
elapsed = current_time - bucket.last_seen
if elapsed > DECAY_INTERVAL:
bucket.count *= self.decay_factor
bucket.error *= self.decay_factor
# 归零清理
if bucket.count < 1:
bucket.item = None
bucket.count = 0
bucket.error = 0
def query(self, item):
"""查询Item的频率估计"""
min_count = float('inf')
for layer in range(self.L):
idx = self.hash_funcs[layer](item) % self.m
bucket = self.buckets[layer][idx]
if bucket.item == item:
min_count = min(min_count, bucket.count)
return min_count if min_count != float('inf') else 0
def get_top_k(self, k):
"""获取Top K大象流"""
candidates = {}
for layer in range(self.L):
for bucket in self.buckets[layer]:
if bucket.count >= self.threshold and bucket.item:
item = bucket.item
candidates[item] = max(candidates.get(item, 0),
bucket.count)
# 返回 Top-k
return sorted(candidates.items(),
key=lambda x: x[1],
reverse=True)[:k]
```
## 相关算法对比
| 算法 | 空间复杂度 | 大象流准确性 | 老鼠流过滤 | 衰减支持 | 适用场景 |
|------|-----------|------------|-----------|---------|---------|
| **HeavyKeeper** | O(m×L) | 高 | 优秀 | 原生支持 | 高速数据流,需检测热点漂移 |
| **Count-Min** | O(m×L) | 中 | 无 | 需额外实现 | 通用频率统计 |
| **SpaceSaving** | O(k) | 中 | 好 | 手动实现 | 固定数量Top-K |
| **LossyCounter** | O(kε) | 高 | 一般 | 手动实现 | 离线精确统计 |
## 参考资料
- HeavyKeeper: Streaming Heavy Hitters Detection with Known Error Bounds (2020)
- Count-Min Sketch: An Improved Data Stream Summary
- Streaming Algorithms for Finding Heavy Hitters
## 关联笔记
- [[CS/NET/Count-Min-Sketch.md]]
- [[CS/DS/HashMap.md]]
- [[CS/NET/Network-Flow-Analysis.md]]
+45
View File
@@ -0,0 +1,45 @@
---
tags: [CS, NET, network]
create time: 2026-04-17
---
# 计算机网络
## 概述
计算机网络是物理上分散的计算机通过通信线路连接起来,在网络软件的管理下实现资源共享和信息传递的系统。
## 核心概念
### OSI七层模型
- 物理层、数据链路层、网络层
- 传输层、会话层、表示层、应用层
### TCP/IP协议栈
- IP协议、TCP/UDP协议
- HTTP/HTTPS、DNS、SMTP等应用层协议
- 网络地址与路由
### 网络架构
- 客户端-服务器架构
- P2P架构
- 分布式系统
### 网络安全
- 加密与解密
- SSL/TLS
- 防火墙与VPN
## 学习重点
- TCP/IP协议详解
- HTTP协议与Web服务
- 套接字编程
- 网络性能优化
## 实践建议
- 使用Wireshark抓包分析
- 编写网络应用
- 搭建本地网络环境
- 理解常见网络问题
+208
View File
@@ -0,0 +1,208 @@
---
tags: [network, protocol, theory, cs]
create time: 2026-04-17 12:15
---
# 网络协议分析基础
## 概述
网络协议分析是理解网络通信的核心技术,通过分析数据包的结构和内容,可以深入理解网络协议的工作原理和通信机制。
## 正文
### TCP 三次握手与四次挥手
#### 三次握手 (SYN, SYN-ACK, ACK)
```
客户端 服务器
| |
| --- SYN, seq=x --------------------> |
| |
| <--- SYN, ACK, seq=y, ack=x+1 ------ |
| |
| --- ACK, seq=x+1, ack=y+1 ---------> |
| | 连接建立
```
**各字段含义:**
- **SYN**: 同步标志,用于建立连接
- **ACK**: 确认标志,表示确认收到
- **seq**: 序列号,确保数据有序传递
- **ack**: 确认号,表示期望收到的下一个序列号
**抓包特征:**
1. 第一个包:SYN 标志位为 1,ACK 为 0
2. 第二个包:SYN 和 ACK 都为 1
3. 第三个包:ACK 为 1,SYN 为 0
#### 四次挥手 (FIN, ACK, FIN, ACK)
```
客户端 服务器
| |
| --- FIN, seq=x --------------------> | 主动关闭
| |
| <--- ACK, seq=y, ack=x+1 ----------- |
| | 半关闭
| <--- FIN, seq=y ------------------- | 被动关闭
| |
| --- ACK, seq=x+1, ack=y+1 ---------> |
| | 连接关闭
```
**状态转换:**
- FIN_WAIT_1: 主动关闭方发送 FIN
- FIN_WAIT_2: 主动关闭方收到 ACK,等待对方 FIN
- CLOSE_WAIT: 被动关闭方收到 FIN,进入半关闭状态
- LAST_ACK: 被动关闭方发送 FIN
- TIME_WAIT: 主动关闭方收到 FIN,等待 2MSL 后完全关闭
### HTTP 协议分析
#### 请求结构
```
Method Request-URI HTTP-Version\r\n
Header-Name: Header-Value\r\n
\r\n
Message-Body
```
**常见方法:**
- **GET**: 获取资源
- **POST**: 提交数据
- **PUT**: 更新资源
- **DELETE**: 删除资源
- **HEAD**: 获取响应头
- **OPTIONS**: 获取支持的方法
**常用请求头:**
```
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/json
Content-Type: application/json
Authorization: Bearer token
Cookie: session=xxx
```
#### 响应结构
```
HTTP-Version Status-Code Reason-Phrase\r\n
Header-Name: Header-Value\r\n
\r\n
Message-Body
```
**状态码分类:**
- **2xx**: 成功 (200 OK, 201 Created, 204 No Content)
- **3xx**: 重定向 (301 Moved Permanently, 302 Found, 304 Not Modified)
- **4xx**: 客户端错误 (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found)
- **5xx**: 服务器错误 (500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable)
**常用响应头:**
```
Content-Type: application/json; charset=utf-8
Content-Length: 1234
Cache-Control: max-age=3600
ETag: "abc123"
Set-Cookie: session=xxx; Path=/; HttpOnly
```
### TLS/SSL 加密通信
#### TLS 握手流程
```mermaid
sequenceDiagram
participant C as 客户端
participant S as 服务器
C->>S: ClientHello<br/>(支持的加密套件、随机数)
S-->>C: ServerHello<br/>(选择的加密套件、随机数、证书)
S-->>C: Certificate<br/>(服务器证书)
S-->>C: ServerHelloDone
C->>S: ClientKeyExchange<br/>(预主密钥,用服务器公钥加密)
C->>S: ChangeCipherSpec<br/>(通知后续使用加密通信)
C->>S: Finished<br/>(握手完成,加密验证)
S-->>C: ChangeCipherSpec
S-->>C: Finished
Note over C,S: 开始加密通信
```
**关键概念:**
- **证书链**: 从服务器证书到根证书的信任链
- **预主密钥**: 通过非对称加密传输,用于生成会话密钥
- **会话密钥**: 通过预主密钥和双方随机数生成,用于对称加密
- **SSL Pinning**: 客户端验证服务器证书,防止中间人攻击
### 数据包分析要点
#### 抓包指标
**性能指标:**
- **RTT (Round Trip Time)**: 往返时延
- **吞吐量**: 单位时间传输的数据量
- **丢包率**: 丢失的数据包比例
- **重传率**: 重发数据包的比例
**连接指标:**
- **TCP 窗口大小**: 接收窗口和拥塞窗口
- **连接状态**: ESTABLISHED, TIME_WAIT 等
- **连接复用**: Keep-Alive, HTTP/2 连接复用
#### 过滤技巧
**基于协议过滤:**
```
# HTTP/HTTPS
http or http2 or ssl
# TCP 特定标志
tcp.flags.syn == 1 # SYN 包
tcp.flags.ack == 1 # ACK 包
tcp.flags.fin == 1 # FIN 包
tcp.flags.reset == 1 # RST 包
```
**基于内容过滤:**
```
# 特定 User-Agent
http.user_agent contains "Chrome"
# 特定域名
http.host == "example.com"
# HTTP 错误
http.response.code >= 400
# 请求体内容
http.file_data contains "keyword"
```
**基于网络层过滤:**
```
# 源/目标地址
ip.src == 192.168.1.1
ip.dst == 192.168.1.1
# 端口范围
tcp.port >= 1024 and tcp.port <= 65535
```
## 关联笔记
- [[CS/TOOLS/网络抓包]]
- [[CS/SECURITY/网络安全基础]]
- [[CS/OS/TCP 协议详解]]
## 参考资源
- RFC 文档: https://www.rfc-editor.org/
- Wireshark 指南: https://www.wireshark.org/docs/wsug_html_chunked/