新兴攻击面与专项安全 — Web3·数据合规·实战·总汇
📚 本册属于《13-新兴攻击面与专项安全-实战专题》共 7 册中的 第 6 册 本册内容:第十一~十四章:Web3、数据合规、综合实战、全书总汇(共 3,709 行)
全 7 册导航:
分册 内容 规模 00-开篇与名词速查 第 0 册 名词速查 A~F(读任何一章前先扫一眼) 263 行
| 01-应用层安全(AI·API) | 第 1 册 第一、二章:AI/LLM 应用安全、API 安全 | 10,138 行 |
| 02-接口与客户端(GraphQL·移动·IoT) | 第 2 册 第三五章:GraphQL/gRPC、移动端、小程序、实时通信与 IoT | 21,168 行 |
| 03-主机与内网渗透 | 第 3 册 第六、七章:主机与操作系统安全、内网横向移动与域渗透 | 21,495 行 |
| 04-数字取证与供应链 | 第 4 册 第八、九章:数字取证与应急响应 DFIR、软件供应链安全 | 17,172 行 |
| 05-云原生与Serverless | 第 5 册 第十章:新兴云原生与 Serverless 安全 | 12,063 行 |
| 06-Web3·数据合规·实战·总汇 | 第 6 册 第十一十四章:Web3、数据合规、综合实战、全书总汇 | 3,709 行 ← 本册 |
术语看不懂?回 00-开篇与名词速查 或 00-名词速查手册 Ctrl+F。
第十一章:Web3 与智能合约安全(代码即法律)
本章定位:前面十章,攻击对象是“运行在别人服务器上的程序”——Web、API、主机、云、K8s。 这一章换一个完全不同的世界:代码跑在区块链上,而且直接管钱。 智能合约一旦部署就几乎无法修改,一个漏洞可能就是几千万美元的直接损失。 这不是“网络安全”的附属品,而是一门独立的攻防手艺——合约审计。
为什么普通工程师也要懂一点:
- 哪怕你不写合约,面试里“重入攻击”“整数溢出”已经是高频题
- Web3 的攻击思路(经济攻击、前置交易)能反过来启发你对传统系统的思考
- “代码即法律”的世界里,安全设计必须前置到写代码那一刻,这个理念对任何系统都成立
本章范围:只讲技术安全(合约漏洞、钱包密钥、预言机、MEV 等), 不涉及发币、炒币、投资建议等金融行为。安全审计是一份正经的技术工作。
11.1 Web3 基础与攻击面全景
11.1.1 名词先行课:把 Web3 讲成大白话
很多人学不会 Web3 安全,是因为上来就被“区块链、去中心化、共识机制、预言机”这些词砸晕。 这一节先把最核心的几个名词,用“订酒店/存钱/转账”这类生活场景讲透。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词一:区块链(Blockchain)
一句话定义:一本【所有人共享、谁也不能偷偷改】的公共账本。
生活类比:想象一个村,村里不设银行,全村人共同记一本账。
每记满一页(一个"区块"),就全村长签字确认,然后用胶水粘在上一页后面("链")。
谁想改第 3 页,就得把第 3 页之后所有页都撕掉重写,
而且全村人手里的副本都得同时改——几乎不可能,所以账本"不可篡改"。
三个关键性质:
· 不可篡改:已上链的数据,改的成本极高(要控制全网算力/节点)
· 公开透明:所有人都能查每笔交易(所以"匿名"其实只是"假名")
· 去中心化:不依赖某一个服务器/机构,靠共识机制维护
致命缺点:慢、贵(要付手续费)、存储极小、写错了也退不回来。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词二:智能合约(Smart Contract)
一句话定义:一段【部署到区块链上、自动执行、无法修改】的代码。
生活类比:自动售货机。
你把钱投进去(发起交易),它自动吐饮料(执行逻辑),
中间不需要售货员(不需要信任任何中介)。
但售货机一旦造出来摆街上,你就没法改了——里面有 bug 也只能让它继续卖。
为什么叫"合约":因为代码里写的就是"规则",比如"存 100 能取 110",
谁来执行都一样,谁也无法赖账——所以叫"代码即法律(Code is Law)"。
★ 安全的关键:因为【无法修改 + 直接管钱】,所以 bug 的代价被无限放大。
传统程序有 bug 可以热修复、回滚;合约有 bug,只能眼睁睁看钱被转走。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词三:Gas(手续费)
一句话定义:执行合约每一步操作,都要付的"燃料费"。
生活类比:出租车计费。
上车(发起交易)先付起步价,每跑一公里(每执行一步计算/存储)再跳一次表。
"油"就是 Gas,Gas 单价(gas price)随网络拥堵浮动。
安全相关性:★ 很多 DoS 攻击就是"让你的操作耗尽 Gas"(gas 不足导致交易回滚)。
一个会无限循环或无限增长的数组,就是一颗"Gas 炸弹"。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词四:钱包 / 私钥 / 助记词
一句话定义:钱包 = 私钥的容器;私钥 = 你资产的唯一"密码";助记词 = 私钥的人类可读形式。
生活类比:私钥就是你家保险柜的【唯一一把钥匙】。
谁拿到钥匙,谁就能打开柜子拿走所有东西——不需要身份证、不需要密码、不需要你同意。
助记词(12/24 个英文单词)是把这把"钥匙"翻译成你能抄下来的形式。
★ 安全铁律:私钥/助记词一旦泄露 = 资产永久丢失,无法找回。
"not your keys, not your coins"(钥匙不在你手里,币就不是你的)。
这也是钓鱼、助记词诈骗、假钱包 App 泛滥的根本原因。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词五:DeFi / 预言机 / 闪电贷(先混个脸熟,后面展开)
DeFi(去中心化金融):把"银行/交易所"搬到区块链上的应用(借贷、交易、质押)。
生活类比:没有柜台的"自助银行",规则全靠智能合约执行。
预言机(Oracle):帮链上合约"读外部世界数据"的桥梁(如 ETH 价格、天气)。
生活类比:链上是个封闭的房间,看不到外面。预言机就是往房间里"递纸条"的人——
纸条上写"现在 ETH 是 3000 刀"。★ 递纸条的人如果被收买/被操纵,整个合约就瞎了。
闪电贷(Flash Loan):在同一笔交易里"借一大笔钱 → 用完 → 立刻还"的零抵押贷款。
生活类比:银行允许你在同一秒钟内"先借 1 亿、花完、马上还回",只要这 1 秒内能还上就行。
★ 攻击者用它"凭空"获得巨量资金,去操纵市场/预言机,这正是闪电贷攻击的可怕之处。
11.1.2 为什么智能合约安全这么“特殊”
传统程序 vs 智能合约,四个根本区别,决定了攻防思路完全不同:
| 维度 | 传统程序 | 智能合约 |
|---|---|---|
| 发布后能否改 | 能热修、能回滚 | ★ 基本不能(除非预埋升级逻辑,而升级逻辑本身又是攻击面) |
| 出 bug 的后果 | 数据损坏、被黑、可恢复 | ★ 直接丢钱,且不可逆,链上转账无法撤销 |
| 谁在跑 | 你自己的服务器,你控制 | 全网节点都跑,谁都能调用你合约的公开函数 |
| 可见性 | 代码可闭源 | ★ 代码(字节码)公开,攻击者可以先读你的代码再打你 |
| 调用者 | 有身份认证、有边界 | 任何人(任何地址)都能调,没有“登录”概念 |
结论一句话:合约是你把“带 bug 的钱包”公开挂在街上,还贴了张“里面有钱”的告示。
11.1.3 Web3 攻击面全景图(六层)
把 Web3 安全拆成六层,从上到下,攻击面越来越“深”:
┌─────────────────────────────────────────────────────────────────┐
│ 第 1 层 用户层:钱包、助记词、钓鱼网站、假钱包 App、签名诈骗 │ ← 11.9
├─────────────────────────────────────────────────────────────────┤
│ 第 2 层 前端 dApp 层:网站被篡改、XSS、接口劫持、假合约地址 │ ← 复用第 3 章
├─────────────────────────────────────────────────────────────────┤
│ 第 3 层 智能合约层:重入、溢出、逻辑漏洞、访问控制缺失 │ ← 11.2~11.8 ★ 本章重点
├─────────────────────────────────────────────────────────────────┤
│ 第 4 层 协议/经济层:预言机操纵、闪电贷、MEV、套利攻击 │ ← 11.5~11.7
├─────────────────────────────────────────────────────────────────┤
│ 第 5 层 基础设施层:节点 RPC、桥(跨链桥)、预言机网络 │ ← 简述
├─────────────────────────────────────────────────────────────────┤
│ 第 6 层 生态层:项目方跑路(rug pull)、治理攻击、私钥托管风险 │ ← 11.8/11.9
└─────────────────────────────────────────────────────────────────┘
本章把火力集中在第 3、4 层——这是“智能合约安全审计”的本职工作, 也是面试里真正考你的地方。第 1、6 层只讲最常见的几种(钱包、助记词、Approve)。
11.1.4 智能合约的攻击思路,和传统 Web 有什么不同
传统 Web 攻击者想的是:“我怎么绕过你的校验,做你没授权我做的事。”
智能合约攻击者想的是:“你的代码在什么状态下会做出错误的经济决策?我能不能构造一笔交易, 把你没想到的调用顺序、你没想到的价格、你没想到的调用者塞进去?”
三个核心差异(记住这三个,后面所有漏洞都是它们的展开):
-
可组合性(Composability):合约能互相调用,A 调 B,B 又回调 A。 攻击者可以“插入”一个恶意合约进来,在你执行到一半的时候打断你、劫持控制流 → 这就是重入攻击的土壤。
-
经济激励:合约的“正确性”不是“逻辑不报错”,而是“经济上不亏”。 攻击者会精算:我投入多少 Gas、能套走多少币。只要利润 > 成本,就有人干。
-
交易原子性 + 前置可见:一笔交易要么全部成功要么全部回滚; 而且所有待执行交易都在公开的 mempool 里排队,别人能先看到你的交易、再抢在你前面下手 → MEV/前置交易。
11.1.5 一个“最小可用”的漏洞示例:会漏钱的银行
在看正式漏洞之前,先看一个 20 行的“银行合约”,它几乎集齐了新手会犯的所有错。 后面每一节都会回到这个例子做对照。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ★ 反面教材:一个漏洞百出的"存款银行",用来做错误示范
contract BadBank {
// 记录每个地址存了多少钱
mapping(address => uint256) public balances;
// 存钱:调用者往合约里打钱,记一笔账
function deposit() public payable {
balances[msg.sender] += msg.value;
}
// 取钱:把余额转回给调用者
function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "no balance");
// ★ 漏洞 1:先转钱,后扣账 —— 经典的"先斩后奏",为重入攻击埋雷
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "transfer failed");
// ★ 漏洞 2:扣账写在了转账之后,如果上面的 call 重入进来,这里还没执行
balances[msg.sender] = 0;
}
// 查询合约里一共有多少钱
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
这个
withdraw的问题就是下一节重入攻击的教科书案例: 它在“扣账之前”就先把钱转出去了,而且用的是会触发对方回调的call。 攻击者只要写一个“收到钱就立刻再调用一次 withdraw”的合约,就能把银行里的钱反复套出来。
★ 别急着看答案,先记住这个例子的两个关键点:
msg.sender.call{value: ...}("")会把控制权交还给对方(对方能执行任意代码)- 状态更新(扣账)发生在外部调用之后,中间留出了一段“危险窗口”
11.2 智能合约经典漏洞总览
11.2.1 十大漏洞类别速查表
先把“智能合约会出哪些事”画一张全景表。面试时你至少要能把这十类名字和一句话危害说全。
| # | 漏洞类别 | 一句话定义 | 一句话危害 | 详参 |
|---|---|---|---|---|
| 1 | 重入攻击 Reentrancy | 转账时对方回调你的合约,趁你还没扣账反复取钱 | 一秒钟把合约余额掏空 | 11.3 |
| 2 | 整数溢出/下溢 Overflow | 数字加爆了绕回 0,或减成负数变成天文数字 | 凭空多出巨额代币 | 11.4 |
| 3 | 未检查返回值 Unchecked return | 调用失败了你却不知道,继续往下执行 | 逻辑悄悄失效 | 11.2 |
| 4 | 未检查调用 Unchecked call | call 返回值没判断,转账失败当成功 |
资金假象 | 11.2 |
| 5 | 访问控制缺失 Missing ACL | 关键函数没加“只有管理员能调” | 谁都能抽走钱 | 11.2 |
| 6 | tx.origin 鉴权 | 用 tx.origin 判断“是不是本人”,可被中间合约绕过 |
授权被盗用 | 11.2 |
| 7 | 预言机/价格操纵 Oracle manip. | 合约用“能被操纵的池子价格”做决策 | 低价买高价卖套利 | 11.5 |
| 8 | 闪电贷攻击 Flash loan | 借巨款瞬间操纵市场,一锤子套利 | 一次交易卷走千万 | 11.6 |
| 9 | 前置交易/MEV | 别人看到你的交易,抢在你前面下单 | 你被“三明治”夹 | 11.7 |
| 10 | 代理合约陷阱 Proxy pitfall | 可升级合约的存储冲突/函数遮蔽 | 升级时把数据覆盖 | 11.2 |
11.2.2 三个“防不胜防”的基础错误(虽小但致命)
在深入重入攻击之前,先把三个“看起来低级、但真实项目里反复出现”的小错讲清楚。 它们属于“代码审计时第一眼就要扫”的东西。
错误一:未检查返回值(Unchecked Return Value)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ★ 反面教材:transferFrom 可能失败(比如对方没授权),但这里没判断
contract Unchecked {
IERC20 public token;
function badTransfer(address to, uint256 amount) public {
// ★ 漏洞:transferFrom 返回 bool,这里直接忽略。
// 如果转账失败(余额不足/没授权),下面的记账还是会执行,
// 结果就是"账记了,钱没到"。
token.transferFrom(msg.sender, to, amount);
recordBookkeeping(to, amount); // 假装钱已经到了
}
function goodTransfer(address to, uint256 amount) public {
// 正确写法:检查返回值,失败就回滚整个交易
require(token.transferFrom(msg.sender, to, amount), "transfer failed");
recordBookkeeping(to, amount);
}
function recordBookkeeping(address, uint256) internal pure {}
}
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
白话:你叫快递员送东西,他没送到也不告诉你,你以为送到了。 传统 Web 里“调用失败”通常抛异常;合约里很多标准接口(尤其 ERC20)用返回值表示成败, 你不检查,它照样往下走。
错误二:未检查 call 返回值(Unchecked Call)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract UncheckedCall {
function badWithdraw(address payable to, uint256 amount) public {
// ★ 漏洞:call 是"低级转账",失败不会自动回滚,只返回 false。
// 这里不检查,转账失败了也不知道。
to.call{value: amount}("");
}
function goodWithdraw(address payable to, uint256 amount) public {
// 正确写法:检查返回值
(bool ok, ) = to.call{value: amount}("");
require(ok, "withdraw failed");
}
}
★ 面试加分点:
transfer/send会自动回滚但固定消耗 2300 gas(容易被拒绝),call不限制 gas 但必须手动检查返回值。现代推荐用call+ 手动检查。 这三点区别(transfer/send/call)是高频考点。
错误三:用 tx.origin 做鉴权(Authorization via tx.origin)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Phishable {
address public owner;
constructor() {
owner = msg.sender;
}
// ★ 漏洞:用 tx.origin 判断"是不是 owner 在操作"
function badOnlyOwner() public {
require(tx.origin == owner, "not owner");
// ... 关键操作
}
function goodOnlyOwner() public {
// 正确写法:用 msg.sender
require(msg.sender == owner, "not owner");
// ... 关键操作
}
}
// 攻击者合约:诱导 owner 调用它,从而"借" owner 的身份去调 badOnlyOwner
contract Attacker {
Phishable target;
constructor(Phishable _target) {
target = _target;
}
// ★ 攻击:owner 如果调了这个函数,那么在这一层:
// tx.origin = owner(最初发起交易的人)
// msg.sender = Attacker 合约(当前这一层的直接调用者)
// 于是 target.badOnlyOwner() 里的 tx.origin 仍然等于 owner,鉴权被绕过
function attack() public {
target.badOnlyOwner();
}
}
白话:
tx.origin是“最初按下按钮的人”,msg.sender是“当前跟你说话的人”。 你用“最初按下按钮的人”做鉴权,攻击者只要骗 owner 点一下它的合约, 就能让 owner 的“最初身份”去执行危险操作。 ★ 铁律:鉴权只用 msg.sender,永远不要用 tx.origin(除非你明确知道自己在做什么)。
11.2.3 访问控制缺失(Missing Access Control)
这是真实项目里最致命、最普遍的一类——重要函数忘了加权限限制,或者权限加错了。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
contract Vault is Ownable {
// ★ 漏洞:这个"提取全部资金"的函数没加 onlyOwner,
// 任何地址都能调用它把合约里的钱全转走
function badDrainAll() public {
payable(msg.sender).transfer(address(this).balance);
}
// 正确写法:加 onlyOwner 修饰符(继承自 OpenZeppelin 的 Ownable)
function goodDrainAll() public onlyOwner {
payable(msg.sender).transfer(address(this).balance);
}
}
白话:金库的大门忘装锁了。合约里的函数默认谁都能调(这是和传统 Web 最大的区别—— 传统 API 你得先“登录”,合约函数默认“对全网开放”)。 ★ 审计第一动作:把每个
function过一遍,问一句“这个函数是任何人都能调吗?该不该限权限?”
★ 常见踩坑:
Ownable的owner默认是部署者;如果部署脚本忘了transferOwnership, 那么 owner 就是一个“部署用的临时地址”,这个地址的私钥一旦丢失,合约就“没人能管理”了。
11.2.4 代理合约陷阱(Proxy Pitfall,可升级合约的坑)
“可升级合约”(Proxy)解决了“合约不能改”的问题,但它自己引入了一堆新坑。 这里只讲两个最经典的,面试能说出来就很加分。
陷阱一:存储冲突(Storage Collision)
白话:代理合约里,逻辑合约的变量是按"位置"(slot 0、slot 1、slot 2...)存的,
而不是按"名字"存的。升级后,如果新逻辑合约在 slot 0 放了一个不同类型的变量,
就会把旧数据"张冠李戴",导致数据错乱甚至被覆盖。
★ 规则:升级时,变量的【声明顺序】绝对不能变,只能在【末尾追加】新变量。
陷阱二:函数选择器遮蔽(Function Clashing)
白话:Solidity 调用函数其实靠的是"函数签名算出来的 4 字节选择器"(如 transfer 是 0xa9059cbb)。
如果代理合约里也有一个同名同参函数,代理自己的函数会"遮蔽"逻辑合约的函数,
造成调用了错误的代码。
★ 规则:代理合约自己尽量不放任何业务函数,只放"转发 + 管理"逻辑。
★ 加分点:可升级合约的推荐实现是 EIP-1967(把实现地址存在一个“固定 slot”里)+ 透明代理(Transparent Proxy), 而不是简单的 delegatecall 转发。
11.3 重入攻击(Reentrancy)——合约安全第一课
11.3.1 什么是重入,用大白话讲
一句话定义:你(合约)在转账的时候,把钱先递了出去、但账还没改,
对方趁这个空档,又回头喊了你一次"再取一次",你就又把钱递了一遍……循环往复,直到掏空。
生活类比:银行柜台的"先给钱、后记账"。
你去取 100 块,柜员先把 100 块递给你(控制权交给你了),
你接到钱的那一瞬,发现他账本上还没划掉你的余额,于是立刻说"再取 100",
柜员又递给你 100……直到柜台里的钱全被你拿走。
★ 柜员错在哪?他应该【先扣账、再给钱】,就不存在这个空档。
为什么合约里会天然出现这个空档?
因为 Solidity 里给合约转账用的 call,会把执行权交还给收款方(触发它的 receive/fallback 函数)。
如果收款方是一个攻击者写的合约,它就能在这个“交还控制权”的瞬间,再调用你的取款函数一次。
而你的合约这时还没来得及把余额扣掉,于是它又能取一次。
11.3.2 经典重入攻击完整演示
先看一个“标准受害者”合约,再看攻击合约怎么打它:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ★ 受害者:有漏洞的"银行"
contract VulnerableBank {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing to withdraw");
// ★ 致命顺序:先转账(触发对方回调),后扣账
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "withdraw failed");
// 扣账写在这里 —— 但攻击者已经在上面的 call 里重入并取走了更多钱
balances[msg.sender] = 0;
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
攻击者合约:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./VulnerableBank.sol";
// ★ 攻击者:一个"收到钱就再取一次"的合约
contract ReentrancyAttacker {
VulnerableBank public bank;
uint256 public attackCount;
constructor(address _bank) {
bank = VulnerableBank(_bank);
}
// 第一步:先存一点钱,让自己有余额可提
function attack() external payable {
require(msg.value >= 1 ether, "need some deposit");
bank.deposit{value: 1 ether}(); // 存 1 ether
bank.withdraw(); // 开始第一次取款
}
// ★ 关键:当银行调用 call 给我们转账时,会自动触发这个 receive 函数
receive() external payable {
// 只要银行里还有钱,就再取一次
if (address(bank).balance > 0 && attackCount < 10) {
attackCount++;
bank.withdraw(); // ★ 重入!此时银行的 balances[我们] 还没被扣成 0
}
}
// 取走战利品
function collect() external {
payable(msg.sender).transfer(address(this).balance);
}
}
攻击时序图(用文字画出来):
攻击者 attack():
1. 存 1 ether 到银行 → balances[攻击者] = 1 ether
2. 调用 withdraw()
├─ amount = 1 ether(读余额)
├─ call 给攻击者转账 1 ether ──→ 触发攻击者的 receive()
│ ├─ 看到银行里还有钱 → 再调 withdraw()
│ │ ├─ amount = 1 ether(★ 余额还没扣!还是 1)
│ │ ├─ call 再转 1 ether ──→ 又触发 receive()
│ │ │ └─ ... 循环,直到把银行掏空
│ │ └─ 扣账 balances[攻击者] = 0(第 N 次才执行)
│ └─ 返回
└─ 扣账 balances[攻击者] = 0(第一次才执行,太晚了)
关键理解:每一层
withdraw在“读余额”时,看到的都还是旧值(因为上一层的“扣账”还没执行)。 于是同一个 1 ether 被反复取走。根因:状态更新(扣账)晚于外部调用(转账)。
11.3.3 重入的四种变体
面试官常问“重入攻击只有这一种吗”,你要能说出下面四种:
变体一:单函数重入(最常见)
就是上面这种——withdraw 自己反复调用自己。防御:CEI。
变体二:跨函数重入(Cross-function) A 函数转账(触发回调),攻击者在回调里调用另一个有同样缺陷的函数 B。 即使 A 函数自己做了 CEI,B 函数没做,照样被掏。
// 跨函数重入示意:withdraw 做了 CEI,但 transferTo 没做
contract CrossFunction {
mapping(address => uint256) public balances;
mapping(address => uint256) public pending;
function withdraw() public {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0; // 先扣账(CEI 做到了)
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "fail");
}
// ★ 这个函数里又有一处"先转账后记账",攻击者可在 withdraw 的回调里转进来打这个
function transferTo(address to) public {
uint256 amount = pending[msg.sender];
pending[msg.sender] = 0;
(bool ok, ) = payable(to).call{value: amount}("");
require(ok, "fail");
// ... 某些状态下这里仍有危险窗口
}
}
变体三:跨合约重入(Cross-contract) 攻击者调合约 A 的取款,在回调里调另一个合约 B 的函数,B 又调回 A。跨越多个合约的重入链。 防御本质一样:每个合约都要自己做好 CEI。
变体四:只读重入(Read-only Reentrancy) ★ 较新的手法:即使你用了 ReentrancyGuard 防住了“转账重入”, 攻击者仍可能利用“你的合约在一个价格/余额已更新但尚未最终结算的中间状态”, 从**只读函数(view)**读到不一致的数据,拿去误导另一个依赖你合约的协议。 防御:让外部依赖读到的状态始终保持一致,或使用“先更新状态再暴露”的最终性设计。
面试话术:“重入不只有一种,本质都是’外部调用时状态不一致’。常见四种:单函数、跨函数、跨合约、只读重入。 前三种靠 CEI + ReentrancyGuard 防,第四种要额外注意状态一致性和 finality。”
11.3.4 三种防御手段(都要会)
防御一:CEI(Checks-Effects-Interactions,检查-生效-交互)
口诀:先检查(Checks)→ 再改状态(Effects)→ 最后才碰外部(Interactions)。
把上面的 VulnerableBank 改成:
function withdraw() public {
uint256 amount = balances[msg.sender]; // Checks:读余额
require(amount > 0, "nothing"); // Checks:校验
balances[msg.sender] = 0; // Effects:★ 先扣账!
(bool ok, ) = msg.sender.call{value: amount}(""); // Interactions:最后才转账
require(ok, "fail");
}
这样即使对方回调重入,第二次进来时 balances 已经是 0,取不到了。
防御二:ReentrancyGuard(互斥锁)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ★ 用一个"锁"标记,禁止函数重入
contract GuardedBank {
mapping(address => uint256) public balances;
bool private locked; // ★ 锁
modifier noReentrancy() {
require(!locked, "reentrancy");
locked = true;
_; // 执行函数体
locked = false; // 结束解锁
}
function withdraw() public noReentrancy {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing");
balances[msg.sender] = 0;
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "fail");
// ★ 攻击者在回调里再调 withdraw,会撞上 locked == true,直接 revert
}
}
白话:给柜员装个“正在办理中”的牌子,办完这单才摘下来。 你在他办理中再喊他,他直接说“请稍等”。
防御三:Pull Payment(拉式支付,让用户自己来“提”,而不是你主动“推”给他)
思路:不主动给用户转账(推),而是记账,让用户自己调一个函数来"领取"(拉)。
这样你的合约里就尽量少出现"转账给外部地址"的 call,攻击面大幅缩小。
contract PullPayment {
mapping(address => uint256) public credits;
function requestWithdraw() public { /* 记账 credits[msg.sender] = x */ }
function withdraw() public { // 用户自己来拉
uint256 amount = credits[msg.sender];
credits[msg.sender] = 0; // 先扣
payable(msg.sender).transfer(amount); // 再给(transfer 只有 2300 gas,够用)
}
}
★ 三者关系:CEI 是【思想】、ReentrancyGuard 是【保险】、Pull Payment 是【架构上的根本规避】。 生产项目通常 CEI + ReentrancyGuard 一起上,高风险路径再用 Pull Payment。
11.3.5 真实案例:The DAO(2016,损失约 6000 万美元 ETH)
这是智能合约安全史上最重要的一件事,面试提到重入必谈。
- 背景:The DAO 是一个去中心化风投基金,用户往里面投 ETH 换投票权,也能“分拆”取回自己的 ETH。
- 漏洞:
splitDAO函数在“给用户返还 ETH”和“扣除用户余额”之间,存在和上面一模一样的重入窗口。 - 结果:攻击者反复调用,把合约里约 360 万 ETH 抽走(当时约 6000 万美元)。
- 后续:社区最终决定对以太坊硬分叉,把资金追回——这也直接导致以太坊分裂成 ETH(分叉后的主链)和 ETC(坚持“代码即法律、不追回”的旧链)。
★ 面试升华点:The DAO 事件暴露的不只是代码 bug,而是一个哲学冲突—— “代码即法律”(不可篡改、不追回) vs “用户资产必须保护”(分叉追回)。 这个事件之后,“重入攻击”和“先扣账再转账”成了所有合约审计的红线。
11.4 整数溢出与下溢(Integer Overflow / Underflow)
11.4.1 什么是溢出,用大白话讲
一句话定义:一个数字超过了它这个类型能表示的最大值(或最小值),就"绕圈"回到另一边。
生活类比:老式机械里程表。
它只有 6 位,最多显示 999999。再往前开 1 公里,就"咔哒"一声从 999999 跳回 000000。
这叫"上溢"(加爆了)。
反过来,从 0 再减 1,就绕回 999999,这叫"下溢"(减穿了)。
在 Solidity 里,uint256(无符号 256 位整数)能表示 0 ~ 2^256 - 1(一个天文数字)。
但如果一个数已经是最大值,再加 1,就会绕回 0;如果是 0,再减 1,就会变成最大值。
11.4.2 经典下溢漏洞:凭空造币
这是最经典的“下溢造币”场景,面试高频:
// SPDX-License-Identifier: MIT
pragma solidity ^0.4.18; // ★ 注意:0.4.x 时代没有内置溢出检查
contract Token {
mapping(address => uint256) public balances;
uint256 public totalSupply;
function transfer(address to, uint256 amount) public returns (bool) {
// ★ 漏洞(0.4.x):如果 balances[msg.sender] < amount,减法会"下溢"
// 得到一个接近 2^256 的天文数字,于是余额瞬间爆炸,代币凭空多出来
balances[msg.sender] -= amount;
balances[to] += amount;
return true;
}
}
白话:你账户里只有 5 块钱,却转账 10 块。老版本合约算
5 - 10, 里程表从 5 往前倒 10 格,直接绕到 “999…99”,你的余额瞬间变成天文数字。
11.4.3 Solidity 0.8.0 的分水岭
这是面试最爱问的版本差异点:
| 版本 | 溢出行为 | 防护方式 |
|---|---|---|
| < 0.8.0 | ★ 不会报错,静默溢出 | 必须手动用 SafeMath 库 |
| >= 0.8.0 | ★ 默认自动检查,溢出直接 revert | 一般不需要 SafeMath,但可 unchecked 主动关闭 |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Overflow8 {
function test() public pure returns (uint256) {
uint256 max = type(uint256).max;
// 0.8.0+ 这一行会直接 revert(溢出检查)
// uint256 bad = max + 1;
// 如果你明确知道这里不会溢出、想省 gas,可以显式关闭检查:
uint256 x = 1;
unchecked { x = x + 1; } // ★ 主动关掉溢出检查
return x;
}
}
★ 加分点:0.8.0 的自动检查是有 gas 成本的。高频循环里如果确定不会溢出, 用
unchecked可以省 gas,但必须非常确定,这是“优化”和“埋雷”的一线之隔。
11.4.4 防御与审计要点
1. 老合约(<0.8.0):确认是否引入了 SafeMath,且所有 + - * 都用 .add/.sub/.mul
2. 新合约(>=0.8.0):默认安全,但要警惕那些【主动用 unchecked】的地方——逐个审查
3. 关注所有"由外部输入参与的四则运算",尤其是减法(下溢造币)和乘法(上溢归零)
4. 关注 for 循环计数器的自增,理论上 i++ 在极端情况下也可能上溢(循环次数不可能到 2^256,风险极低)
// SPDX-License-Identifier: MIT
pragma solidity ^0.4.24;
// SafeMath 时代的标准写法(0.4.x)
library SafeMath {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "underflow"); // ★ 显式检查,防下溢
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "overflow"); // ★ 防上溢
return c;
}
}
contract SafeToken {
using SafeMath for uint256;
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public returns (bool) {
balances[msg.sender] = balances[msg.sender].sub(amount); // 下溢会 revert
balances[to] = balances[to].add(amount); // 上溢会 revert
return true;
}
}
11.5 预言机与价格操纵(Oracle Manipulation)
11.5.1 预言机是什么,用大白话讲
一句话定义:预言机(Oracle)是把"链下真实世界的数据"喂给链上合约的桥梁。
生活类比:封闭房间里的"递纸条的人"。
区块链是个没窗户的房间,合约看不到外面的世界(不知道 ETH 现在多少钱、今天几号)。
预言机就是那个站在门口的人,每隔一会儿往房间里塞一张纸条:"现在 ETH = 3000 美元"。
合约的所有"按价格决策"(抵押、清算、兑换),都信这张纸条。
★ 致命问题:如果这张纸条可以被【操纵】(比如有人故意把价格报成 1 美元),
那么合约就会在错误的价格上做决策——这正是价格操纵攻击的本质。
11.5.2 为什么“现货价格”能被操纵(AMM 定价原理)
很多新手项目图省事,直接拿“去中心化交易所(DEX)里某个交易对的当前现货价格“当预言机。 问题是:DEX 的现货价格,是由池子里的两种资产比例决定的,而这个比例可以被一笔大额交易瞬间改变。
AMM(自动做市商)最经典的公式:x * y = k
x = 池子里 A 币的数量
y = 池子里 B 币的数量
k = 恒定乘积(不变)
价格 = y / x(用 B 计价 A)。如果你往池子里【砸进巨量 B 币】,y 暴涨,
那么 A 的价格(y/x)瞬间暴涨——哪怕这只是你一手造成的短暂假象。
白话:一个小池塘,你往里倒一卡车水,水位当然瞬间暴涨。 但这个“水位”是被你一个人临时抬高的,不是真实价值。 合约如果信了这个假水位去做“抵押/清算”,就被你钻了空子。
11.5.3 价格操纵攻击完整演示
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDex {
function getPrice() external view returns (uint256); // 池子的现货价格
function swap(address tokenIn, uint256 amountIn) external;
}
// ★ 受害者:用"现货价格"判断抵押是否安全的借贷协议
contract VulnerableLending {
IDex public dex;
mapping(address => uint256) public collateral; // 用户抵押的 ETH
constructor(address _dex) { dex = IDex(_dex); }
function deposit() public payable {
collateral[msg.sender] += msg.value;
}
// 借款额度 = 抵押物价值 × 0.8(抵押率 80%)
function borrow(uint256 amount) public {
uint256 ethPrice = dex.getPrice(); // ★ 用现货价格
uint256 borrowPower = collateral[msg.sender] * ethPrice * 8 / 10;
require(amount <= borrowPower, "insufficient collateral");
payable(msg.sender).transfer(amount);
}
}
攻击者如何打(伪代码 + 讲解):
攻击者目标:用很少的抵押,借走协议里大量的钱。
步骤:
1. 攻击者先往 DEX 池子里【砸巨量钱】,把 ETH 现货价格抬高 100 倍
(这是"自己抬起来的假价格")
2. 趁价格还高,攻击者调 borrow(),协议一看"你抵押的 ETH 现在值 100 倍",
就允许他借走远超真实价值的钱
3. 攻击者再反向交易,把价格砸回正常,套利离场
4. 协议留下了"借出的钱 > 抵押真实价值"的坏账,无法清算,直接亏空
11.5.4 三种防御手段
防御一:TWAP(时间加权平均价格)
思路:不取"某一瞬间"的价格,而是取"过去一段时间"的加权平均。
这样攻击者要用一笔巨款把价格持续顶住好几分钟,成本极高,往往得不偿失。
白话:不看"这一秒的水位",看"过去 30 分钟的平均水位"。
你倒一车水能顶起一瞬间,但顶不起 30 分钟的平均值。
防御二:去中心化预言机网络(如 Chainlink)
思路:不用单一来源,而是多个独立节点(多个递纸条的人)各自从多个交易所聚合报价,
取中位数/加权,并且有经济惩罚机制防止节点作恶。
★ 面试要点:Chainlink 不是"一个数据源",而是"预言机网络 + 聚合器 + 喂价合约"。
它通过多节点、多数据源、离线聚合来抵抗单一来源操纵。
防御三:多种价格源交叉验证 + 异常熔断
思路:同时读多个价格(DEX 现货 + 预言机 + 中心化交易所),
如果彼此偏差超过阈值(比如 5%),就暂停敏感操作(清算、借款),触发熔断。
★ 诚实提醒:没有一种方案是 100% 安全的。TWAP 能防“瞬时代价”,但挡不住“长期持续操纵”; Chainlink 能防单一节点作恶,但极端行情下的更新延迟仍可能被利用。 安全审计的要点是【识别“价格来源是否可被单笔交易影响”】,而不是迷信某个方案。
11.6 闪电贷攻击(Flash Loan Attack)
11.6.1 闪电贷是什么,用大白话讲
一句话定义:闪电贷是【在同一笔交易内】借出巨款、用完、立刻归还的零抵押贷款。
生活类比:银行允许你在"同一秒钟内"借 1 个亿,但要求这一秒结束时必须连本带息还清。
只要你能在这一秒内"用这 1 个亿赚到钱并还上",这 1 个亿就随你支配。
因为"借"和"还"发生在同一笔交易里,区块链的原子性保证了:
如果你还不上,整笔交易回滚,等于从没发生过——所以放贷方【几乎零风险】。
关键点:
- 零抵押:不需要你有任何本金(只需付一点手续费)
- 原子性:借、用、还三件事在同一笔交易里,要么全成,要么全回滚
- 它本身不是攻击:闪电贷是个中立工具(套利者用它做无风险套利), 但攻击者用它凭空获得巨量资金,去放大其它漏洞(价格操纵、重入等)
11.6.2 闪电贷攻击的典型套路
闪电贷几乎从不单独“攻击”,它是放大器,把一个小漏洞放大成天文数字的损失。 典型组合套路:
闪电贷 → 借巨款 → 砸进池子操纵价格 → 利用"价格操纵"漏洞套利 → 还贷 → 离场
或者:
闪电贷 → 借巨款 → 用巨款触发某个"按余额分配奖励/分红"的漏洞 → 抽走奖励 → 还贷
白话:闪电贷给了攻击者一把“无限子弹的枪”,但枪本身不伤人,伤人的是你的合约里那个 “会被大额资金影响决策”的漏洞。所以防闪电贷,本质是修好自己的价格/余额逻辑,而不是“禁掉闪电贷”(也禁不掉)。
11.6.3 一个简化的闪电贷攻击演示
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ★ 受害协议:按"合约余额"分配奖励的质押协议(有漏洞)
contract RewardsPool {
mapping(address => uint256) public staked;
uint256 public totalStaked;
function stake() public payable {
staked[msg.sender] += msg.value;
totalStaked += msg.value;
}
// ★ 漏洞:奖励 = 合约余额 - totalStaked(即"多出来的钱全当奖励发")
// 攻击者可以在同一笔交易里"临时存入巨款",把合约余额瞬间撑大,
// 领走绝大部分"奖励",再把巨款撤走。
function claimReward() public {
uint256 reward = address(this).balance - totalStaked;
require(reward > 0, "no reward");
(bool ok, ) = msg.sender.call{value: reward}("");
require(ok, "fail");
}
}
攻击逻辑(讲解,无需完整合约代码):
1. 攻击者通过闪电贷借到 10000 ETH
2. 把这 10000 ETH 全部 stake 进 RewardsPool
→ 现在合约余额 = 10000 ETH + 原本的奖励池,totalStaked 也 = 10000 ETH + 原质押
→ 但"奖励"的算法是 address(this).balance - totalStaked,
如果协议本身有"历史积累的未分配奖励",这个差值仍然存在
3. 攻击者 claimReward(),把"多出来的奖励"领走
4. 攻击者 unstake 撤走自己的 10000 ETH(如果协议允许),还掉闪电贷
5. 净赚:那些"历史未分配奖励"被攻击者用闪电贷的巨款一次性洗走
★ 这个例子的核心教训:任何“用当前余额做分母/做分配依据”的逻辑,都要假设余额可以被 一笔闪电贷临时撑大或抽干。正确的做法是“奖励按时间累积(如 block.timestamp 记账)”, 而不是“看瞬时余额差”。
11.6.4 防御闪电贷攻击的原则
1. 【别用瞬时余额做决策】—— 用时间累积的记账,而不是 address(this).balance 的瞬时值
2. 【价格用 TWAP / 预言机】—— 别用可被单笔交易操纵的现货价
3. 【奖励按区块/时间线性累积】—— 让"临时撑大余额"无法撬动分配比例
4. 【关键操作加冷却期】—— 存/取之间加时间锁,让闪电贷"一锤子"无从下手
5. 【重入防护】—— 闪电贷攻击常配合重入,先堵住重入这道门
★ 面试升华点:闪电贷攻击说明了一个更深层的安全理念——在可组合、资金可瞬时流动的链上世界里, “局部正确”不等于“全局安全”。你的合约单独看没问题,但和别人一组合、被一笔闪电贷一放大, 就崩了。这也是为什么合约审计越来越强调“协议级/经济级”审计,而不只是“代码级”审计。
11.7 MEV 与前置交易(Front-running / Sandwich)
11.7.1 MEV 是什么,用大白话讲
一句话定义:MEV(Miner/Maximal Extractable Value,矿工可提取价值)=
交易排序者(矿工/验证者/机器人)通过【调整交易顺序、插入自己的交易】来额外赚取的那部分价值。
生活类比:排队买限量球鞋。
你排在一个黄牛后面。你刚要下单,黄牛看到你的订单,抢先一步把你想要的鞋全买空,
然后再高价卖回给你。黄牛赚的就是"排序优势"的钱。
在链上,"黄牛"能看到 mempool 里你【尚未被打包】的交易,于是抢在你前面下单。
关键机制:链上交易不是“提交就立刻执行”,而是先进一个公开的待处理池(mempool), 再由打包者挑选、排序。这个“公开排队 + 有人能排序”的结构,天然产生了 MEV。
11.7.2 三明治攻击(Sandwich Attack)
这是最典型、最好讲的 MEV 攻击,面试高频:
你的交易:在 DEX 上买 100 个 A 币(会推高 A 币价格)
攻击者:
1. 在 mempool 里看到你的买单
2. 【抢在你前面】也买 A 币 → 价格被抬高
3. 你的买单执行 → 因为价格已更高,你买到更少的 A 币(你被"夹"了)
4. 【在你后面】攻击者把 A 币卖出 → 因为价格被你和他一起推高,他卖在高点
5. 净赚:你多付的钱 + 他低买高卖的差价
┌───────────┐
│ 攻击者买入 │ ← 第一片"面包":抬高价格
├───────────┤
│ 你的交易 │ ← 中间的"肉":你高价成交,承受滑点
├───────────┤
│ 攻击者卖出 │ ← 第二片"面包":高位套现离场
└───────────┘
11.7.3 MEV 的几种常见形态
| 类型 | 白话解释 |
|---|---|
| 前置交易 Front-running | 看到你的交易,抢在你前面执行相同/相关交易,赚差价 |
| 后置交易 Back-running | 跟在你后面,利用你造成的价格变化反向操作 |
| 三明治 Sandwich | 前 + 后一起夹你(上面讲的) |
| 清算套利 Liquidation | 抢着帮“该被清算”的仓位清算,赚清算奖励 |
| 套利 Arbitrage | 两个池子价格不一致,低买高卖(这个本身是良性的) |
★ 面试加分点:要区分“MEV 本身”和“MEV 攻击”。套利、清算这类 MEV 是市场的正常润滑剂, 甚至是好事(让价格回归);真正伤用户的是三明治、前置交易这类“以普通用户为代价”的提取。
11.7.4 防御手段(含用户侧和协议侧)
用户侧(作为普通用户能做的):
1. 设【滑点容忍度】(slippage tolerance)—— 价格偏离超过 N% 就取消交易,
让三明治攻击者无法把价格抬太高(抬太高你的单子会失败)
2. 用【私有交易/Flashbots】—— 不把交易公开进 mempool,直接发给打包者,黄牛看不到
协议侧(作为开发者能做的):
3. 关键操作加【提交-揭示(commit-reveal)】或【时间锁】—— 让攻击者无法即时抢先
4. 用 TWAP 而非瞬时价 —— 提高操纵成本
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 滑点保护的示意:设一个"最多能接受的价格"上限
contract SlippageGuard {
uint256 public constant MAX_SLIPPAGE = 100; // 1% = 100 个基点
function swapWithGuard(uint256 amountIn, uint256 expectedOut, uint256 minOut) public {
// 调用者自己声明"最少要拿到多少",协议据此兜底
uint256 minAcceptable = expectedOut * (10000 - MAX_SLIPPAGE) / 10000;
require(minOut >= minAcceptable, "too much slippage");
// ... 执行兑换,若实际得到 < minOut 则回滚
}
}
白话:滑点保护就是“挂单时先设个止损价”——“如果价格被抬得太过分,这单我不做了”。 这样黄牛抬价抬过头,你的单子直接作废,他就白抬了。
11.8 代币安全(Token Security)
11.8.1 ERC20 的 approve / transferFrom 两段式,藏着什么坑
ERC20 标准的授权是“两段式”:先 approve(授权某地址花你的币),再 transferFrom(它替你花)。
这个设计带来一个经典问题——无限授权(unlimited approval)。
白话:你为了让 DEX 能自动帮你卖币,得先"签字授权"它动用你的币。
很多钱包/前端为了省事,直接授权一个"无限额度"(2^256 - 1,天文数字)。
这意味着:只要这个被授权的合约【将来出任何漏洞、被黑、或被替换成恶意合约】,
攻击者就能把你钱包里【所有】这种币转走——而不需要你的私钥。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
contract ApproveHelper {
// ★ 危险做法:无限授权
function riskyApprove(IERC20 token, address spender) external {
token.approve(spender, type(uint256).max);
}
// 安全做法:只授权本次需要的额度
function safeApprove(IERC20 token, address spender, uint256 amount) external {
token.approve(spender, amount);
}
// ★ 收尾:用完后把授权归零(尤其发现某合约有风险时,第一时间 revoke)
function revoke(IERC20 token, address spender) external {
token.approve(spender, 0);
}
}
★ 面试加分点:
approve的“先归零再设新值”顺序问题——直接approve(new)在部分实现下可能因 旧额度未清零而被“覆盖失败”或产生竞争窗口,安全做法是先approve(0)再approve(new)。- 用户应对:定期用 revoke 工具(如 revoke.cash)检查并撤销不必要的授权。
11.8.2 貔貅盘 / 蜜罐 / 假代币(用户侧最常见的坑)
这些属于“用户被骗”的坑,但面试里“怎么识别一个恶意代币”也是常见话题:
1. 貔貅盘(Honeypot):只能买、不能卖。
—— 合约里"卖"这个函数对普通用户是禁用/必定失败的,只有项目方自己能卖。
识别:看代码里 transfer 是否对"卖方向"做了白名单限制。
2. 蜜罐(Honeypot 变体):看起来有漏洞(比如"能抽走池子的钱"),诱骗你打钱去"捡漏",
结果你的钱进去就取不出来。
3. 假代币(Fake token):伪造知名代币的合约地址和符号,骗你在 DEX 里买到空气。
4. 无限增发(Unlimited mint):合约里 mint 函数没限权限,项目方能无限印币砸盘。
★ 审计口诀:看到一个代币,先问四个问题—— ① mint 有没有限权限? ② transfer/卖有没有隐藏限制? ③ 有没有黑名单/白名单能冻结你的币? ④ 税/手续费(fee-on-transfer)会不会吞掉你的转账金额?
11.8.3 转账扣税代币(Fee-on-Transfer)的兼容性坑
白话:有些代币每转一笔账,会扣一定比例当"手续费"(比如 2% 销毁或归项目方)。
这本身是产品设计,但对【不知道这一点】的协议是灾难:
坑:协议按"amount"记账,但实际到账的是 amount * 98%。
如果协议拿 amount 去算抵押/兑换,就会"账实不符",轻则用户吃亏,重则被套利。
防御:协议接新代币前,先测"实际到账余额差",不支持扣税代币就拒绝,
或一律用"转账前后的余额差值"来确认真实到账数量,而不是信传入的 amount。
11.8.4 小数精度(Decimals)与舍入攻击
白话:代币有"精度"(decimals),比如 USDT 是 6 位小数、大多数是 18 位。
合约里做除法、按比例分配时,如果先除后乘、或向下取整(floor),
会产生"舍入误差"。攻击者可以通过精确构造金额,让每次舍入都"偏向自己",积少成多。
口诀:
1. 【先乘后除】,尽量最后才做除法,减少中间精度损失
2. 警惕"向下取整"累积——分配时要把"余数"处理掉(如归入协议或让利给最小单位)
3. 金额计算用"最小单位"(整数),别用浮点(Solidity 根本没有浮点)
诚实提醒:代币安全是一个“深坑”,上面只是最常见四类。真实审计里还有 rebase 代币(余额会变)、重入式 ERC777 钩子、transfer 返回 false 却不 revert 等一堆兼容性问题。
11.9 钱包与私钥安全(用户侧攻防)
11.9.1 私钥与助记词:一条铁律 + 三个禁区
一句话定义(复习):私钥 = 资产的唯一钥匙;助记词 = 私钥的"人类可读备份"。
谁拿到它们,谁就能【无需任何其他验证】地把资产全部转走,且无法追回。
铁律:not your keys, not your coins —— 私钥不在你手里,币就不是你的。
(把币存在中心化交易所 = 把你的钥匙交给交易所保管,交易所被黑/跑路,你的币就没了)
三个禁区:
1. 【绝不】把私钥/助记词截图、存网盘、发微信/邮件、抄在能被拍照的地方
2. 【绝不】在任何网页、任何"客服"引导下输入助记词(正规钱包从不需要你"在线输入"助记词)
3. 【绝不】把助记词导入一个"来路不明"的钱包 App(假钱包 App 会直接偷走你的助记词)
11.9.2 四类最常见的钓鱼手法
手法一:假网站 / 假钱包 App(Phishing)
原理:做一个和官方几乎一模一样的网站/App,诱导你输入私钥/助记词,或者诱导你"授权"。
识别:核对域名(如 uniswap.org vs uniswap-com.cn)、核对 App 来源、绝不点陌生链接里的"连接钱包"。
手法二:签名诈骗(Signature Phishing)
原理:骗你在钱包里"签一笔交易"(sign a message),你以为只是"登录/验证",
实际上签的是"授权转走你所有币"或"把某币的授权给了攻击者"。
白话:对方递给你一份"文件",跟你说"签个字就行",你以为是签到表,其实是"财产转让同意书"。
★ 关键认知:很多钓鱼不需要你的私钥,只需要你【点一下"签名"】。
因为"签名"= 你本人同意执行某个操作,攻击者把这个"同意"用在恶意交易上。
手法三:授权钓鱼(Approval Phishing)
原理:诱导你对一个恶意合约 approve(授权),授权之后攻击者就能 transferFrom 你的币。
识别:授权前看【授权对象地址】和【授权额度】,不明合约 + 无限额度 = 危险。
补救:立刻用 revoke 工具撤销授权。
手法四:假空投 / 假客服
原理:以"你中了空投""你的钱包有异常""帮你解冻"为由,诱导你"验证身份"= 交出助记词或签名。
铁律:真客服、真空投【永远】不会要你的助记词/私钥,也不会让你"先打钱"。
11.9.3 多签钱包(Multisig):把“一把钥匙”变成“N 把钥匙”
一句话定义:多签钱包要求一笔交易必须由【多个私钥中的 M 个】共同签名才能执行(M-of-N)。
生活类比:银行保险库需要【两把钥匙同时转】才能打开,行长一把、会计一把,缺一不可。
这样即使一把钥匙被偷,攻击者也打不开。
安全价值:
1. 单把私钥泄露 ≠ 资产丢失(还差其他人的签名)
2. 防止"单人作恶"(内部人员监守自盗要串通多人)
3. 适合项目方金库、DAO 资金池这类"大额 + 多人共管"的场景
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 极简多签钱包示意(M-of-N)
contract SimpleMultiSig {
address[] public owners;
uint256 public required; // 至少需要 required 个签名
mapping(address => bool) public isOwner;
mapping(bytes32 => uint256) public signed; // 每笔交易已有多少签名
mapping(bytes32 => mapping(address => bool)) public hasSigned;
constructor(address[] memory _owners, uint256 _required) {
owners = _owners;
required = _required;
for (uint256 i = 0; i < _owners.length; i++) {
isOwner[_owners[i]] = true;
}
}
function sign(bytes32 txHash) external {
require(isOwner[msg.sender], "not owner");
require(!hasSigned[txHash][msg.sender], "already signed");
hasSigned[txHash][msg.sender] = true;
signed[txHash]++;
}
// 收集够签名后,任意 owner 可执行这笔交易
function execute(bytes32 txHash, bytes calldata data) external {
require(signed[txHash] >= required, "not enough signatures");
(bool ok, ) = msg.sender.call(data);
require(ok, "exec failed");
}
}
白话:把“一把钥匙”拆成“N 把”,要凑够 M 把才能开门。 这是项目方资金安全的标配,也是面试里“如何保护大额资产”的标准答案之一。
11.9.4 私钥存储的最佳实践(从低到高)
第 0 级(危险):助记词明文存电脑/手机备忘录、截图、网盘、微信收藏 —— 随时可能被盗
第 1 级(基础):手抄在纸上,物理保存,多份异地备份 —— 但怕火灾、盗窃、被拍照
第 2 级(推荐):硬件钱包(如 Ledger/Trezor)—— 私钥【永不联网】,签名在硬件内完成
第 3 级(进阶):硬件钱包 + 多签 + 分片备份(把助记词拆成多份,异地存放,凑够才能还原)
★ 面试加分点:
- 硬件钱包的核心是“私钥离线 + 签名不出设备”,即使电脑中了毒也偷不到私钥
- 但硬件钱包也有风险:供应链被篡改、用户自己把助记词输进钓鱼网站、实物被盗
- 没有“绝对安全”,只有“把攻击成本拉高到不值得”
11.9.5 一条贯穿全节的审计心法
钱包安全的本质不是“技术多高深”,而是**“人”是最大的漏洞**。 再硬的硬件钱包,也挡不住用户自己把助记词截图发群里。 所以钱包安全的第一课永远是【安全教育】,其次才是技术手段(硬件钱包、多签、授权管理)。
11.10 面试题 K 组:Web3 与智能合约安全(30 题)
11.10.1 基础题(K1 ~ K12)
K1. 什么是智能合约?它和传统程序最本质的区别是什么?
★ 定义:部署在区块链上、自动执行、几乎无法修改的一段代码,直接管理链上资产。
生活类比:自动售货机——投钱自动出饮料,中间不需要人;但一旦摆上街就改不了,有 bug 也只能让它继续跑。
三个本质区别(必答):
- 不可篡改:部署后无法热修复,漏洞没法打补丁
- 直接管钱:出 bug 的后果是直接、不可逆的资金损失
- 代码公开:字节码全网可见,攻击者可以先读你的代码再打你
★ 加分点:补一句“代码即法律(Code is Law)”,并提 The DAO 事件对这条原则的冲击(分叉追回 vs 代码即法律)。
K2. 什么是重入攻击?请说它的根因和防御。
★ 定义:合约在“扣账之前”就调用外部合约转账,外部合约回调(重入)你的函数,趁状态未更新反复取钱。
生活类比:银行柜员“先给钱、后记账”,你接到钱发现账还没划掉,立刻再取,直到柜台被掏空。
根因:状态更新(Effects)晚于外部调用(Interactions)。
防御三条(都要说):
- CEI(检查-生效-交互):先改状态,最后才外部调用
- ReentrancyGuard:互斥锁禁止重入
- Pull Payment:改成“用户自己来提”,减少主动转账
★ 加分点:能说出四种变体(单函数/跨函数/跨合约/只读重入),并提 The DAO 损失 6000 万美元。
K3. 什么是整数溢出/下溢?Solidity 0.8.0 有什么变化?
★ 定义:数值超过类型上限绕回最小值(上溢),或低于 0 绕回最大值(下溢)。
生活类比:老式里程表,6 位显示,999999 再 +1 变 000000;0 再 -1 变 999999。
经典危害:下溢造币——余额 5 却转 10,5 - 10 下溢成天文数字,凭空多出代币。
版本分水岭:
- < 0.8.0:静默溢出,必须手动 SafeMath
-
= 0.8.0:默认自动检查,溢出直接 revert,可用
unchecked主动关闭
★ 加分点:unchecked 能省 gas 但必须非常确定,是“优化”和“埋雷”的一线之隔。
K4. transfer / send / call 三种转账方式的区别?
| 方式 | 失败行为 | Gas | 现代推荐 |
|---|---|---|---|
| transfer | 自动回滚 | 固定 2300 | 不推荐(2300 太少,易被拒) |
| send | 返回 false | 固定 2300 | 不推荐 |
| call | 返回 false,需手动检查 | 可指定 | ★ 推荐(+ 手动检查返回值) |
★ 加分点:transfer/send 的 2300 gas 上限是历史遗留(为了防重入), 但它导致“只要收款合约有稍复杂逻辑就转账失败”,所以现代改用 call + CEI + ReentrancyGuard。
K5. 什么是预言机?为什么“直接用现货价格”很危险?
★ 定义:预言机是把链下真实数据(价格等)喂给链上合约的桥梁。
生活类比:封闭房间里的“递纸条的人”,合约信纸条上的价格做决策。
危险:DEX 现货价格由池子资产比例决定,一笔大额交易就能瞬间改变它, 合约若用这个“可被单笔交易操纵”的价格做抵押/清算,就会被攻击者抬价套利。
防御:TWAP(时间加权平均价)、去中心化预言机网络(Chainlink)、多源交叉验证 + 熔断。
K6. 什么是闪电贷?它本身是攻击吗?
★ 定义:同一笔交易内“借巨款 → 用完 → 立刻还”的零抵押贷款。
生活类比:银行允许你同一秒内借 1 亿、赚到钱立刻还,还不上就整笔回滚。
关键:闪电贷本身是中立工具(套利者用它做无风险套利),但它给了攻击者“无限子弹”, 用来放大其它漏洞(价格操纵、余额分配漏洞等)。
★ 加分点:防闪电贷的本质是修好自己的价格/余额逻辑,而不是“禁掉闪电贷”(也禁不掉)。
K7. 什么是 MEV?什么是三明治攻击?
★ 定义:MEV = 交易排序者通过调整交易顺序、插入自己交易来额外提取的价值。
生活类比:排队买限量鞋,黄牛看到你的订单,抢在你前面买空再高价卖回给你。
三明治攻击:看到你的买单 → 抢在你前面买(抬价)→ 你高价成交 → 攻击者在你后面卖(套现), 你被“两片面包”夹在中间,多付了滑点。
★ 加分点:区分“良性 MEV”(套利、清算,让价格回归)和“恶性 MEV”(三明治、前置,坑普通用户)。
K8. ERC20 的 approve 有什么风险?
★ 定义:ERC20 授权是“两段式”(approve 授权 + transferFrom 花费), 很多场景授权了“无限额度”,一旦被授权合约出问题,攻击者能转走你所有币。
风险:无限授权 + 被授权合约有漏洞/被黑/被替换 = 资产被洗,无需私钥。
应对:只授权本次所需额度;用完 revoke 归零;定期用 revoke 工具撤销不必要授权。
★ 加分点:approve 的“先归零再设新值”顺序问题,避免旧额度未清零导致的覆盖失败/竞争窗口。
K9. 什么是多签钱包?它解决什么问题?
★ 定义:一笔交易需 N 个私钥中的 M 个共同签名才能执行(M-of-N)。
生活类比:银行保险库要两把钥匙同时转才能开。
价值:单钥泄露≠资产丢失;防单人作恶;适合项目方金库、DAO 资金池。
★ 加分点:多签是“如何保护大额资产”的标准答案之一,配合硬件钱包 + 分片备份更稳。
K10. 为什么不能把私钥/助记词截图存手机?
★ 定义:私钥/助记词是资产的唯一钥匙,拿到即可转走全部资产且无法追回。
铁律:not your keys, not your coins。
风险:截图/网盘/微信/备忘录都可能被云端泄露、被恶意 App 读取、被截图后盗用。
★ 加分点:正确答案是“手抄纸质 + 硬件钱包离线保存”,并强调“人”是钱包安全最大的漏洞。
K11. 访问控制缺失是什么?为什么它在合约里特别常见?
★ 定义:重要函数没加“只有管理员能调”的权限限制,任何地址都能调用。
为什么常见:合约函数默认对全网开放,和传统 Web“默认需要登录”的习惯相反, 新手容易漏掉“这个函数该不该限权限”这一步。
★ 加分点:审计第一动作 = 每个 function 过一遍,问“这是不是谁都能调?该不该 onlyOwner?”。
K12. tx.origin 和 msg.sender 的区别?为什么鉴权不能用 tx.origin?
★ 定义:tx.origin 是“最初发起交易的人”,msg.sender 是“当前这一层直接调用你的人”。
生活类比:tx.origin 是“最初按下按钮的人”,msg.sender 是“当前跟你说话的人”。
为什么不能用 tx.origin 鉴权:攻击者诱导 owner 调它的合约,在该合约里再调你的函数, 此时 tx.origin 仍是 owner(绕过鉴权),而 msg.sender 是攻击者合约。
★ 铁律:鉴权只用 msg.sender。
11.10.2 进阶题(K13 ~ K22)
K13. 请手写一个“先扣账再转账”的安全 withdraw,并说明为什么安全。
function withdraw() public {
uint256 amount = balances[msg.sender]; // Checks
require(amount > 0, "nothing"); // Checks
balances[msg.sender] = 0; // Effects ★ 先扣
(bool ok, ) = msg.sender.call{value: amount}(""); // Interactions 后转
require(ok, "fail");
}
为什么安全:即使对方在 call 里重入 withdraw,第二次进来时 balances 已经是 0,
require(amount > 0) 直接失败,重入被阻断。这就是 CEI 的完整体现。
K14. 只读重入(Read-only Reentrancy)和经典重入有什么不同?
★ 经典重入:通过“转账回调”重复调用,目的是重复取钱。 ★ 只读重入:即使加了 ReentrancyGuard 防住转账重入,攻击者仍能利用合约在“状态已更新但尚未结算”的 中间状态,从**只读函数(view)**读到不一致的数据,去误导另一个依赖该合约的协议。
区别:经典重入针对“资金”;只读重入针对“状态一致性/最终性(finality)”。
★ 加分点:防御是保证外部依赖读到的状态始终一致,或采用“先更新状态再暴露”的最终性设计。
K15. 如何审计一个“价格预言机”是否安全?
答(结构化四问):
- 价格从哪来?—— 单一 DEX 现货价(危险) vs 多源聚合(较安全)
- 能否被单笔交易影响?—— 现货价可以,TWAP/多源中位数难
- 有没有异常熔断?—— 价格偏离阈值时是否暂停清算/借款
- 更新延迟多大?—— 极端行情下旧价是否会造成套利窗口
★ 加分点:给出“TWAP + Chainlink + 熔断”的分层方案,并诚实说“没有 100% 安全”。
K16. 闪电贷攻击通常怎么和价格操纵组合?请描述完整攻击链。
完整链:闪电贷借巨款 → 砸进池子把价格抬/砸到目标值 → 触发目标协议的“价格决策”漏洞套利 → 反向交易恢复价格 → 还闪电贷 → 净赚离场。
关键:闪电贷提供“无限子弹”,价格操纵提供“错误决策”,两者叠加才致命。
★ 加分点:防御要落在“价格用 TWAP + 奖励按时间累积 + 关键操作加冷却期”。
K17. 什么是代理合约的存储冲突(Storage Collision)?
★ 定义:代理模式下,变量按“slot 位置”存储而非“名字”。升级后新逻辑合约若在相同 slot 放了不同类型/含义的变量,会覆盖或错读旧数据。
铁律:升级时变量声明顺序不能变,只能末尾追加。
★ 加分点:提 EIP-1967(实现地址放固定 slot)+ 透明代理(Transparent Proxy)。
K18. 什么是貔貅盘(Honeypot)?如何从代码识别?
★ 定义:只能买不能卖的恶意代币,“卖”对普通用户禁用/必失败,只有项目方能卖。
识别:看 transfer/卖相关函数是否对“卖方向”做了白名单限制、是否在卖出时强制 revert、 是否只有特定地址能成功卖出。
★ 加分点:审计一个代币先问四问——mint 权限?买卖限制?黑名单冻结?扣税?
K19. 如何防止三明治攻击?(用户侧和协议侧各说几点)
用户侧:设滑点容忍度(价格偏离过大就取消);用私有交易/Flashbots 绕开公开 mempool。 协议侧:关键操作提交-揭示/时间锁;用 TWAP 提高操纵成本。
★ 加分点:滑点保护的本质是“挂单先设止损价”,抬价过头单子就作废,黄牛白抬。
K20. 为什么“用 address(this).balance 做奖励分配”很危险?
★ 因为合约余额是“瞬时值”,可以被一笔闪电贷临时撑大或抽干。 用瞬时余额做分配依据,攻击者就能借巨款瞬间撑大余额、领走大部分奖励、再撤走。
防御:奖励按时间/区块累积记账,而非看瞬时余额差。
★ 加分点:可组合 + 资金可瞬时流动的世界里,“局部正确 ≠ 全局安全”。
K21. SafeMath 解决了什么问题?0.8.0 之后还需要吗?
SafeMath:在 <0.8.0 时代,把 + - * 包装成带溢出检查的 .add/.sub/.mul,溢出即 revert。
0.8.0 之后:编译器内置溢出检查,一般不再需要 SafeMath。
★ 加分点:但 unchecked 块会关闭检查,审计时反而要重点盯 unchecked 块。
K22. 如何保护一个项目的金库资金?(给一个分层方案)
分层方案:
- 多签钱包(M-of-N),大额需多人签名
- 硬件钱包离线保管私钥,冷热分离
- 关键操作加时间锁(Timelock),延迟执行留出“反悔/发现”窗口
- 定期 revoke 不必要授权 + 最小权限
- 应急预案:紧急暂停开关(但暂停开关本身要防滥用)
★ 加分点:时间锁(Timelock)是“防内部作恶 + 防被黑后瞬间卷款”的关键一环。
11.10.3 场景题(K23 ~ K27)
K23. 老板问你“我们项目要用区块链,安全吗?“你怎么回答?
答(三步法):
- 先澄清:区块链解决的是“信任/防篡改”,不解决“安全”。代码该有的漏洞一样有,而且更严重—— 因为不可篡改 + 直接管钱 + 代码公开。
- 给类比:上链 = 把带 bug 的钱包挂街上还贴了“里面有钱”。
- 给方案:安全要前置到写代码那一刻——合约审计、CEI、最小权限、预言机用 TWAP、金库多签。
★ 加分点:补一句“链上安全的第一责任人是写合约的人,不是链本身”。
K24. 你审计一个借贷协议,发现它用 DEX 现货价做清算价,怎么写报告?
答(报告要点):
- 风险定性:高危——现货价可被单笔交易操纵,导致错误清算/超额借款
- 攻击推演:攻击者闪电贷砸池子抬价 → 超额借款 → 砸回价格 → 坏账
- 修复建议:改用 TWAP / Chainlink 聚合价 + 多源交叉验证 + 异常熔断
- 附加:清算逻辑加冷却期,避免被闪电贷“一锤子”打穿
★ 加分点:给一个可量化的阈值建议(如“价格偏离 5% 暂停清算”)。
K25. 你的钱包收到一个陌生空投代币,还看到“xx 平台”让你“验证钱包领取奖励”,怎么办?
答:
- 不点、不签名、不授权——空投 + “验证钱包”是典型钓鱼话术
- 真空投不需要你输入助记词/私钥,也不需要你“先打钱”
- 若已授权过可疑合约,立刻 revoke
- 核对平台域名、App 来源,只信官方渠道
★ 加分点:强调“签名 = 同意执行某个操作”,很多钓鱼只需你点一下签名,不需要私钥。
K26. 项目被黑,攻击者还在陆续转钱,你作为安全负责人第一步做什么?
答(应急顺序):
- 先止血:能暂停的先暂停(紧急暂停开关/多签),冻结相关合约/撤销授权
- 保留证据:链上交易本就是公开的,立即拉取攻击交易哈希、时间线
- 通知:交易所/相关方冻结流入的赃款地址(部分中心化交易所能配合)
- 分析:定位漏洞(重入?价格操纵?私钥泄露?),确认影响面
- 复盘:修复 + 重新审计 + 公告
★ 加分点:诚实说明“链上转账不可逆”,所以第一优先级是“阻止进一步损失”而非“追回已转走的”。
K27. 面试官给你一段 withdraw 代码,让你找 bug,你的检查顺序是什么?
答(审计顺序):
- 看状态更新和外部调用的顺序(是否 CEI)
- 看转账方式(call 是否检查返回值,是否用 tx.origin 鉴权)
- 看有没有访问控制(谁都能调吗)
- 看算术(有没有 unchecked、有没有用瞬时余额/现货价)
- 看是否可被闪电贷/价格操纵影响
★ 加分点:能边看边把“每一处”对应到具体漏洞类别名(重入/溢出/ACL/tx.origin/预言机)。
11.10.4 追问链(K28 ~ K30)
K28. Web3 安全十连问
Q1: 智能合约为什么不能随便改? A: 部署到链上后代码(字节码)全网存储,无中心化“管理员”可改;要改只能预埋升级(代理),而升级本身又是攻击面。
Q2: 重入攻击的根因? A: 状态更新(扣账)晚于外部调用(转账),中间留出重入窗口。
Q3: CEI 三个字母分别是什么? A: Checks(检查)→ Effects(生效/改状态)→ Interactions(交互/外部调用)。
Q4: transfer 和 call 哪个现代更推荐?为什么? A: call(+手动检查返回值)。transfer 固定 2300 gas 太易被拒。
Q5: tx.origin 为什么不能做鉴权? A: 它代表“最初发起者”,攻击者可诱导 owner 调中间合约,绕过鉴权。
Q6: 0.8.0 之前的整数溢出怎么防? A: SafeMath(.add/.sub/.mul 带溢出检查)。
Q7: 预言机价格怎么防操纵? A: TWAP + 去中心化预言机网络(Chainlink)+ 多源交叉验证 + 熔断。
Q8: 闪电贷为什么能“零抵押”? A: 借和还发生在同一笔交易内,靠区块链原子性保证:还不上整笔回滚,放贷方零风险。
Q9: 三明治攻击夹的是谁? A: 普通用户的交易——攻击者前买后卖,让用户高价成交、承受滑点。
Q10: 钱包安全最大的漏洞是什么? A: 人——再硬的硬件钱包也挡不住用户自己把助记词截图发群里。
K29. 合约审计方法论十连问
Q1: 拿到一个合约,第一步做什么? A: 先读“它管什么钱、有哪些外部可调函数、状态变量有哪些”,建立全局模型。
Q2: 每个 function 必问的一句话? A: “这个函数是任何人都能调吗?该不该限权限(onlyOwner/onlyRole)?”
Q3: 看到 .call 转账,先看什么? A: 先看返回值是否检查,再看它在“扣账之前还是之后”。
Q4: 看到除法/比例分配,警惕什么? A: 精度丢失、先除后乘、向下取整累积,可能被舍入攻击。
Q5: 看到价格来源,问什么? A: 能不能被单笔交易影响?是现货价还是 TWAP/预言机?
Q6: 看到 address(this).balance 参与逻辑,警惕什么? A: 瞬时余额可被闪电贷撑大/抽干,做分配依据很危险。
Q7: 看到代理合约,警惕什么? A: 存储冲突(变量顺序不能变)+ 函数选择器遮蔽。
Q8: 看到 ERC20 交互,警惕什么? A: 扣税代币(到账≠传入 amount)、假币、无限授权。
Q9: 审计报告怎么分级? A: 按危害和可利用性分 Critical/High/Medium/Low,每条给“攻击推演 + 修复建议”。
Q10: 为什么说“局部正确 ≠ 全局安全”? A: 可组合 + 闪电贷放大,单个合约没问题,组合起来可能被套利/操纵打穿。
K30. 给非技术朋友讲“智能合约安全”八连问
Q1: 智能合约是什么? A: 跑在区块链上、自动执行、改不了的代码,就像街上的自动售货机。
Q2: 它和普通程序最大的不同? A: 改不了 + 直接管钱,出 bug 钱就没了,还追不回来。
Q3: 重入攻击是啥? A: 柜员先给钱后记账,你接到钱又立刻再取,直到柜台被掏空。
Q4: 整数溢出是啥? A: 里程表 999999 再走一格变 000000,余额算错账。
Q5: 闪电贷是啥? A: 同一秒内借 1 亿、赚完立刻还,还不上整笔作废——攻击者拿它当“无限子弹”。
Q6: 三明治攻击是啥? A: 黄牛看到你买单,抢你前面买、再高价卖回给你,你被夹中间。
Q7: 钱包被偷最多的原因? A: 不是被破解,是自己把助记词截图/发给假客服/点了假签名。
Q8: 普通人怎么自保? A: 助记词手抄离线存、用硬件钱包、不点陌生链接签名、定期 revoke 授权。
11.11 第十一章小结
这一章讲的是一个“代码直接管钱”的世界。它和前面十章的底层逻辑相通(最小权限、状态一致、审计), 但有两个颠覆性的新前提:不可篡改(出 bug 不能修)和资金可瞬时流动(闪电贷让“局部正确”失效)。 记住这两点,所有合约漏洞都能归结到“状态不一致”和“经济激励错位”两条主线上。
11.11.1 五条核心认知
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知一:代码即法律,但法律有 bug 时,代价是钱
智能合约 = 无法修改 + 直接管钱 + 代码公开。
传统程序有 bug 可以热修;合约有 bug 只能眼睁睁看钱被转走(除非硬分叉,如 The DAO)。
★ 推论:安全必须【前置】到写代码那一刻,审计是"上线前"而非"出事后"的事。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知二:重入攻击的根因是"状态更新晚于外部调用",一句话记住 CEI
先检查(Checks)→ 再改状态(Effects)→ 最后才外部调用(Interactions)。
这个顺序反了,就给了攻击者"趁你还没记账、再取一次"的窗口。
CEI 不只是合约的规矩,它适用于任何"先改数据还是先做副作用"的场景。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知三:价格是合约的"眼睛",眼睛可以被蒙上
合约看不到链下世界,只能信预言机。用"可被单笔交易操纵的现货价"当眼睛,
攻击者就能蒙住它、骗它做出错误的抵押/清算决策。
★ 防御:TWAP、去中心化预言机网络、多源交叉验证 + 熔断。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知四:闪电贷不是攻击,是放大器;"局部正确 ≠ 全局安全"
闪电贷本身是中立工具,但它给攻击者"无限子弹"。
你的合约单独看没问题,但在可组合、资金可瞬时流动的链上,
一个"用瞬时余额/现货价做决策"的小漏洞,会被一笔闪电贷放大成天文数字的损失。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知五:钱包安全最大的漏洞是"人",不是技术
再硬的硬件钱包,也挡不住用户自己把助记词截图发群里、点假签名、授权给恶意合约。
私钥/助记词一旦泄露 = 资产永久丢失,无法追回。
★ 所以钱包安全的第一课永远是安全教育,其次才是硬件钱包、多签、授权管理。
11.11.2 攻防速查卡:合约攻击手法 × 防御措施
| # | 攻击手法 | 一句话危害 | 一句话防御 | 详参 |
|---|---|---|---|---|
| 1 | 经典重入 | 反复取钱掏空合约 | CEI + ReentrancyGuard | 11.3 |
| 2 | 跨函数/跨合约重入 | 换函数继续重入 | 每个函数都 CEI | 11.3 |
| 3 | 只读重入 | 误导依赖方 | 保证状态一致性/finality | 11.3 |
| 4 | 整数上溢/下溢 | 凭空造币 | 0.8.0 自动检查 / SafeMath | 11.4 |
| 5 | 未检查返回值 | 转账失败当成功 | require 检查返回值 | 11.2 |
| 6 | tx.origin 鉴权 | 授权被盗用 | 只用 msg.sender | 11.2 |
| 7 | 访问控制缺失 | 谁都能抽钱 | onlyOwner/onlyRole | 11.2 |
| 8 | 代理存储冲突 | 升级覆盖数据 | 变量顺序不变 + EIP-1967 | 11.2 |
| 9 | 预言机/价格操纵 | 错误清算套利 | TWAP + Chainlink + 熔断 | 11.5 |
| 10 | 闪电贷攻击 | 一锤子卷走千万 | 不用瞬时余额/现货价 | 11.6 |
| 11 | 三明治/前置交易 | 用户被夹、多付滑点 | 滑点保护 + 私有交易 | 11.7 |
| 12 | 无限授权 | 被授权合约出事洗走你币 | 最小授权 + revoke | 11.8 |
| 13 | 貔貅盘/假币 | 只能买不能卖 | 审计买卖限制/mint 权限 | 11.8 |
| 14 | 扣税代币坑 | 到账≠传入金额 | 按余额差确认真实到账 | 11.8 |
| 15 | 助记词钓鱼/假签名 | 资产被洗、无法追回 | 安全教育 + 硬件钱包 | 11.9 |
11.11.3 智能合约安全成熟度自评表(L0 ~ L4)
| 级别 | 状态 | 典型表现 | 下一步 |
|---|---|---|---|
| L0 裸奔 | 无审计、凭感觉 | 上线前没人审合约;用现货价做清算 | 先做一次完整代码审计 |
| L1 起步 | 有基础规范 | 知道 CEI、用 0.8.x、用 Ownable | 引入自动化审计工具(Slither) |
| L2 制度 | 流程化 | 上线前必审、有 check-list | 价格用 TWAP/预言机 + 熔断 |
| L3 自动化 | 工具 + 监控 | Slither 进 CI、链上事件监控告警 | 上正式审计 + 漏洞赏金 |
| L4 自适应 | 纵深防御 | 多签 + 时间锁 + 监控 + 应急预案 | 定期红蓝对抗、跟踪新攻击手法 |
★ 工具提示:Slither(静态分析)、Mythril(符号执行)、Echidna(模糊测试)是合约审计三件套, 面试提到“你用过哪些审计工具”时,能说出这三个 + 各自定位,会很加分。
11.11.4 五份可直接使用的清单
清单一:合约代码审计 check-list(上线前必过)
□ 每个 function:是否限了权限(该 onlyOwner 的有没有加)?
□ 每个 .call 转账:返回值是否检查?在"扣账之前还是之后"?
□ 每个算术:有没有 unchecked?有没有用瞬时余额/现货价?
□ 每个价格来源:能否被单笔交易影响?
□ 每个外部调用:会不会重入?有没有 ReentrancyGuard?
□ 每个代理:变量顺序是否锁定?有没有存储冲突风险?
□ 每个 ERC20 交互:是否兼容扣税代币?授权是否最小化?
清单二:价格安全 check-list
□ 价格来源是现货价还是 TWAP/预言机?
□ 是否多源交叉验证?偏差阈值多少?
□ 是否有异常熔断(价格偏离 N% 暂停清算)?
□ 预言机更新延迟是否会造成套利窗口?
清单三:资金金库安全 check-list
□ 是否多签(M-of-N)?
□ 是否硬件钱包冷热分离?
□ 是否有时间锁(Timelock)延迟执行?
□ 是否有紧急暂停开关(且暂停开关本身受限权)?
□ 是否定期 revoke 不必要授权?
清单四:用户钱包自保 check-list
□ 助记词是否手抄离线保存(不截图、不存网盘/微信)?
□ 是否使用硬件钱包?
□ 是否定期 revoke 不必要授权?
□ 是否只信官方渠道、核对域名?
□ 是否养成了"陌生链接不签名、不授权"的习惯?
清单五:合约审计工具链
□ 静态分析:Slither(找重入、未检查返回值、访问控制等常见问题)
□ 符号执行:Mythril(找可达路径上的漏洞)
□ 模糊测试:Echidna(用随机/定向输入测不变量)
□ 人工审计:以上工具 + 人工推演经济攻击(工具查代码,人查"经济逻辑")
11.11.5 五句话记忆法
一句话记【代码即法律】:自动售货机摆上街就改不了,有 bug 也只能让它继续卖。
一句话记【重入攻击】:柜员先给钱后记账,你接到钱又立刻再取,直到柜台被掏空。
一句话记【整数溢出】:里程表 999999 再走一格变 000000,余额算错账。
一句话记【闪电贷】:同一秒借 1 亿、赚完立刻还——攻击者拿它当"无限子弹"。
一句话记【钱包安全】:私钥是唯一钥匙,最大的漏洞不是锁,是拿钥匙的人。
11.11.6 本章与前后章节的关系
┌─────────────────────────────────────┐
│ 第十二章 数据合规与隐私保护 │
│ (从"技术攻防"转向"合规红线") │
└─────────────────────────────────────┘
▲
前九章(经典/云原生攻击面) │ 新的价值载体:链上资产
┌──────────────────────────┐ ┌──────────────────────────────┐
│ 第一~五章:应用层 │→ │ 第十一章 Web3 与智能合约安全 │
│ 第六~七章:主机/内网 │ │ · 重入 / 溢出 / 访问控制 │
│ 第八~九章:DFIR/供应链 │ │ · 预言机 / 闪电贷 / MEV │
│ 第十章:云原生与Serverless│ │ · 钱包 / 私钥 / 多签 │
└──────────────────────────┘ └──────────────────────────────┘
│ │
└────────── 共用的地基 ───────────┘
(最小权限、状态一致、纵深防御、审计前置——这些基本功跨越所有技术栈)
一句话串起来:第十一章把“安全”从“防漏洞”上升到了“守资产”——当代码直接管钱、无法修改、资金可瞬时流动时, 安全不再是“上线后打补丁”,而是“写代码那一刻就该算清的经济博弈”。 下一章(第十二章)再换一个维度:不是“怎么被攻击”,而是“怎么不违法”——数据合规与隐私保护。
第十二章:数据合规与隐私保护(从“不被黑”到“不违法”)
本章定位:前面十一章都在讲“怎么不被攻击”,这一章换一个维度——怎么不违法、不踩红线。 对工程师来说,安全和合规是一体两面:安全是“防止数据被坏人拿走”,合规是“防止数据被你自己乱用”。 面试里,凡是涉及用户数据、跨境业务、金融/政务系统的岗位,“个保法”“等保”“数据出境”已经是必答题。
为什么普通工程师也要懂:
- 你写的每一个“收集用户手机号”的接口,背后都挂着一部《个人信息保护法》
- 数据出境、隐私政策、敏感个人信息,不再是法务一个人的事,而是架构设计的一部分
- “等保测评”“密评”是很多系统上线的硬性门槛,不懂连验收都过不了
本章口径说明:以下内容严格依据中国现行法律法规(《网络安全法》《数据安全法》《个人信息保护法》等) 及配套标准(等保 2.0、商用密码应用安全性评估等)的公开要求,做技术层面的客观介绍, 旨在帮助工程师理解“什么能做、什么不能做、该怎么做”,不构成法律意见。
12.1 数据合规全景与名词先行课
12.1.1 名词先行课:把合规术语讲成大白话
合规领域的术语又多又绕,先用生活类比把最核心的几个讲透,后面每一节都是它们的展开。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词一:个人信息 / PII(Personal Identifiable Information)
一句话定义:能【直接或间接】识别到"具体某个自然人"的信息。
生活类比:PII 就像一个人的"指纹"——单独一个"张三"可能不是(重名太多),
但"张三 + 手机号"或者"张三 + 家庭住址"就能精准锁定"就是你"。
分类(个保法的关键区分):
· 一般个人信息:姓名、电话、邮箱……(能识别,但敏感性一般)
· ★ 敏感个人信息:身份证号、银行账户、行踪轨迹、健康医疗、宗教信仰、
不满 14 周岁未成年人信息……(一旦泄露/滥用,危害更大,规则更严)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词二:《个人信息保护法》(PIPL,个保法)
一句话定义:中国专门管"个人信息怎么收集、怎么用、怎么保护"的一部法律(2021 年 11 月 1 日施行)。
生活类比:给"个人信息"立了规矩的"交通法规"——规定了谁能收集(要有合法理由)、
收集了能干嘛(目的明确)、不能干嘛(不能超范围用、不能随便卖)。
几个关键词(后面 12.2 展开):
· 告知-同意:收集前要明明白白告诉用户、征得同意
· 最小必要:只收"提供服务所必需"的信息,不能多收
· 单独同意:处理敏感个人信息、向第三方提供、跨境提供,要【单独】同意
· 删除权/更正权:用户有权要求你删、改他的信息
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词三:GDPR(欧盟《通用数据保护条例》)
一句话定义:欧盟的数据保护法规(2018 年生效),是"全球最严"的隐私法之一,
对全球任何"处理欧盟居民数据"的企业都有管辖权。
生活类比:欧盟给"欧洲人的数据"立的一部"域外效力的家规"——不管你的公司开在哪,
只要你处理欧洲用户的数据,就得守它的规矩。
几个关键点(后面 12.3 展开):
· 数据主体权利:访问权、更正权、删除权(被遗忘权)、可携带权、反对权
· 合法处理依据:同意、合同、法定义务、重大利益、公共利益、正当利益(六选一)
· 处罚:最高可罚【全球年营业额 4% 或 2000 万欧元】取较高者
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词四:等保 2.0(网络安全等级保护 2.0)
一句话定义:中国对"信息系统按重要程度分等级、按等级做安全保护"的强制性制度。
生活类比:给大楼按"重要程度"分消防等级——普通住宅和银行金库的消防要求当然不一样。
等保就是给信息系统分五级(一级最低、五级最高),等级越高,安全要求越严。
关键点(后面 12.7 展开):
· 定级 → 备案 → 建设整改 → 等级测评 → 监督检查,五个规定动作
· 绝大多数企业系统是二级或三级
· 三级以上要做"等保测评"(找有资质的测评机构),是很多系统上线的硬门槛
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词五:密评 / 国密(商用密码应用安全性评估 / 商用密码算法)
一句话定义:密评 = 对"系统里用的密码技术是否合规、是否达标"的评估;
国密 = 中国自主的商用密码算法(SM2 加密、SM3 哈希、SM4 分组加密、SM9 标识密码)。
生活类比:国密就是"国产锁芯标准"——要求关键系统用国产的锁(算法),
密评就是检查"你这把锁装得对不对、达不达标"。
关键点(后面 12.7 展开):
· 等保三级以上的系统、关键信息基础设施,通常要求"过密评"
· SM2(公钥加密/签名,对标 RSA/ECDSA)、SM3(哈希,对标 SHA-256)、
SM4(对称加密,对标 AES)是三个最常考的国密算法
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词六:数据出境(Cross-border Data Transfer)
一句话定义:把在中国境内产生/收集的数据,传输到境外(或让境外主体可访问)的行为。
生活类比:把"国内收集的客户资料"打包寄到国外分公司/用国外的云服务器存——这就叫"出境",
不是"人出国",而是"数据出国"。
关键点(后面 12.5 展开):
· 出境要过"安全评估"或"标准合同"或"认证"等合规路径
· 重要数据、达到一定量级的个人信息,出境前要申报安全评估
· 用境外云服务器存国内用户数据,本身就是一种"数据出境"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
名词七:DPIA(数据保护影响评估 / 个人信息保护影响评估)
一句话定义:在做一个"可能对个人权益有高风险"的数据处理活动【之前】,
先评估它的风险、想好怎么降低,形成一份评估报告。
生活类比:盖一栋可能影响居民采光的大楼之前,先做"环境影响评估"——
提前把"会不会挡光、怎么补救"想清楚,而不是盖完了再被投诉。
12.1.2 为什么工程师要懂合规(三个理由)
理由一:合规是【架构约束】,不是"事后补材料"。
数据要"最小必要"→ 影响你的接口设计(不能一次性收集一堆字段)
数据要"可删除"→ 影响你的存储设计(要能按用户 ID 彻底删干净)
数据要"可携带"→ 影响你的导出设计(要能导出结构化数据)
这些都必须【在写代码之前】就想清楚,等系统上线了再改,成本极高。
理由二:合规是【上线门槛】。
等保测评、密评、数据出境安全评估,都是"过不了就不能上线/不能接客户"的硬性要求。
不懂这些,你在政务、金融、医疗、跨境业务里寸步难行。
理由三:合规是【面试考点】。
"个保法和 GDPR 的区别""什么是敏感个人信息""数据出境怎么合规"
已经是后端/架构/安全岗位的常见题。
12.1.3 中国数据合规法规体系全景
中国当前的数据合规,核心是“三法一条例 + 配套办法/标准”,先建立全局观:
┌─────────────────────────────────────────────────────────────────┐
│ 《网络安全法》(2017) —— 网络运行安全 + 等级保护 + 关键信息基础设施 │
│ 《数据安全法》(2021) —— 数据分类分级 + 数据出境 + 数据安全制度 │
│ 《个人信息保护法》(2021)—— 个人信息处理规则 + 用户权利 + 跨境 │
│ 《数据出境安全评估办法》等配套 —— 数据出境的具体路径 │
├─────────────────────────────────────────────────────────────────┤
│ 配套标准:等保 2.0(GB/T 22239)· 密评 · 数据分类分级指南 │
└─────────────────────────────────────────────────────────────────┘
★ 记忆口诀(面试常用):“网安法管网络,数安法管数据,个保法管个人”。 三者层层递进:先保网络运行安全(网安法),再保数据本身安全(数安法), 最后落到最细的“个人信息”保护(个保法)。
12.1.4 合规 vs 安全:一体两面,但别搞混
| 维度 | 安全(Security) | 合规(Compliance) |
|---|---|---|
| 回答的问题 | 怎么不被攻击、不被偷 | 怎么不违法、不踩红线 |
| 保护对象 | 数据的机密性/完整性/可用性 | 数据主体的权利、法律的强制性要求 |
| 失败后果 | 被黑、数据泄露 | 行政处罚、罚款、下架、刑事责任 |
| 验证方式 | 渗透测试、漏洞扫描 | 等保测评、密评、监管检查 |
★ 关键认知:“合规”≠“安全”,但“合规”往往是“安全的最低标准”。 一个过了等保的系统照样可能被黑(等保是“底线要求”,不是“攻不破”); 但一个“技术上很安全”却违规收集数据的系统,照样会被罚。 优秀工程师两个都要懂,且要能分清“这件事是安全需求,还是合规需求”。
12.2 个人信息保护法(PIPL)技术落地
12.2.1 个保法的五条“铁规矩”
先把个保法最核心的规则提炼成工程师听得懂的五条:
规矩一:告知-同意(Consent)
收集前,要【明明白白】告诉用户:你是谁、收什么、用来干嘛、存多久、怎么联系你,
并取得用户【自愿、明确】的同意。
★ 技术含义:不能偷偷收集;隐私政策要"单独弹窗",不能藏在几十页里默认勾选。
规矩二:最小必要(Data Minimization)
只收集"提供服务所必需"的信息。
★ 技术含义:能收手机号就别收身份证;能收昵称就别收家庭住址。
接口字段、数据库字段都要"能少则少"。
规矩三:目的限制(Purpose Limitation)
收集来的信息,只能用于当初告诉用户的那个目的,不能"顺便"拿去干别的。
★ 技术含义:营销、画像、二次利用,要重新告知并取得同意。
规矩四:单独同意(Separate Consent)
处理敏感个人信息、向第三方提供、跨境提供,要【单独】同意,不能混在一揽子协议里。
★ 技术含义:这几个场景要有"独立的勾选框/独立弹窗",不能和主协议绑定。
规矩五:用户权利(Data Subject Rights)
用户有权【查询、更正、删除、撤回同意、注销账户】。
★ 技术含义:系统要能按用户 ID 找到他的所有数据、改、删、导出。
12.2.2 敏感个人信息(最容易踩的坑)
一句话定义:一旦泄露或非法使用,容易导致自然人的人格尊严受损或人身、财产安全受危害的个人信息。
个保法明确列举的敏感个人信息:
· 生物识别信息(人脸、指纹、声纹)
· 宗教信仰、特定身份、医疗健康、金融账户、行踪轨迹
· 不满十四周岁未成年人的个人信息
★ 处理敏感个人信息的特别要求:
1. 要有【特定目的 + 充分必要性】,且采取严格保护措施
2. 要取得【单独同意】(不能一揽子)
3. 要告知"处理的必要性 + 对个人的影响"
4. 处理不满 14 周岁未成年人信息,要取得【监护人同意】,且制定专门规则
白话:敏感个人信息就像“高危品”,普通物品走普通通道,高危品要单独申报、专人押运。 人脸、身份证、健康、金融这些,就是“高危品”。
12.2.3 个保法的技术落地(代码示例)
个保法的很多要求,最终都落到工程实现上。下面用代码演示三个最常见的落地点。
落地一:最小必要 + 字段分级(接口只返回必要字段)
# 用户信息表(示意):把字段按敏感性分级,接口按需返回
USER_FIELDS = {
"basic": ["user_id", "nickname"], # 基础:公开场合可展示
"contact": ["phone", "email"], # 联系:需授权才用
"sensitive": ["id_card", "bank_account", "face_id"], # 敏感:严格管控
}
def get_user_profile(user_id: str, need: str):
"""按'最小必要'原则,只返回调用方真正需要的字段层级"""
allowed = {
"basic": USER_FIELDS["basic"],
"contact": USER_FIELDS["basic"] + USER_FIELDS["contact"],
"sensitive": [], # 默认绝不下发敏感字段
}
fields = allowed.get(need, USER_FIELDS["basic"])
return query_user(user_id, fields) # 只查这些字段
落地二:同意记录留痕(“告知-同意”要有证据)
# 每次收集敏感信息前,记录用户的"单独同意"作为合规证据
def collect_sensitive_info(user_id: str, field: str, purpose: str):
if field not in USER_FIELDS["sensitive"]:
raise PermissionError("敏感字段需单独同意")
# 1. 记录同意时间、版本、目的
record_consent(user_id=user_id,
field=field,
purpose=purpose, # 明确告知的目的
policy_version="v2.3", # 当时的隐私政策版本
consented_at=now())
# 2. 才去采集
return collect(user_id, field)
落地三:删除权 / 撤回同意(要能“彻底删干净”)
# 用户行使删除权:不仅删主表,还要删所有关联副本、缓存、备份引用
def delete_user_data(user_id: str):
# 1. 主表删除
db.delete("users", where={"user_id": user_id})
# 2. 关联表删除(订单、日志、画像、行为记录)
for table in ["orders", "behavior_log", "user_profile", "consents"]:
db.delete(table, where={"user_id": user_id})
# 3. 缓存删除
cache.delete(f"user:{user_id}")
# 4. 标记"待物理删除",让备份/归档在保留期后同步清除
db.insert("deletion_tasks", {"user_id": user_id, "status": "pending_purge"})
★ 面试加分点:删除权落地最大的坑是“只删了主表,没删副本”——日志、备份、数仓、缓存里还躺着数据, 严格来说不算“删除”。要设计“删除任务队列 + 备份保留期 + 定期物理清除”的闭环。
12.2.4 个保法的处罚力度
· 一般违法:责令改正、警告、没收违法所得;拒不改正的,可处 100 万元以下罚款
· 严重违法:可处【5000 万元以下】或【上一年度营业额 5% 以下】罚款,并可责令暂停业务、吊销执照
· 直接责任人:可处 10 万~100 万元罚款,并可能"禁业"
· 造成严重后果的,还可能涉及刑事责任(《刑法》侵犯公民个人信息罪)
★ 记忆点:个保法罚款是“5000 万 或 营业额 5% 取高”,和 GDPR 的“2000 万欧 或 4% 取高”是同一个量级思路, 都是“罚到肉疼”的顶格设计。
12.3 GDPR(欧盟通用数据保护条例)
12.3.1 GDPR 的三个“全球性”特点
特点一:域外效力(Extraterritorial)
不管你的公司注册在哪国,只要你在【欧盟境内设立机构】,或【向欧盟居民提供商品/服务】、
或【监控欧盟居民的行为】,GDPR 就管得到你。
★ 白话:一个中国公司做面向欧洲用户的 App,也得守 GDPR。
特点二:合法处理依据(六选一)
处理个人数据,必须至少满足下面一条,否则就是违法:
① 数据主体同意 ② 履行合同所必需 ③ 法定义务 ④ 保护重大利益
⑤ 公共利益/公权力 ⑥ 控制者的正当利益(需利益平衡)
★ 对比:个保法更强调"同意"为主,GDPR 把"合同必需""正当利益"也作为独立依据。
特点三:天价罚款
最高可处【2000 万欧元】或【全球年营业额 4%】,取较高者。
12.3.2 GDPR 的用户权利(比个保法更细)
| 权利 | 白话解释 | 技术落地 |
|---|---|---|
| 访问权 | 用户有权知道你存了他什么 | 提供“下载我的数据” |
| 更正权 | 改错 | 提供资料编辑 |
| 删除权(被遗忘权) | 彻底删 | 删除任务闭环 |
| 限制处理权 | 暂停用我的数据 | 冻结处理标记 |
| 可携带权 | 把我的数据带走 | 导出结构化格式(JSON/CSV) |
| 反对权 | 反对你拿我数据做营销 | 退订/反对营销画像 |
★ 面试加分点:“可携带权”和“被遗忘权”是 GDPR 相对个保法更突出、面试更爱考的两条, 要能说清技术落地(可携带 = 导出标准化结构化数据;被遗忘 = 全链路删除)。
12.3.3 GDPR vs 个保法 对比表(面试高频)
| 维度 | 个保法(PIPL) | GDPR |
|---|---|---|
| 适用范围 | 在中国境内处理自然人信息 | 域外效力,覆盖欧盟居民 |
| 合法依据 | 以“同意”为核心,兼顾合同必需等 | 六种依据并列(同意/合同/法定义务/正当利益等) |
| 敏感信息 | “敏感个人信息”(列举 + 定义) | “特殊类别数据”(种族、健康、性取向等) |
| 删除权 | 删除权 | 删除权(被遗忘权),更强调 |
| 可携带权 | 有(条件性) | 有,明确且强调 |
| 罚款上限 | 5000 万人民币 或 营业额 5% | 2000 万欧元 或 全球营业额 4% |
| 数据出境 | 安全评估/标准合同/认证等路径 | 充分性认定/标准合同条款(SCC)/约束性公司规则(BCR) |
★ 一句话总结(面试可直接说):“个保法立足’境内处理 + 同意为核心’,GDPR 强调’域外效力 + 六种依据 + 被遗忘/可携带权’, 但两者的底层逻辑一致——都是’数据最小化 + 用户权利 + 重罚’。”
12.3.4 被遗忘权 / 可携带权的技术落地示例
import json
# 可携带权:把用户数据导出为机器可读的标准格式
def export_my_data(user_id: str) -> bytes:
data = {
"profile": query_user(user_id, USER_FIELDS["basic"] + USER_FIELDS["contact"]),
"orders": query_table("orders", user_id),
"exported_at": now(),
"format_version": "1.0", # 声明格式版本,方便接收方解析
}
return json.dumps(data, ensure_ascii=False, indent=2).encode("utf-8")
# 被遗忘权:全链路删除(主表 + 关联 + 缓存 + 备份引用)
def right_to_be_forgotten(user_id: str):
delete_user_data(user_id) # 见 12.2.3 的删除闭环
# 额外:通知第三方处理者同步删除(GDPR 要求控制者通知下游)
notify_processors(user_id, action="erasure")
★ 诚实提醒:被遗忘权的落地难点在于“备份和日志里的残留数据”——GDPR 允许“为证明合规、履行法定义务” 而保留必要的最少记录,但这和“彻底删除”之间存在张力,落地时要和法务一起明确“保留什么、删什么、删到哪一层”。
12.4 数据分类分级
12.4.1 什么是数据分类分级,用大白话讲
一句话定义:数据分类分级 = 给数据"分门别类" + "定安全等级",然后【按等级配不同的保护措施】。
生活类比:档案室管理文件。
· 分类:按"内容"分——人事档案、财务档案、技术档案(分类回答"这是什么")
· 分级:按"重要/敏感程度"分——公开、内部、秘密(分级回答"丢了有多严重")
· 落地:不同等级放不同柜子、不同人能看、不同借阅流程
★ 关键认知:分类分级是“数据安全治理的地基”。不知道哪些数据重要,就不知道把安全资源往哪投, 就会出现“不重要的数据花大钱保护、核心数据却裸奔”的错配。
12.4.2 中国的三级数据分级(《数据安全法》框架)
按"一旦被破坏、泄露、非法利用,对国家安全、公共利益、个人/组织合法权益的危害程度"分级:
· 一般数据:泄露危害小(如公开的新闻、已脱敏的统计)
· 重要数据:泄露可能危害国家安全、经济运行、社会稳定、公共利益(如能源、交通、人口健康大数据)
· 核心数据:关系国家安全、国民经济命脉、重要民生、重大公共利益(危害程度最重)
★ 面试要点:“重要数据”和“核心数据”是《数据安全法》的特有概念,和个人信息保护法里的 “敏感个人信息”不是一回事——前者站在“国家/公共安全”角度,后者站在“个人权益”角度。 一个数据集可能同时是“重要数据”又包含“敏感个人信息”。
12.4.3 常见的分类维度(按业务定,别生搬硬套)
| 分类维度 | 举例 |
|---|---|
| 按数据主体 | 个人信息、企业数据、公共数据、政务数据 |
| 按业务 | 用户数据、交易数据、日志数据、配置数据 |
| 按敏感度 | 公开 / 内部 / 秘密 / 机密 |
| 按来源 | 自采数据、第三方提供、公开爬取 |
★ 务实建议:分类分级没有“全国统一的一张表”,而是“行业有指引 + 企业自己定标准”。 金融、医疗、政务、汽车等行业各有指南,落地时要先找本行业的分类分级指引,再结合自身业务细化。
12.4.4 数据分类分级的技术落地
落地一:给数据打标签(元数据管理)
# 数据分级标签(示例,企业自定义)
DATA_LEVEL = {
"L1_PUBLIC": "公开数据,可自由流通",
"L2_INTERNAL": "内部数据,限企业内部",
"L3_SENSITIVE": "敏感数据,需授权 + 脱敏 + 审计",
"L4_CORE": "核心数据,最高管控,原则上不出域",
}
def tag_asset(asset_id: str, level: str, category: str, owner: str):
"""给每个数据资产打上'等级 + 分类 + 责任人'标签"""
meta_store.set(asset_id, {
"level": level, # 如 L3_SENSITIVE
"category": category, # 如 "个人信息/交易数据"
"owner": owner, # 数据责任人
"tagged_at": now(),
})
落地二:分级访问控制(不同等级不同权限)
# 访问数据前,校验"请求者的权限级别 >= 数据等级要求"
def access_data(user: dict, asset_id: str):
asset = meta_store.get(asset_id)
required = asset["level"]
user_level = user["clearance"] # 用户的"可访问等级"
if rank(user_level) < rank(required):
audit_log(f"DENIED: {user['id']} -> {asset_id} ({required})")
raise PermissionError("无权限访问该等级数据")
# 敏感/核心数据:额外要求"脱敏"或"审计"
if required in ("L3_SENSITIVE", "L4_CORE"):
audit_log(f"ACCESS: {user['id']} -> {asset_id} ({required})")
return read(asset_id)
落地三:分级存储与加密(不同等级不同保护强度)
· L1 公开:明文存,正常备份
· L2 内部:访问控制 + 传输加密(TLS)
· L3 敏感:加密存储(如 AES/SM4)+ 脱敏展示 + 访问审计 + 最小权限
· L4 核心:国密算法加密 + 密钥分级管理 + 不出域 + 双人复核 + 全程审计
★ 面试加分点:“分类分级是手段,差异化保护才是目的”——分级不是贴个标签就完事, 而是要驱动后续的【访问控制、加密、脱敏、审计、备份、出境】等一整套差异化措施。
12.5 数据出境
12.5.1 什么是数据出境,用大白话讲
一句话定义:数据出境 = 在中国境内运营中收集和产生的数据,被传输、存储到境外,
或虽存储在境内但【境外主体可以访问/处理】。
生活类比:不是"人出国",是"数据出国"。
· 把国内用户的资料存到国外的云服务器 → 出境
· 国内存数据,但国外分公司能远程访问 → 也算出境("向境外提供")
· 用境外 SaaS 工具处理国内客户数据 → 同样涉及出境
★ 最容易忽略的坑:很多人以为"服务器在国内"就没出境,其实只要【境外能访问到】,就是出境。
12.5.2 数据出境的三条合规路径
路径一:数据出境安全评估(国家网信部门组织的评估)
适用:重要数据出境;或个人信息处理者达到一定规模(如处理 100 万人以上个人信息、
或累计向境外提供 10 万人以上个人信息/1 万人以上敏感个人信息)等法定情形。
路径二:个人信息出境标准合同
适用:未达到"必须安全评估"门槛的个人信息出境,与境外接收方签标准合同并备案。
路径三:个人信息保护认证
适用:通过国家认可的认证机构,证明境外接收方具备相应的保护水平。
★ 底线原则:无论走哪条路径,都要满足"告知-同意 + 最小必要 + 出境前影响评估 + 安全保障"。
12.5.3 触发“必须申报安全评估”的典型情形(记忆版)
满足【任一】即须申报数据出境安全评估:
① 向境外提供"重要数据"
② 关键信息基础设施运营者向境外提供个人信息
③ 处理 100 万人以上个人信息者,向境外提供个人信息
④ 自上年 1 月 1 日起,累计向境外提供 10 万人以上个人信息 或 1 万人以上敏感个人信息
★ 面试要点:这几个数字(100 万 / 10 万 / 1 万)是高频考点,记清楚“谁、什么数据、达到多少量”。
12.5.4 数据出境的技术落地
落地一:数据本地化 + 境内存储优先
# 存储路由:核心/重要数据强制境内,普通数据才允许走跨境通道
STORAGE_REGION = {
"L1_PUBLIC": "any", # 公开数据,哪里都行
"L2_INTERNAL": "cn", # 内部数据,境内
"L3_SENSITIVE": "cn_only", # 敏感数据,仅境内,禁止出境
"L4_CORE": "cn_only", # 核心数据,仅境内
}
def route_storage(asset: dict):
region = STORAGE_REGION.get(asset["level"], "cn")
if region == "cn_only":
return china_storage.write(asset) # 强制境内
return default_storage.write(asset)
落地二:跨境传输的安全保障(加密 + 审计 + 最小化)
# 必须出境的场景:加密后传输,记录审计日志,只传必要字段
def cross_border_transfer(user_id: str, fields: list, destination: str):
# 1. 最小化:只传境外业务真正必需的字段
minimal = [f for f in fields if f in USER_FIELDS["contact"]] # 敏感字段一律不下发
data = query_user(user_id, minimal)
# 2. 加密(用国密 SM4 或 AES)后传输
ciphertext = sm4_encrypt(json.dumps(data), key_from_kms())
# 3. 全程审计
audit_log(f"cross_border: {user_id} -> {destination}, fields={minimal}")
return send(destination, ciphertext)
★ 面试加分点:数据出境的技术落地点是“三个最小 + 两个保障”—— 最小字段、最小范围、最短保留,加上传输加密 + 全程审计。 同时要和法务确认“走了哪条合规路径(安全评估/标准合同/认证)”,技术只是合规链条上的一环。
12.6 个人信息保护影响评估(DPIA / PIA)
12.6.1 什么时候必须做 DPIA
一句话定义:在开展"可能对个人权益有高风险"的数据处理活动【之前】,
先评估风险、想好降险措施,形成书面评估报告。
个保法明确【必须】做影响评估的情形(记忆版):
① 处理敏感个人信息
② 利用个人信息进行自动化决策(如算法评分、画像)
③ 委托处理、向第三方提供、公开个人信息
④ 向境外提供个人信息
⑤ 其他对个人权益有重大影响的情形
白话:DPIA 就是“动工前的安全交底”——先想清楚“我要拿用户数据干嘛、会不会出事、出事怎么兜底”, 而不是等出了事再补救。
12.6.2 DPIA 的标准流程(五步)
第一步:描述处理活动
处理什么数据?什么目的?什么范围?涉及多少人?存多久?谁在管?
第二步:评估必要性 & 合规性
这个处理是否"最小必要"?是否已取得同意?是否有合法依据?
第三步:识别风险
泄露、滥用、过度收集、跨境、自动化决策歧视……各有什么风险?概率多大?影响多大?
第四步:设计降险措施
脱敏、加密、访问控制、最小化、留存期限、应急预案……
第五步:形成报告 + 持续跟踪
记录评估结论;当处理活动变化时,重新评估。
12.6.3 DPIA 报告模板(可直接套用)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
个人信息保护影响评估报告(摘要模板)
1. 处理活动概述:________(如"用于风控的自动化评分")
2. 涉及数据类型:□一般个人信息 □敏感个人信息(____)□未成年人信息
3. 数据规模/范围:________人,境内□ 出境□
4. 合法依据:□同意 □合同必需 □法定义务 □其他____
5. 风险识别:
· 风险1:________(概率:高/中/低;影响:高/中/低)
· 风险2:________
6. 降险措施:
· 措施1:脱敏/加密/访问控制/最小化________
7. 评估结论:□可开展 □附条件开展(需完成____) □不可开展
8. 复核人 / 日期:________
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
★ 面试加分点:DPIA 的核心是“事前、书面、留痕、可追溯“——它是证明”你已经尽到合规义务“的关键证据, 出问题时,一份合格的 DPIA 报告能显著降低处罚风险。
12.7 等保 2.0、密评与国密算法
12.7.1 等保 2.0:五步 + 定级
等保 2.0 的五个规定动作(顺序不能乱):
定级 → 备案 → 建设整改 → 等级测评 → 监督检查
定级(五个等级,绝大多数企业是二级或三级):
一级:损害公民/组织合法权益(最低)
二级:损害公民/组织合法权益,或对社会秩序造成轻微危害
三级:损害国家安全、社会秩序、公共利益(★ 多数金融/政务/重要业务在此)
四级:对社会秩序、公共利益造成特别严重危害
五级:对国家安全造成特别严重危害(最高,特殊场景)
★ 三级及以上:必须委托【有资质的测评机构】做等级测评,是上线的硬门槛。
白话:等保就像“给大楼定消防等级、装对应设施、定期验收”。定级越高,防火墙、加密、审计、灾备的要求越严。
12.7.2 等保 2.0 的技术要求框架(面试要点)
等保 2.0 的要求分"安全通用要求 + 安全扩展要求",技术层面核心是"一个中心、三重防护":
一个中心:安全管理中心(统一的管理、审计、策略下发)
三重防护:
① 安全通信网络(网络架构、边界防护、传输加密)
② 安全区域边界(边界防护、入侵防范、恶意代码防范)
③ 安全计算环境(身份鉴别、访问控制、数据加密、数据备份、审计)
★ 常考的具体要求(二级/三级通用):
· 身份鉴别:口令复杂度 + 登录失败锁定 + 双因素(三级)
· 访问控制:最小权限、三权分立(管理员/审计员/操作员分离)
· 安全审计:日志留存不少于 6 个月(重要系统)
· 数据完整性与保密性:传输/存储加密、备份、异地容灾
· 入侵防范:部署 IDS/IPS、防病毒、边界防火墙
12.7.3 密评(商用密码应用安全性评估)
一句话定义:密评 = 对"系统里用没用合规的密码技术、用得好不好"进行评估。
什么时候要过密评:
· 等保三级及以上的系统,通常要求同步过密评
· 关键信息基础设施(关基)
· 政务、金融、能源、交通等重要领域的系统
密评查什么:
· 密码算法是否合规(是否用了国密算法)
· 密码产品/服务是否合规(用了有资质的密码产品)
· 密码应用是否到位(加密、签名、密钥管理是否规范)
12.7.4 国密算法(SM2 / SM3 / SM4)+ 代码示例
三个最常考的国密算法,记住"对标关系":
SM2 —— 非对称(公钥加密/数字签名),对标 RSA / ECDSA
SM3 —— 哈希(摘要),对标 SHA-256
SM4 —— 对称(分组加密),对标 AES
# 用 Python 的 gmssl 库演示国密算法的基本用法(示意)
from gmssl import sm2, sm3, sm4
# ---- SM3 哈希(对标 SHA-256)----
def sm3_hash(text: str) -> str:
crypt_sm3 = sm3.CryptSM3()
return crypt_sm3.hash(text.encode("utf-8"))
# ---- SM4 对称加密(对标 AES,密钥 16 字节)----
def sm4_encrypt(plaintext: bytes, key: bytes) -> bytes:
crypt_sm4 = sm4.CryptSM4()
crypt_sm4.set_key(key, sm4.SM4_ENCRYPT)
return crypt_sm4.crypt_ecb(plaintext) # 生产建议用 CBC/GCM 模式
# ---- SM2 公钥加密(对标 RSA 加密,密钥 64 字节十六进制私钥)----
def sm2_encrypt(public_key: str, data: bytes) -> bytes:
crypt_sm2 = sm2.CryptSM2(private_key="", public_key=public_key)
return crypt_sm2.encrypt(data)
★ 面试加分点:要能说出“为什么用国密”——自主可控 + 合规要求。在政务、金融、关基场景, 等保/密评会要求关键环节使用国密算法;同时要能说出“国密算法的安全性对标国际算法, 但生态/性能/兼容性还在追赶”这种客观判断。
12.7.5 等保、密评、关基 三者的关系(面试高频)
网络安全等级保护(等保 2.0)── 通用基础制度,绝大多数系统都要做
│
├── 三级以上系统 ──► 同步要求 密评(商用密码应用安全性评估)
│
关键信息基础设施(关基)── 等保基础上"再加码"的重点保护对象
│(能源、交通、金融、水利、公共服务、国防科技等一旦破坏即危及国家安全)
│
数据安全法 / 个保法 ── 从"系统安全"延伸到"数据安全 + 个人信息保护"
★ 一句话串起来:等保管"系统",密评管"密码",关基管"重点系统",
数安法/个保法管"数据和个人信息",它们共同构成中国的网络安全与数据合规体系。
12.8 面试题 L 组:数据合规与隐私保护(30 题)
12.8.1 基础题(L1 ~ L12)
L1. 什么是个人信息(PII)?什么算“敏感个人信息”?
★ 定义:PII = 能直接或间接识别到具体自然人的信息。
生活类比:PII 像“指纹”——“张三”可能重名,“张三 + 手机号”就锁定是你。
敏感个人信息:一旦泄露/滥用易损害人格尊严或人身、财产安全——身份证号、银行账户、行踪轨迹、 健康医疗、生物识别(人脸指纹)、宗教信仰、不满 14 周岁未成年人信息等。
★ 加分点:敏感个人信息的处理要“单独同意 + 特定目的 + 充分必要 + 严格保护”。
L2. 个保法的核心原则有哪些?(至少说 5 条)
答:告知-同意、最小必要、目的限制、单独同意(敏感/第三方/跨境)、用户权利(查询更正删除撤回注销)、 安全保护义务、公开透明。
★ 加分点:能对应到技术落地——“最小必要”对应接口字段裁剪,“删除权”对应全链路删除闭环。
L3. 什么是“告知-同意”?技术怎么落地?
★ 定义:收集前明明白白告诉用户“谁、收什么、干嘛用、存多久”,并取得自愿明确同意。
技术落地:隐私政策单独弹窗(不能默认勾选)、敏感信息单独勾选框、同意记录留痕(时间+版本+目的)。
★ 加分点:留痕是关键——出问题时,同意记录是证明“已尽告知义务”的证据。
L4. GDPR 和个保法最大的区别是什么?
答(三点):
- 适用范围:GDPR 有域外效力(管欧盟居民),个保法立足境内处理
- 合法依据:GDPR 六种并列(同意/合同/法定义务/正当利益等),个保法以同意为核心
- 特色权利:GDPR 更强调被遗忘权、可携带权
★ 加分点:两者底层逻辑一致——数据最小化 + 用户权利 + 重罚(GDPR 4%/2000万欧,个保法 5%/5000万)。
L5. 什么是数据分类分级?为什么它很重要?
★ 定义:给数据“分门别类 + 定安全等级”,按等级配差异化保护。
生活类比:档案室管理——按内容分类(人事/财务/技术),按重要程度分级(公开/内部/秘密)。
为什么重要:不知道哪些数据重要,安全资源就会错配(不重要的花大钱,核心的裸奔)。
★ 加分点:分级是手段,差异化保护(访问控制/加密/脱敏/审计/出境)才是目的。
L6. 《数据安全法》里的“重要数据”和“核心数据”是什么?
★ 定义:按“泄露/非法利用对国家安全、公共利益等的危害程度”分级。 重要数据 = 可能危害国家安全、经济运行、社会稳定、公共利益; 核心数据 = 关系国家安全、国民经济命脉、重大公共利益(危害最重)。
★ 加分点:和“敏感个人信息”不是一回事——前者站在国家/公共安全角度,后者站在个人权益角度。
L7. 什么是数据出境?“服务器在国内”就安全了吗?
★ 定义:境内收集产生的数据,被传输/存储到境外,或境内存储但境外可访问。
生活类比:不是“人出国”,是“数据出国”;用境外 SaaS 处理国内客户数据也算出境。
★ 加分点:最容易忽略的坑——服务器在国内,但境外能远程访问,也构成出境。
L8. 数据出境有哪几条合规路径?
答(三条):① 数据出境安全评估(重要数据/达到规模);② 个人信息出境标准合同;③ 个人信息保护认证。
★ 加分点:无论哪条路径,都要满足“告知-同意 + 最小必要 + 出境前影响评估 + 安全保障”。
L9. 触发“必须申报数据出境安全评估”的情形有哪些?
答(记忆数字):① 出境重要数据;② 关基运营者出境个人信息;③ 处理 100 万人以上个人信息者出境个人信息; ④ 累计出境 10 万人以上个人信息 或 1 万人以上敏感个人信息。
★ 加分点:100 万 / 10 万 / 1 万 这三个数字是高频考点。
L10. 什么是 DPIA?什么时候必须做?
★ 定义:开展高风险数据处理活动之前,先评估风险、设计降险措施、形成书面报告。
必须做的情形:处理敏感个人信息、自动化决策、委托/第三方/公开、出境、其他重大影响。
★ 加分点:核心是“事前、书面、留痕、可追溯”,是证明“已尽义务”的关键证据。
L11. 什么是等保 2.0?五个规定动作是什么?
★ 定义:对信息系统按重要程度分等级、按等级做安全保护的强制性制度。
五个动作:定级 → 备案 → 建设整改 → 等级测评 → 监督检查。
★ 加分点:三级及以上必须找有资质机构测评,是上线的硬门槛。
L12. 什么是国密算法?SM2/SM3/SM4 分别对标什么?
答:国密 = 中国自主商用密码算法。SM2(非对称加密/签名,对标 RSA/ECDSA)、SM3(哈希,对标 SHA-256)、 SM4(对称加密,对标 AES)。
★ 加分点:用国密是“自主可控 + 合规”要求,政务/金融/关基场景常见。
12.8.2 进阶题(L13 ~ L22)
L13. “最小必要”原则在接口设计上怎么落地?
答:接口按“字段层级”返回——基础字段/联系字段/敏感字段分档,默认只返回业务必需的最小集合, 敏感字段绝不下发;采集时“能收手机号就不收身份证”。
★ 加分点:结合代码说“get_user_profile(need) 按需返回字段层级”这种落地。
L14. 用户的“删除权”怎么彻底落地?有什么坑?
答:不只删主表,要删关联表(订单/日志/画像)、缓存、并标记备份/归档待物理清除,形成删除任务闭环。
坑:日志、备份、数仓、缓存里还躺着数据,严格来说不算“删除”。
★ 加分点:设计“删除任务队列 + 备份保留期 + 定期物理清除”闭环。
L15. 敏感个人信息在技术上有哪些特殊保护要求?
答:单独同意、特定目的+充分必要、严格保护措施(加密存储、脱敏展示、最小权限、访问审计)、 处理未成年人信息要监护人同意。
★ 加分点:给“敏感字段默认不下发 + 展示脱敏 + 访问留痕”的代码思路。
L16. 数据分类分级后,怎么驱动“差异化保护”?
答:不同等级配不同措施——L1 明文、L2 访问控制+TLS、L3 加密+脱敏+审计+最小权限、L4 国密+不出域+双人复核。
★ 加分点:强调“分级是手段,差异化保护才是目的”,不是贴标签就完事。
L17. 数据出境的技术保障措施有哪些?
答:三个最小(最小字段、最小范围、最短保留)+ 两个保障(传输加密、全程审计); 核心/重要数据强制境内存储。
★ 加分点:技术只是合规链条的一环,要和法务确认“走了哪条路径(评估/标准合同/认证)”。
L18. 等保 2.0 的“一个中心、三重防护”是什么?
答:一个中心 = 安全管理中心;三重防护 = 安全通信网络、安全区域边界、安全计算环境。
★ 加分点:能说出具体措施(身份鉴别双因素、最小权限、审计日志留 6 个月、传输存储加密、备份容灾)。
L19. 等保、密评、关基 三者什么关系?
答:等保管“系统”(通用基础)、密评管“密码”(三级以上同步要求)、关基管“重点系统”(等保上加码)。
★ 加分点:串成“等保 + 密评 + 数安法/个保法”共同构成中国网络安全与数据合规体系。
L20. 合规和安全有什么区别?为什么“合规”不等于“安全”?
答:安全回答“怎么不被攻击”,合规回答“怎么不违法”;合规往往是安全的最低标准。
★ 加分点:过了等保照样可能被黑(等保是底线不是攻不破);技术安全却违规收集照样被罚。
L21. 自动化决策(算法评分)有哪些合规风险?
答:个保法要求自动化决策透明 + 结果公平公正,不得对个人实行不合理的差别待遇; 涉及重大影响的自动化决策,个人有权要求说明,并有权拒绝“仅由自动化决策”作出的决定。
★ 加分点:DPIA 必做 + 提供人工复核渠道 + 决策可解释。
L22. 一份合格的 DPIA 报告要包含哪些要素?
答:处理活动概述、数据类型与规模、合法依据、风险识别(概率×影响)、降险措施、评估结论、复核人。
★ 加分点:核心是“事前、书面、留痕、可追溯”。
12.8.3 场景题(L23 ~ L27)
L23. 老板说“我们收集用户信息越多越好,以后有用”,你怎么回应?
答(三步):
- 合规风险:违反“最小必要”,个保法最高罚营业额 5%/5000 万
- 安全风险:多存一份敏感数据 = 多一个泄露点 + 多一份保护成本
- 给方案:先明确业务真正需要哪些字段,只收必需的;用“字段分级 + 按需返回”落地
★ 加分点:把“合规”翻译成“成本和风险”,让老板听得懂利害。
L24. 你发现数据库里存了明文身份证号,怎么处理?
答:
- 定性:身份证是敏感个人信息,明文存储不合规且风险高
- 整改:加密存储(如 SM4/AES)+ 展示脱敏 + 最小权限 + 访问审计
- 收尾:存量数据清洗(历史明文加密回迁),更新 DPIA,确认是否“单独同意”到位
★ 加分点:区分“存量整改”和“新增管控”两条线,存量往往更难(要兼容老数据)。
L25. 公司要把数据放到境外云服务器,作为技术负责人你第一步做什么?
答:
- 先确认是否构成“数据出境”(境外存储/境外可访问都算)
- 确认数据类型(是否重要数据/敏感个人信息)和规模(是否触发安全评估门槛)
- 拉法务确认合规路径(评估/标准合同/认证)
- 技术侧:最小字段 + 传输加密 + 审计 + 境内保留必要副本
★ 加分点:技术负责人第一动作是“识别是否出境 + 拉法务”,而不是闷头做技术迁移。
L26. 面试官问你“等保三级系统,你会重点做哪些安全建设?”
答(按三重防护展开):
- 身份鉴别:口令复杂度 + 失败锁定 + 双因素
- 访问控制:最小权限、三权分立
- 审计:日志留存 6 个月以上、集中审计
- 数据安全:传输/存储加密、备份、异地容灾
- 边界防护:防火墙 + 入侵防范 + 恶意代码防范
- 密码应用:密评达标(国密算法)
★ 加分点:主动补一句“还要同步准备密评”,体现体系化认知。
L27. 用户投诉“你们把我的数据泄露了”,你怎么应对?
答:
- 先核实:是否真的泄露、泄露了什么、影响多少人
- 止损:封堵漏洞、冻结相关数据、联系可能泄露方
- 合规动作:按个保法要求“立即补救 + 通知用户 + 报告主管部门”(重大泄露有报告义务)
- 留痕:记录时间线、处置过程,配合调查
★ 加分点:个保法要求发生泄露时“立即采取补救措施 + 及时通知个人 + 按规定报告”, 这是法定义务,不能隐瞒。
12.8.4 追问链(L28 ~ L30)
L28. 数据合规十连问
Q1: 三法一条例分别是什么? A: 网安法、数据安全法、个保法 + 数据出境安全评估办法等配套。
Q2: 网安法/数安法/个保法各管什么? A: 网安法管网络运行安全,数安法管数据安全,个保法管个人信息。
Q3: 敏感个人信息举 5 个例子? A: 身份证号、银行账户、行踪轨迹、健康医疗、生物识别(人脸指纹)。
Q4: 最小必要是什么? A: 只收提供服务所必需的信息,不能多收。
Q5: 单独同意在哪些场景必须? A: 敏感个人信息、向第三方提供、跨境提供。
Q6: 数据出境的三种路径? A: 安全评估、标准合同、保护认证。
Q7: 触发安全评估的个人信息量级? A: 处理 100 万人以上 / 累计出境 10 万个人信息 / 1 万敏感个人信息。
Q8: GDPR 罚款上限? A: 2000 万欧元 或 全球营业额 4%,取高。
Q9: 等保五步? A: 定级、备案、建设整改、等级测评、监督检查。
Q10: SM2/SM3/SM4 对标什么? A: SM2→RSA/ECDSA,SM3→SHA-256,SM4→AES。
L29. 个保法技术落地十连问
Q1: 告知-同意怎么落地? A: 隐私政策单独弹窗 + 敏感字段单独勾选 + 同意记录留痕。
Q2: 最小必要怎么落地? A: 接口字段分级、按需返回,采集字段能少则少。
Q3: 删除权怎么落地? A: 全链路删除:主表 + 关联表 + 缓存 + 备份引用 + 物理清除闭环。
Q4: 可携带权怎么落地? A: 导出标准化结构化数据(JSON/CSV)。
Q5: 敏感信息怎么保护? A: 加密存储 + 脱敏展示 + 最小权限 + 访问审计。
Q6: 自动化决策要满足什么? A: 透明 + 公平 + 可拒绝仅自动决策 + 提供说明。
Q7: 数据泄露了要做什么? A: 立即补救 + 通知个人 + 报告主管部门。
Q8: 数据分类分级怎么落地? A: 元数据打标签(等级+分类+责任人)+ 分级访问控制 + 分级存储加密。
Q9: 跨境传输技术要点? A: 最小字段 + 传输加密 + 全程审计。
Q10: 合规落地最大的坑? A: 只做“表面合规”(贴标签、写政策),没落到代码和架构里。
L30. 给非技术朋友讲“数据合规”八连问
Q1: 数据合规是啥? A: 就是“收集、使用别人数据时,守规矩、不越界”。
Q2: 个保法是啥? A: 给“个人信息怎么收集怎么用”立的交通法规。
Q3: 什么算个人信息? A: 能认出“就是你”的信息——名字+手机号就能锁定你。
Q4: 敏感个人信息是啥? A: 身份证、银行卡、人脸、健康、行踪这些“高危品”。
Q5: 数据出境是啥? A: 不是人出国,是数据出国——存到国外服务器、让国外能访问。
Q6: 等保是啥? A: 给系统按重要程度定消防等级、装对应设施、定期验收。
Q7: 国密是啥? A: 国产锁芯标准,关键系统要用国产的加密算法。
Q8: 普通用户怎么保护自己? A: 授权时看清要什么、能少给就少给、定期撤销不用的授权、不点陌生链接。
12.9 第十二章小结
这一章把视角从“怎么不被黑”切换到“怎么不违法”。安全是“防止数据被坏人拿走”,合规是“防止数据被自己乱用”。 两者一体两面,但落地方式完全不同:安全靠技术(加密、访问控制、审计), 合规靠“制度 + 技术 + 留痕”三者结合。对工程师而言,最关键的一句话是—— 合规不是法务的事,而是架构设计的一部分,必须前置到写代码之前。
12.9.1 五条核心认知
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知一:合规是"架构约束",不是"事后补材料"
"最小必要"影响接口设计,"删除权"影响存储设计,"可携带权"影响导出设计,
"数据出境"影响部署架构。这些都要在写代码前想清楚,上线后再改成本极高。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知二:三法一条例,各管一段
《网安法》管网络运行安全 → 《数安法》管数据安全 → 《个保法》管个人信息,
加上数据出境等配套办法,共同构成中国网络安全与数据合规体系。
口诀:"网安法管网络,数安法管数据,个保法管个人。"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知三:个人信息处理的核心是"告知-同意 + 最小必要 + 用户权利"
收集前明明白白告知并同意、只收必需的、用户能查能改能删能带走。
敏感个人信息要"单独同意",未成年人信息要"监护人同意"。
这三条是几乎所有个保法落地场景的"公分母"。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知四:数据分类分级是"差异化保护"的地基
不知道哪些数据重要,安全资源就会错配。分级之后,用不同的访问控制、
加密、脱敏、审计、备份、出境策略去保护——分级是手段,差异化保护才是目的。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
认知五:"合规"≠"安全",但合规是安全的最低标准
过了等保照样可能被黑;技术很安全却违规收集照样被罚。
优秀工程师两个都要懂,且能分清"这是安全需求还是合规需求"。
12.9.2 合规速查卡
| 主题 | 核心要求 | 一句话记忆 |
|---|---|---|
| 个人信息处理 | 告知-同意 + 最小必要 + 目的限制 | 先告知、再同意、只收必需的 |
| 敏感个人信息 | 单独同意 + 特定目的 + 严格保护 | 高危品要单独申报 |
| 用户权利 | 查询/更正/删除/撤回/注销/可携带 | 用户的数据,用户说了算 |
| 数据分类分级 | 分类 + 定级 + 差异化保护 | 分好类、定好级、差别保护 |
| 数据出境 | 评估/标准合同/认证 + 安全保障 | 数据出国,先办手续 |
| 等保 2.0 | 定级→备案→整改→测评→监督 | 按等级装设施、定期验收 |
| 密评 | 密码算法/产品/应用合规 | 关键系统用国密 |
| GDPR | 六种依据 + 用户权利 + 重罚 | 管全球欧盟居民数据 |
12.9.3 数据合规成熟度自评表(L0 ~ L4)
| 级别 | 状态 | 典型表现 | 下一步 |
|---|---|---|---|
| L0 无意识 | 无制度、无意识 | 明文存身份证、随便收集、不知道个保法 | 做一次数据盘点 |
| L1 有意识 | 知道但不系统 | 有隐私政策,但没落到代码 | 建数据分类分级 + 敏感数据清单 |
| L2 制度化 | 有流程有留痕 | 有 DPIA、有同意记录、有删除流程 | 合规要求落到架构(加密/脱敏/访问控制) |
| L3 技术化 | 合规进代码 | 字段分级、加密存储、审计留痕自动化 | 上数据出境合规 + 密评/等保 |
| L4 闭环 | 持续合规 | 定期评估、跨境合规、应急响应完备 | 持续跟踪法规变化,定期复审 |
★ 判断口诀:L0 是“不知道”,L1 是“知道了没做”,L2 是“做了没进代码”,L3 是“进代码了没闭环”,L4 是“闭环了能持续”。 多数团队卡在 L1→L2,根因是“把合规当法务的事,没当成架构的事”。
12.9.4 五份可直接使用的清单
清单一:个人信息处理合规自查
□ 收集前是否告知(谁/收什么/干嘛用/存多久/联系方式)?
□ 是否取得明确同意(非默认勾选)?
□ 是否最小必要(能少收就少收)?
□ 敏感信息是否单独同意?未成年人是否监护人同意?
□ 是否有同意记录留痕(时间+版本+目的)?
清单二:用户权利落地自查
□ 用户能否查询自己的数据?
□ 用户能否更正?
□ 用户能否删除(全链路,含缓存/备份引用)?
□ 用户能否撤回同意、注销账户?
□ 用户能否导出数据(可携带权)?
清单三:数据分类分级自查
□ 是否做了数据资产盘点?
□ 是否给每个资产打了等级 + 分类 + 责任人标签?
□ 是否区分了"敏感个人信息 / 重要数据 / 核心数据"?
□ 是否按等级配了差异化访问控制 / 加密 / 审计?
清单四:数据出境合规自查
□ 是否识别出所有"境外存储 / 境外可访问"的场景?
□ 是否确认数据类型(重要数据/敏感个人信息)和规模(是否触发评估门槛)?
□ 是否已确认合规路径(评估 / 标准合同 / 认证)?
□ 是否落实了最小字段 + 传输加密 + 全程审计?
清单五:等保/密评准备自查
□ 是否完成定级与备案?
□ 三级以上是否已委托测评机构?
□ 身份鉴别是否达标(口令复杂度/失败锁定/双因素)?
□ 访问控制是否最小权限、三权分立?
□ 日志是否留存 6 个月以上?
□ 关键环节是否使用国密算法(SM2/SM3/SM4)?是否准备密评?
12.9.5 五句话记忆法
一句话记【个保法】:先告知、再同意、只收必需的,用户数据用户说了算。
一句话记【敏感信息】:身份证、银行卡、人脸、行踪是高危品,要单独申报。
一句话记【数据出境】:不是人出国,是数据出国,出国先办手续。
一句话记【等保】:按等级装设施、定期验收,三级以上是硬门槛。
一句话记【合规本质】:合规不是法务的事,是写代码之前就该想清楚的架构约束。
12.9.6 本章与前后章节的关系
┌─────────────────────────────────────┐
│ 第十三章 综合实战:六道大题的攻防推演 │
│ (把前十二章的知识串起来打实战) │
└─────────────────────────────────────┘
▲
前十一章(技术攻防) │ 从"不被黑"到"不违法"
┌──────────────────────────┐ ┌──────────────────────────────┐
│ 第一~五章:应用层 │→ │ 第十二章 数据合规与隐私保护 │
│ 第六~九章:主机/供应链 │ │ · 个保法 / GDPR │
│ 第十章:云原生 │ │ · 分类分级 / 数据出境 │
│ 第十一章:Web3 │ │ · 等保 / 密评 / 国密 │
└──────────────────────────┘ └──────────────────────────────┘
│ │
└────────── 安全与合规是一体两面 ───────────┘
(安全防"被偷",合规防"被乱用";都靠最小权限、审计、留痕这些基本功)
一句话串起来:第十二章补上了整个安全知识体系的最后一块拼图——技术之外,还有法律和制度的红线。 一个完整的安全工程师,既要会“攻防”,也要懂“合规”,还要能把两者都翻译成工程落地。 下一章(第十三章)就是大考:用六道综合实战题,把前面十二章的知识串起来,做完整的攻防推演。
第十三章:综合实战——六道大题串起全书
本章定位:前面十二章是“分科”——一章一个专题。这一章是“综合大考”: 用六道贴近真实场景的大题,把分散的知识点串成完整的攻防推演。 面试里,高级岗位最爱考这种“给一个场景,看你能不能系统性地分析、决策、落地”的题。
怎么用这一章:每道题先自己想一想,再对照答案。重点不是“记住答案”,而是 学会这套**“识别风险 → 推演攻击 → 分层防御 → 落地检查”**的分析框架。
13.1 综合实战题一:一个电商系统的全链路攻防
场景
你接手一个电商系统:Java 后端 + MySQL + Redis + 前端 Vue + Nginx,对外有登录、下单、支付、订单查询。 老板问:“我们这个系统,攻击者会怎么打进来?我们该怎么防?” 请给出一份“攻击链推演 + 分层防御”的完整分析。
攻击链推演(攻击者视角)
第一步:信息收集(打点)
· 扫描暴露端口、识别框架指纹(Nginx 版本、Java 中间件)
· 找子域名、GitHub 搜源码/密钥、看错误页面泄露的堆栈信息
第二步:找入口(突破)
· 登录接口:撞库、弱口令、SQL 注入
· 支付/下单接口:越权、参数篡改(改金额、改数量)
· 订单查询接口:水平越权(改 orderId 看别人订单)
· 评论/搜索:存储型 XSS、注入
第三步:提权与内网横向
· SQL 注入拿数据库 → 拖用户表(含手机号、密文密码、可能明文敏感字段)
· 服务器 RCE(反序列化、上传 WebShell)
· 内网横向:Redis 未授权、SSRF 打内网服务
第四步:扩大战果
· 拖库 → 撞库其他平台 → 卖给黑产
· 勒索:加密数据 + 删备份
· 埋后门:持久化,长期窃取
分层防御(防守者视角,对应全书章节)
| 攻击环节 | 对应防御 | 详参 |
|---|---|---|
| 信息收集 | 收敛暴露面、隐藏版本、错误页不泄露堆栈 | 第一~五章 |
| 注入 | 预编译参数化、WAF、输入校验 | 第二章 |
| 越权/篡改 | 服务端校验金额、对象级授权、防水平越权 | 第二~五章 |
| XSS | 输出编码、CSP、HttpOnly Cookie | 第三章 |
| 认证会话 | 强密码、多因素、会话管理、防撞库(限速/验证码) | 第四章 |
| 数据库安全 | 最小权限、加密敏感字段、审计 | 第六章 |
| 供应链 | 依赖漏洞扫描(SCA)、SBOM | 第九章 |
| 应急响应 | 日志留存、备份、应急预案、遏制流程 | 第八章 |
面试答题框架(记住这四步)
1. 先定性:把系统拆成"入口层 / 应用层 / 数据层 / 基础设施层"
2. 逐层推演攻击:每层最可能的攻击手法是什么
3. 分层给防御:每个攻击手法对应什么防御措施
4. 给优先级:不是所有防御一起上,而是按"被攻击概率 × 损失"排序,先堵最高危的
★ 加分点:结尾补一句“安全不是一次做完,而是先做’拖库、越权、支付篡改’这三件最容易出事、损失最大的事, 再逐步覆盖。分清 P0/P1/P2 优先级,比列一堆工具清单更能体现工程思维。”
13.2 综合实战题二:一次 SSRF 引发的云上横向渗透
场景
你的 Web 应用有个“用户输入 URL → 服务端抓取该 URL 内容”的功能(比如抓网页标题/图片预览)。 部署在云上(AWS 或国内云),服务有访问云存储、云数据库的权限。 面试官问:“这个功能有什么风险?攻击者能走到哪一步?怎么防?”
攻击链推演
第一步:确认 SSRF 存在
· 输入 http://127.0.0.1:8080 看能否访问到内网服务(端口探测)
第二步:打元数据服务(云上的"隐藏后门")
· 请求 http://169.254.169.254/... (各云元数据地址)
· 拿到本机角色的【临时访问密钥】(IAM/云凭据)
第三步:用偷来的密钥横向
· 列存储桶 → 拖走敏感文件
· 访问数据库 → 拖库
· 如果密钥权限过大(如 s3:* / admin)→ 甚至提权、删桶、创建资源
第四步:持久化 + 扩大
· 创建新的高权限密钥留后门
· 跨服务横向,甚至打到其他账号
关键知识点串联(第十、二章)
1. SSRF 本质(第二章):服务端代替客户端发请求,攻击者控制了"请求的目标"
2. 元数据服务(第十章 10.2.3):169.254.169.254 是云主机内置的"身份证查询窗口"
3. 权限过大(第十章 10.2.2):偷到的密钥权限有多大,损失就有多大
完整防御(三层都要做)
# 第一层:应用层 SSRF 白名单 + DNS 二次解析校验
import ipaddress, socket
BLOCKED = ipaddress.ip_network("169.254.0.0/16") # 元数据段
PRIVATE = [
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("172.16.0.0/12"),
ipaddress.ip_network("192.168.0.0/16"),
ipaddress.ip_network("127.0.0.0/8"),
]
def is_safe_url(url: str) -> bool:
host = parse(url).hostname
ip = ipaddress.ip_address(socket.gethostbyname(host)) # 第一次解析
# 再解析一次,防 DNS rebinding(两次解析结果不一致 = 攻击)
if socket.gethostbyname(host) != str(ip):
return False
if ip in BLOCKED or any(ip in net for net in PRIVATE):
return False
return True
第二层:云平台层
· 开启 IMDSv2(要求 PUT token 才能读元数据)
· 容器 hop limit 设 1
· 最小权限:应用角色只给"真正需要"的权限,绝不 s3:* / admin
第三层:检测层
· 监控"对 169.254.169.254 的异常访问"
· 云审计日志开数据事件,告警异常密钥使用
面试答题框架
1. 定性:这是"SSRF → 元数据服务 → 云凭据泄露"的经典链,是云上最危险的 SSRF 变种
2. 推演:SSRF → 169.254.169.254 → 偷临时密钥 → 凭密钥权限横向
3. 防御三层:应用层白名单 + 云平台层(IMDSv2 + 最小权限)+ 检测层(审计告警)
4. 诚实补一句:IMDSv2 不能 100% 防 SSRF(DNS rebinding 等),但能把攻击成本拉高一个数量级
★ 加分点:能说出“SSRF 在云上比传统环境危险得多”——传统 SSRF 最多打打内网服务, 云上 SSRF 能直接偷到角色密钥、接管云资源,所以“元数据服务”是云安全里最被低估的攻击面。
13.3 综合实战题三:一次供应链投毒事件的完整溯源
场景
你的 CI 流水线某天开始,构建产物里出现了一个可疑的域名外联请求,而且只在生产环境触发。 排查发现是一个上游 npm 依赖被投毒了。面试官问:“你怎么溯源这件事?怎么防它再次发生?”
溯源推演(应急响应 + 供应链取证)
第一步:止血(遏制)
· 锁定受影响的构建版本,回滚到干净版本
· 下架受污染产物,切断可疑外联
第二步:定位(溯源)
· 从"可疑外联域名"反查 → 是哪个依赖引入的
· 比对 package-lock / lock 文件,找出"哪个依赖在哪个时间点被换成了恶意版本"
· 检查是否是:Typosquatting(拼写相似的假包)?账号劫持?版本回滚投毒?
第三步:定范围(影响面)
· 哪些构建、哪些版本、哪些环境用了这个坏依赖
· 恶意包做了什么(窃取密钥?留后门?外传数据?)
第四步:根因(为什么进来了)
· 依赖是否固定了版本?还是用了 ^ / latest 拉到了最新毒包?
· 是否用了私有源?私服是否校验了完整性?
第五步:复盘(防再发)
· 锁依赖版本 + 锁 hash
· 引入 SBOM + 依赖漏洞扫描(SCA)进 CI
· 关键依赖做人工评审 + 多源校验
关键知识点串联(第九章)
1. 依赖投毒五种姿势(9.2):Typosquatting / 依赖混淆 / 账号劫持 / 生命周期脚本 / 版本回滚
2. 供应链防线(9.3~9.5):锁文件、SBOM、Sigstore 签名、私有源、CI 安全
3. 溯源工具(9.8):依赖 diff、lock 文件比对、恶意包行为特征(外联、读密钥、生命周期脚本)
防御落地(可复用的流水线加固)
# 示例:CI 里的依赖安全门禁(伪代码,示意)
steps:
- name: 锁文件校验
run: |
# 必须存在 lock 文件,且和 package.json 一致,禁止拉最新
test -f package-lock.json || exit 1
npm ci # 严格按 lock 安装,不用 npm install
- name: 依赖漏洞 + 恶意包扫描
run: |
npm audit --audit-level=high # 已知漏洞
# 扫描可疑生命周期脚本、可疑外联域名
./scan_malicious_deps.sh
- name: 生成 SBOM
run: cyclonedx-bom -o sbom.cdx.json
面试答题框架
1. 先讲溯源思路:止血 → 定位(反查外联域名 + 比对 lock 文件)→ 定范围 → 找根因 → 复盘
2. 再讲根因:大概率是"依赖没锁版本,拉到了最新毒包"或"拼写相似假包"
3. 最后讲防线:锁依赖 + SBOM + SCA 进 CI + 私有源 + 关键依赖人工评审
★ 加分点:强调“供应链攻击利用的是信任,不是漏洞”——你信任了上游,上游被攻破,你就连带中招。 所以防御的核心是“信任最小化”:锁版本、锁 hash、签名验证、私有源、关键依赖评审。
13.4 综合实战题四:一个 DeFi 协议被“闪电贷 + 价格操纵”打穿
场景
一个借贷协议,用 DEX 现货价格作为抵押品定价,且奖励按“合约瞬时余额”分配。 面试官问:“这个协议有哪些致命漏洞?攻击者如何组合攻击?怎么修?”
攻击链推演(第十一章知识串联)
第一步:借(闪电贷)
· 攻击者通过闪电贷借出巨额资金(零抵押、同一笔交易内还)
第二步:操纵(价格操纵)
· 把巨款砸进 DEX 池子,瞬间抬高抵押品现货价格
第三步:套利(触发漏洞)
· 协议一看"抵押品现在值很多钱",允许超额借款
· 攻击者借走远超真实价值的资金
第四步:收割(余额分配漏洞)
· 协议按"瞬时余额"发奖励,攻击者用闪电贷临时撑大余额,领走大部分奖励
第五步:还贷离场
· 反向交易恢复价格,还掉闪电贷,净赚离场
完整修复(对应两个根因)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 修复后的协议(关键两点:价格用 TWAP + 奖励按时间累积)
contract FixedLending {
// 修复一:价格用时间加权平均(TWAP),不用现货价
uint256 public lastPrice;
uint256 public lastUpdateTime;
function getTWAP() public view returns (uint256) {
// 简化示意:取过去一段时间的平均价,而非瞬时价
return oracle.getTimeWeightedPrice(30 minutes);
}
// 修复二:奖励按时间累积记账,不用瞬时余额差
mapping(address => uint256) public staked;
mapping(address => uint256) public rewardDebt;
uint256 public accRewardPerToken;
function claimReward() public {
uint256 earned = staked[msg.sender] * accRewardPerToken - rewardDebt[msg.sender];
rewardDebt[msg.sender] = staked[msg.sender] * accRewardPerToken;
if (earned > 0) payable(msg.sender).transfer(earned);
}
}
面试答题框架
1. 定性:两个致命漏洞——"现货价定价"(可被单笔交易操纵)+ "瞬时余额分配"(可被闪电贷撑大)
2. 攻击链:闪电贷 → 操纵价格 → 超额借款 → 领走奖励 → 还贷离场
3. 修复:价格用 TWAP/预言机 + 奖励按时间累积 + 关键操作加冷却期
4. 升华:可组合 + 资金可瞬时流动的世界里,"局部正确 ≠ 全局安全"
★ 加分点:点出“闪电贷本身不是攻击,是放大器”——修好价格和余额逻辑才是根本, “禁闪电贷”既做不到也没意义。
13.5 综合实战题五:一次数据泄露事件的应急响应与合规处置
场景
某天安全监控告警:数据库出现异常大量查询,疑似拖库。初步判断泄露了约 20 万用户的 姓名、手机号、部分身份证号。面试官问:“作为安全负责人,你从第一分钟开始怎么做?”
处置时间线(技术应急 + 合规义务双线并行)
┌─ 技术线(第八章 应急响应)─────────────────────────────────────────┐
│ 0~15 分钟:止血(遏制) │
│ · 封堵拖库入口(临时下线可疑接口 / 隔离服务器) │
│ · 修改/禁用泄露的数据库凭据,限制异常来源 IP │
│ · 保留现场:拉取日志、数据库慢查询、网络流量(证据保全) │
│ │
│ 15 分钟~2 小时:定位 + 定范围 │
│ · 确认攻击入口(SQL 注入?越权?凭据泄露?) │
│ · 确认泄露了哪些字段、多少人、是否含敏感个人信息 │
│ │
│ 2 小时~:根除 + 恢复 + 复盘 │
│ · 修复漏洞、清理后门、恢复服务 │
│ · 写复盘报告,落实整改 │
└─────────────────────────────────────────────────────────────────────┘
┌─ 合规线(第十二章 个保法义务)──────────────────────────────────────┐
│ 立即:采取补救措施,阻止泄露扩大 │
│ 及时:通知【受影响的个人】(告知泄露了什么、可能后果、已采取措施) │
│ 报告:按规定向【主管部门】报告(重大泄露有报告义务) │
│ 留痕:全程记录时间线、处置过程,作为合规证据 │
└─────────────────────────────────────────────────────────────────────┘
关键知识点串联(第八、十二章)
1. 应急响应六阶段(8.9):准备→检测→遏制→根除→恢复→复盘
2. 证据保全(8.1):日志、流量、快照,保证可追溯
3. 个保法泄露义务(12.2):立即补救 + 通知个人 + 报告主管部门
4. 敏感信息(12.2):身份证号属于敏感个人信息,泄露后果更重,处置要求更严
面试答题框架
1. 先亮"双线并行":技术线(止血→定位→根除→复盘)+ 合规线(补救→通知→报告→留痕)
2. 技术线按时间轴展开,强调"先止血再查因"
3. 合规线强调"通知个人 + 报告主管部门"是法定义务,不能隐瞒
4. 加分:身份证号是敏感个人信息,要评估是否触发"重大泄露"的更高报告要求
★ 加分点:很多人只会答“技术应急”,漏了“合规义务”。能同时答出“通知个人 + 报告主管部门”, 说明你懂“安全”和“合规”是一体两面,这正是高级岗位要的。
13.6 综合实战题六:从零设计一个“安全 + 合规”双达标的新系统
场景
公司要做一个面向 C 端用户的新 App(收集手机号、身份证用于实名认证,数据可能跨境, 部署在云上,K8s + 微服务)。面试官问:“作为安全负责人,你从设计阶段开始,怎么把它建成一个 既安全又合规的系统?”
设计框架(安全 + 合规双线,贯穿全书)
第一层:架构设计阶段(先想清楚,再写代码)
· 数据最小化:实名认证只收"手机号 + 身份证号"必需字段,不多收
· 敏感信息:身份证号加密存储(SM4/AES)+ 脱敏展示 + 单独同意
· 数据出境:确认是否跨境,若是,提前走合规路径(评估/标准合同/认证)
· 云架构:IAM 最小权限、对象存储默认私有、IMDSv2
第二层:开发阶段(把安全写进代码)
· 输入校验 + 参数化查询(防注入)
· 对象级授权(防越权)
· 密钥不硬编码,用密钥管理服务(KMS/密钥管理)
· 依赖锁版本 + SCA 扫描(防供应链投毒)
第三层:部署阶段(云原生安全)
· K8s:RBAC 最小权限、NetworkPolicy 默认 deny、Secret 用 External Secrets
· 准入控制(PSA/Kyverno)+ 容器镜像扫描 + 非 root 运行
· IaC 安全检查(Checkov)进 CI
第四层:运行阶段(检测 + 响应)
· 云审计日志(CloudTrail)+ 数据事件 + 告警
· 运行时检测(Falco)+ 日志进 SIEM
· 应急预案 + 数据泄露处置流程
第五层:合规闭环(等保 + 密评 + 个保法)
· 定级备案(等保三级大概率要做)
· 关键环节用国密算法,准备密评
· DPIA(处理敏感个人信息必做)
· 隐私政策 + 单独同意 + 用户权利(删除/导出/撤回)落地
关键知识点串联(全书覆盖)
| 设计层 | 用到的章节 |
|---|---|
| 敏感信息 + 最小必要 + 出境 | 第十二章 |
| 注入/越权/会话 | 第一~五章 |
| 供应链 | 第九章 |
| 云 IAM + K8s + IaC | 第十章 |
| 应急响应 | 第八章 |
面试答题框架
1. 先给"五层框架":架构 → 开发 → 部署 → 运行 → 合规闭环
2. 每层点 2~3 个最关键的落地动作,别堆砌
3. 强调"安全 + 合规双线并行",敏感信息(身份证)贯穿始终
4. 收尾:安全设计要前置,等上线了再补,成本翻十倍
★ 加分点:能把“实名认证收身份证”这种具体业务,落到“加密存储 + 脱敏展示 + 单独同意 + DPIA”, 说明你不是背概念,而是真能把合规翻译成工程落地。这是这道题想考察的核心能力。
13.7 第十三章小结
13.7.1 六道题的共同框架
六道题场景各不相同,但底层是同一个分析框架,值得反复用:
识别风险 → 推演攻击 → 分层防御 → 落地检查
1. 识别风险:这个系统/功能,最可能被怎么打?(定性)
2. 推演攻击:攻击者具体会怎么一步步走?(攻击链)
3. 分层防御:每一环用什么措施挡?(对应全书章节)
4. 落地检查:这些措施怎么落到代码/配置/流程?(可执行)
13.7.2 六道题的知识点地图
| 题 | 场景 | 串联的章节 |
|---|---|---|
| 13.1 | 电商全链路攻防 | 一~六、九章 |
| 13.2 | SSRF 云上横向 | 二、十章 |
| 13.3 | 供应链投毒溯源 | 八、九章 |
| 13.4 | DeFi 闪电贷+价格操纵 | 十一章 |
| 13.5 | 数据泄露应急+合规 | 八、十二章 |
| 13.6 | 安全+合规新系统设计 | 全书 |
下一章(第十四章)是全书收尾:把 12 个章节、几百道面试题做一次全量索引 + 高频 TOP50 + 答题方法论, 帮你从“会做题”升级到“会应对任何题”。
第十四章:全书总汇——356 题总索引与答题方法论
本章定位:这是全书收尾。前面十二章已经产出了 356 道面试题(A~L 组)。 这一章做三件事:① 给你一张全量索引,方便检索;② 提炼 50 道最高频题; ③ 给你一套“应对任何题”的答题方法论 + 自测评分表。
14.1 全书面试题总索引(A ~ L 组,共 356 题)
| 组 | 章节 | 主题 | 题数 | 核心考点 |
|---|---|---|---|---|
| A | 第一章 | AI / LLM 应用安全 | 28 | Prompt 注入、模型数据泄露、RAG 投毒、越狱 |
| B | 第二章 | API 安全 | 30 | 对象级/功能级越权、认证缺失、速率限制 |
| C | 第三章 | GraphQL 与 gRPC 安全 | 30 | 深度查询 DoS、内省泄露、gRPC 元数据 |
| D | 第四章 | 移动 App 与小程序 | 28 | 反编译、脱壳、证书校验、越权 |
| E | 第五章 | 实时通信与 IoT | 30 | WebSocket 劫持、MQTT 未授权、协议漏洞 |
| F | 第六章 | 主机与操作系统安全 | 30 | 提权、持久化、SUID、内核漏洞 |
| G | 第七章 | 内网横向与域渗透 | 30 | Kerberoast、Pass-the-Hash、黄金票据 |
| H | 第八章 | 数字取证与应急响应 | 30 | 证据链、时间线、遏制、复盘 |
| I | 第九章 | 软件供应链安全 | 30 | 依赖投毒、SBOM、CI/CD、供应链溯源 |
| J | 第十章 | 云原生与 Serverless | 30 | IAM、IMDS、K8s、容器逃逸、IaC |
| K | 第十一章 | Web3 与智能合约 | 30 | 重入、溢出、预言机、闪电贷、MEV |
| L | 第十二章 | 数据合规与隐私 | 30 | 个保法、GDPR、分类分级、数据出境、等保 |
★ 检索技巧:题目都是“组 + 序号”编号(如 J24、K13),在文档里 Ctrl+F 搜编号即可直达。 全书题目都遵循统一结构:定义 → 生活类比 → 原理 → 代码 → 加分点。
14.2 高频 TOP50(跨章节精选)
面试时间有限,如果你只能复习一部分,优先吃透这 50 道。按主题归类,标注难度。
14.2.1 应用层(A~E 组,20 题)
| # | 题目 | 难度 | 一句话答案锚点 |
|---|---|---|---|
| 1 | Prompt 注入攻击是什么?怎么防? | ★★☆ | 把用户输入当“指令”而非“数据”,输入输出隔离 + 权限最小化 |
| 2 | RAG 检索增强有什么安全风险? | ★★☆ | 知识库投毒 → 检索到毒 → 生成被污染 |
| 3 | 对象级越权(BOLA)是什么? | ★★★ | 每个对象都校验“当前用户是否拥有”,不能只验登录 |
| 4 | 功能级越权(BFLA)是什么? | ★★☆ | 每个接口校验角色/权限,不能只靠前端隐藏按钮 |
| 5 | API 速率限制缺失有什么危害? | ★☆☆ | 撞库、刷接口、DDoS、薅羊毛 |
| 6 | GraphQL 深度查询 DoS 怎么防? | ★★☆ | 查询深度限制 + 复杂度预算 + 超时 |
| 7 | GraphQL 内省(Introspection)泄露风险? | ★★☆ | 生产环境关闭内省,否则泄露 schema |
| 8 | 移动 App 反编译能拿到什么? | ★★☆ | 硬编码密钥、接口地址、逻辑,配合加固/混淆 |
| 9 | 移动 App 证书校验绕过怎么防? | ★★☆ | SSL Pinning + 双向校验 |
| 10 | WebSocket 劫持与 CSWSH 怎么防? | ★★☆ | Origin 校验 + 鉴权 token + 心跳 |
| 11 | MQTT 未授权访问的危害? | ★★☆ | 订阅敏感主题、伪造消息,需账号密码 + ACL + TLS |
| 12 | XSS 三种类型及防御? | ★★☆ | 存储/反射/DOM,输出编码 + CSP + HttpOnly |
| 13 | CSRF 原理与防御? | ★★☆ | 浏览器自动带 Cookie,用 Token/SameSite/校验 Referer |
| 14 | SQL 注入原理与防御? | ★★☆ | 拼接 SQL,用预编译参数化 + 最小权限 |
| 15 | SSRF 原理与防御? | ★★☆ | 服务端代发请求,白名单 + 禁内网 + 二次解析 |
| 16 | 越权 vs 未授权访问的区别? | ★☆☆ | 越权=有账号但越权访问;未授权=没账号也能访问 |
| 17 | JWT 常见安全坑? | ★★☆ | 弱签名、alg=none、密钥泄露、不设过期 |
| 18 | 会话固定攻击怎么防? | ★★☆ | 登录后重新生成 sessionId |
| 19 | 密码存储的正确姿势? | ★★☆ | bcrypt/argon2 加盐慢哈希,绝不明文/可逆 |
| 20 | 文件上传漏洞怎么防? | ★★☆ | 类型白名单 + 重命名 + 存隔离 + 不解析 |
14.2.2 主机与内网(F~H 组,12 题)
| # | 题目 | 难度 | 一句话答案锚点 |
|---|---|---|---|
| 21 | Linux 常见提权手法? | ★★☆ | SUID、sudo 配置错、内核漏洞、计划任务、PATH 劫持 |
| 22 | SUID 提权原理? | ★★☆ | 以文件属主权限运行,找 root 属主 SUID 可滥用 |
| 23 | 持久化常见手法? | ★★☆ | 计划任务、SSH 公钥、启动项、内核模块 |
| 24 | Pass-the-Hash 原理? | ★★★ | 用 NTLM Hash 直接认证,无需明文密码 |
| 25 | Kerberoasting 攻击? | ★★★ | 请求服务票据离线爆破,弱口令可解 |
| 26 | 黄金票据 vs 白银票据? | ★★★ | 黄金=伪造 TGT(任意权限);白银=伪造服务票据(限服务) |
| 27 | 横向移动常用手法? | ★★☆ | PsExec、WMI、SMB、Pass-the-Hash |
| 28 | 应急响应六阶段? | ★★☆ | 准备→检测→遏制→根除→恢复→复盘 |
| 29 | 取证第一原则? | ★★☆ | 易失性优先(内存→网络→进程→磁盘) |
| 30 | 证据链(Chain of Custody)是什么? | ★★☆ | 证据从采集到庭审全程可追溯、未被篡改 |
| 31 | 内网横向最常用的探测命令? | ★☆☆ | 找域控、找共享、找凭据、找可达主机 |
| 32 | 黄金票据的防御? | ★★☆ | 定期改 krbtgt 密码两次、监控异常票据 |
14.2.3 供应链 / 云原生 / 新兴(I~K 组,12 题)
| # | 题目 | 难度 | 一句话答案锚点 |
|---|---|---|---|
| 33 | 依赖混淆攻击? | ★★★ | 私包名撞公有源,公有源同名包被拉取 |
| 34 | SBOM 是什么? | ★★☆ | 软件物料清单,SPDX/CycloneDX,列出所有依赖 |
| 35 | CI/CD 安全风险? | ★★☆ | 密钥泄露、脚本注入、Runner 污染 |
| 36 | 云责任共担模型? | ★★☆ | 云管底层,你管云上配置 |
| 37 | IAM 最小权限怎么落地? | ★★☆ | 按需授予、定期审查、权限边界兜底 |
| 38 | IMDS / SSRF 攻击链? | ★★★ | SSRF → 169.254.169.254 → 偷角色密钥 |
| 39 | 混乱代理人(Confused Deputy)? | ★★★ | 用 ExternalId + 精确信任策略 |
| 40 | K8s RBAC 最小权限? | ★★☆ | 按命名空间/资源/动词最小化,禁通配符 |
| 41 | 容器逃逸手法? | ★★★ | 特权容器、docker.sock、内核漏洞 |
| 42 | K8s Secret 为什么只是 base64? | ★★☆ | base64 不是加密,需 etcd 加密 + External Secrets |
| 43 | 重入攻击? | ★★★ | 先转账后记账,用 CEI + ReentrancyGuard |
| 44 | 整数溢出/下溢? | ★★☆ | 数字绕圈,0.8.0 自动检查 / SafeMath |
| 45 | 预言机价格操纵? | ★★★ | 现货价可被操纵,用 TWAP/Chainlink |
| 46 | 闪电贷攻击? | ★★★ | 借巨款放大漏洞,防价格/余额逻辑漏洞 |
| 47 | 三明治攻击? | ★★★ | 前买后卖夹用户,滑点保护 + 私有交易 |
| 48 | IaC 安全风险? | ★★☆ | 硬编码密钥、tfstate 明文、漂移 |
14.2.4 合规(L 组,2 题)
| # | 题目 | 难度 | 一句话答案锚点 |
|---|---|---|---|
| 49 | 个保法核心原则? | ★★☆ | 告知-同意 + 最小必要 + 用户权利 + 单独同意 |
| 50 | 数据出境三条路径? | ★★☆ | 安全评估 / 标准合同 / 保护认证 |
★ 使用建议:先自测这 50 题,能流利答出 40 题以上,说明你已经建立起完整的安全知识骨架; 剩下的 300 多题是“深化 + 覆盖边缘场景”,按目标岗位的侧重点挑着补即可。
14.3 答题方法论:如何应对任何安全面试题
14.3.1 通用五步答题法
面试题千变万化,但都能套用这个五步框架。这套框架贯穿全书每一道题:
第一步:先给一句话定义(定性)
"这是一个 XX 攻击/机制,本质是……"
先让面试官知道"你懂这是什么",为后面铺路。
第二步:给一个生活类比(让人秒懂)
"打个比方,就像……"
类比的目的是证明你"真理解"了,而不是死记硬背。
第三步:讲原理/流程(show 深度)
攻击链怎么走?关键机制是什么?核心参数是什么?
这是区分"背过"和"真懂"的分水岭。
第四步:给代码/配置(show 落地)
能写一段关键代码、一条命令、一个配置,瞬间拉开差距。
第五步:加分点(show 认知)
补一个"局限/坑/升华"——"但这里有个坑……""诚实地讲,它防不住……"
这一句往往决定你是"合格"还是"优秀"。
14.3.2 五种题型的应对侧重
| 题型 | 侧重 | 示例 |
|---|---|---|
| 概念题 | 定义 + 类比 + 一句话危害 | “什么是重入攻击?” |
| 原理题 | 流程/时序 + 关键机制 | “SSRF 怎么打到元数据服务?” |
| 场景题 | 定性 → 推演 → 分层防御 → 优先级 | “这个系统怎么防?” |
| 手写题 | 关键代码 + 为什么这样写 | “写一个安全的 withdraw” |
| 开放题 | 框架 + 取舍 + 诚实局限 | “如何建设安全体系?” |
14.3.3 三条加分话术(贯穿全书)
话术一:诚实说明局限(最加分,没有之一)
"IMDSv2 不能 100% 防 SSRF……" / "Falco 只能检测不能阻断……"
/ "脱敏不等于匿名化……" / "等保是底线不是攻不破……"
★ 面试官最反感"什么都懂、什么都绝对",最欣赏"懂边界"。
话术二:给出优先级和取舍
"不是所有防御一起上,而是按'被攻击概率 × 损失'排序,先堵拖库、越权、支付篡改这三件……"
★ 体现工程思维,而非堆砌工具清单。
话术三:把概念翻译成工程落地
"最小必要 → 接口字段分级" / "删除权 → 全链路删除闭环"
/ "单独同意 → 敏感字段独立勾选 + 同意留痕"
★ 证明你能把抽象要求变成可执行方案。
14.4 自测评分表(评估你的安全水平)
按“能答对多少题 + 答到什么深度”给自己打分:
| 级别 | 表现 | 说明 |
|---|---|---|
| L1 入门 | 能说出名词定义,但说不出原理 | 概念题 60% 能答,原理题卡壳 |
| L2 熟悉 | 定义 + 原理 + 能举例 | 高频题能流利答,代码题勉强 |
| L3 熟练 | 能写关键代码 + 讲攻击链 | 手写题、场景题能拿下 |
| L4 精通 | 能讲局限 + 给优先级 + 落地 | 开放题能系统性作答,有取舍判断 |
自测方法:随机抽 TOP50 里的 10 题,用“五步答题法”完整作答并录音/录像。 10 题里能流利答出 8 题(含加分点),你就处于 L3 水平,可以应对绝大多数安全岗位面试。
14.5 连环追问链模板(模拟面试官)
面试官常常从一道题“往下追问”,检验你是不是真懂。下面给三条高频追问链:
追问链一(SSRF):
Q1 什么是 SSRF? → Q2 它和普通 SSRF 在云上有什么不同?
→ Q3 怎么打到 169.254.169.254? → Q4 IMDSv2 能完全防住吗?
→ Q5 那 DNS rebinding 怎么绕过?怎么防?
追问链二(重入攻击):
Q1 什么是重入? → Q2 根因是什么? → Q3 CEI 三个字母?
→ Q4 只用 ReentrancyGuard 够吗? → Q5 只读重入是什么?
追问链三(数据合规):
Q1 个保法核心原则? → Q2 敏感个人信息有哪些?
→ Q3 数据出境怎么合规? → Q4 触发安全评估的量级?
→ Q5 数据泄露了要做什么?
★ 使用建议:把每条追问链的“最后一问”当成重点——那才是区分度所在。 能答到“最后两问”的人,才真正掌握了这个主题。
14.6 全书总结与学习路线
14.6.1 全书脉络一句话回顾
全书 12 章 + 1 章实战,是一条"从应用层到基础设施、再到新兴与合规"的完整攻击面地图:
应用层(一~五章)→ 主机内网(六~七章)→ 出事后(八章)→
供应链(九章)→ 云原生(十章)→ Web3(十一章)→ 合规(十二章)→ 综合实战(十三章)
14.6.2 全书反复出现的“四个基本功”
无论哪一章,最终都回到这四个不变的基本功:
1. 最小权限 —— 每个身份、每个账号、每个角色,只给"刚好够用"的权限
2. 状态一致 / 先改后调 —— 先改状态再外部调用(CEI),先扣账再转账
3. 审计与留痕 —— 一切关键操作可追溯,出事后能还原时间线
4. 纵深防御 —— 不依赖单一防线,层层设卡,一处失守还有下一处
14.6.3 建议学习路线(按目标岗位)
通用安全工程师:一~五章(应用层)→ 六~七章(主机内网)→ 八章(应急)→ 高频 TOP50
云安全工程师:一~二章(基础)→ 九章(供应链)→ 十章(云原生,重点)→ 十二章(合规)
安全研发/架构:一~五章(应用层)→ 九章(供应链)→ 十二章(合规)→ 十三章(综合)
区块链安全:十一章(Web3,重点)→ 二章(API)→ 十三章(综合实战)
★ 最后一句话:安全知识的价值不在“记住多少攻击手法”,而在“能不能在任何新场景下, 快速识别风险、推演攻击、给出分层防御、并诚实地说出它的边界”。 这套分析框架,才是本书真正想交给你的东西。
14.6.4 全书完
感谢你读到这里。356 道题、12 个专题、6 道综合实战,加上开篇的名词速查, 构成了这份《新兴攻击面与专项安全-实战专题》。 建议配合同目录的《00-名词速查手册.md》交叉查阅——遇到看不懂的术语,Ctrl+F 回手册查白话解释。 祝你面试顺利,把安全思维带进每一个你写的系统里。