资讯动态

时间攻击原理与Web侧信道攻击实战防御指南

发布时间:2026/10/21 15:42:21 来源:尧图企业网站定制
1. 内容整体设计与思路拆解1.1 什么是时间攻击与侧信道攻击先说结论时间攻击Timing Attack是侧信道攻击Side-Channel Attack中落地成本最低、复现门槛最友好的一大分支。我在安全测试中试过不少攻击方式如果要给刚接触Web安全的朋友推荐一个研究切入点时间攻击绝对值得优先看。侧信道攻击这个概念本质上是在利用“实现层面的物理或逻辑泄漏”来获取信息。常规攻击思路是直接打功能的逻辑漏洞比如SQL注入、越权访问、文件上传绕过这些都是在攻击系统“本身想让你看到的部分”。侧信道不一样它盯的是系统在运行过程中“不经意暴露”的信息处理时间长短、功耗波动、电磁辐射、缓存命中的差异、错误提示的用词区别……最要命的是这些信息往往和敏感数据直接或间接相关。放到Web场景里最容易复现的就是时间侧信道。Web应用跑在服务器上它处理不同输入时耗时往往不同——比如密码比对时逐字符比较、API Key校验时不一致就立即返回、数据库查询时数据量大就多查一会儿。攻击者只要把网络抖动控制住、取样次数堆够用统计学方法对比两组响应时间的差异就能一点一点推断出本不应该知道的秘密。1.2 为什么Web场景特别容易滋生时间侧信道问题这要怪Web应用对性能的极度敏感。开发者为了快普遍采用“提前返回”的优化逻辑校验不通过就马上结束绝不浪费时间。密码校验通常是这个伪代码def check_password(user_input, stored_password): for i in range(len(stored_password)): if user_input[i] ! stored_password[i]: return False return True这个逻辑在测试时速度极快性能上没有任何问题。但放到安全视角这就是一个教科书级的侧信道漏洞第一个字符只要不对函数立刻返回第一个字符对了它就会继续比第二个字符。攻击者不需要知道完整密码只要逐个字符试就能把一次暴力破解从“天文数字级别的组合”降维成“双层循环量级”。加上Web应用普遍依赖网络请求-响应模型攻击者可以轻松、批量地发请求并记录响应时间。虽然网络延迟是一条很脏的噪声通道但只要样本量足够大、统计方法得当信号依然能刺穿噪声浮出水面。这也是我为什么说时间攻击是Web侧信道里最“便宜”的——你只需要一个正常的HTTP客户端不需要示波器、探头、物理接触纯属远程就能完成。1.3 这个内容适合谁读这篇文章不是纯理论宣讲而是把完整思路、测试方法、踩坑记录和防御手段串在一起。适合三类人Web开发者你大概率在无意中写过上面的逐字符比较代码看完这篇文章能意识到“快”并不总是优点。安全测试工程师这里给出时间攻击的实操路径、统计模型和网络噪声处理方法可以充实你的测试工具箱。对Web安全感兴趣但没入门的同学时间攻击的门槛很低不需要你精通密码学只需要理解基本的概率统计和HTTP协议就能复现经典案例。下面我从原理拆解、测试环境搭建、完整攻击复现、问题排查到防御方案一层层把知识剥开。特别是对时间攻击来说大多数资料只讲理论模型很少讲实际操作时会遇到什么坑这一篇会把那些坑也都趟一遍。2. 核心细节解析与实操要点2.1 时间攻击的两个前置条件在我开始任何一次时间攻击测试之前都会先确认两个条件是否成立可观测的时间差异和足够的采样能力。可观测的时间差异目标系统必须存在至少一条执行路径其耗时差异能体现内部数据的内容。拿密码比较来说如果框架底层用了安全的恒定时间比较函数constant-time comparison那攻击者就很难从时间上获取信息。反之如果用了上面那种逐字符比较那就是明摆着送弹药。足够的采样能力Web场景下时间攻击需要大量请求样本。一个字符的差异可能是微秒或毫秒级别但加上网络RTT抖动单次请求根本看不出区别。只有采集几百上千条记录用均值、中位数来做统计假设检验才能稳定地区分“这个字符猜对了”和“猜错了”。我见过不少新手在本地写了个测试脚本发现每次请求时间差异很大就以为攻击无效直接放弃。这其实是忽略了“采样量”这个变量。把采样量从10次提到1000次之后差异的稳定性会完全不一样。这是一个用时间换信噪比的过程。2.2 常见的Web时间侧信道场景时间侧信道在Web里绝不是只有一个密码比较场景。认真梳理一下至少有这么几类场景一密码与秘密校验。这是最经典的逐字符比较导致的信息泄漏。凡是手写了字符串比较逻辑的地方都存在这种风险。很多老系统用的还是这种模式。场景二用户名校验。有些系统在用户不存在和密码错误时返回不同文案或者响应时间不同。比如先查用户表用户不存在就立刻返回“用户不存在”存在才去查密码哈希并执行比较。这两条路径的耗时差异非常明显攻击者可以直接确认某个用户名是否存在为后续定向攻击奠定基础。场景三API令牌与签名验证。这个场景更隐蔽。很多开放平台校验调用方签名时用strcmp、这类操作符直接比较。如果攻击者能拿到一个合法请求就可以逐字节猜测签名参数。这比爆破密码的威胁更大因为API令牌直接关联到用户的敏感操作权限。场景四缓存命中与未命中。这个稍微偏旁路一点如果系统对某些可预测的资源路径做了缓存那么首次访问和二次访问的响应时间会有明显差异。攻击者可以通过时间差判断某个资源是否已被缓存过间接推断系统内的访问行为记录。场景五JSON序列化或数据处理量的差异。例如系统根据查询结果的条数决定是否给响应体做分页或压缩条数多时耗时长攻击者能通过时间差推测SQL命中到了哪一批数据相当于从侧面证实了某些数据存在。2.3 恒定时间比较函数攻击者的对头在继续讲攻击手法之前必须先认识一下防御侧的“天敌”——恒定时间比较函数。它们的设计目标就是让不同输入的处理耗时尽可能一致把侧信道通道打掉一个。Python的hmac.compare_digest、Go的crypto/subtle.ConstantTimeCompare、Java的MessageDigest.isEqual都是典型实现。它们通过对所有字符做异或合并结果再把结果映射到统一的延时上从根本上去掉了“提前返回”这个信号。但这里不要产生一个误解用了恒定时间比较不代表万事大吉。如果系统在比较之前对不同输入走了不同的逻辑分支——比如先判断用户是否存在再决定是否比较密码——那么分支间的耗时差异依然是侧信道。恒定时间只保护了“比较”这个环节防不住上下游的旁路。2.4 时间攻击的统计模型基础我刚开始做时间攻击的时候觉得拿到一堆响应时间数据然后看平均值就行。后来实操多了才发现光看均值是很粗糙的做法。因为网络延迟的分布是重尾的少数极端值会把均值拉偏中位数在对抗这种离群点时更稳健但如果目标时间差本身不明显中位数也可能不敏感。比较稳妥的做法是结合两种工具均值差异检验和Mann-Whitney U检验。均值差异检验好理解对猜测字符A的N次请求取均值对猜测字符B的N次请求取均值两者差值如果显著大于网络噪声的波动范围说明A可能命中正确分支。Mann-Whitney U检验则是不要求数据满足正态分布的非参数检验它对离群值的抵抗力更强。我常用的做法是每个猜测值采集50到100个样本先做一次Q-Q图大概看分布再用U检验计算P值。P值小于0.05时才认为两个猜测值之间的耗时差异有统计学意义。有一段我早期写的统计代码片段Python版可以作为参考from scipy.stats import mannwhitneyu def compare_timing(sample_a, sample_b): # sample_a / sample_b 是两次不同猜测的耗时列表 stat, p_value mannwhitneyu(sample_a, sample_b, alternativetwo-sided) return stat, p_value # 实际使用时p_value 0.05 才认为差异显著要注意的是P值只是辅助工具不是绝对判据。在真实网络中P值结果偶尔会有误差所以我都会配合“重复实验”的流程两天之内跑三遍如果结论一致才采信。3. 实操过程与核心环节实现3.1 搭建本地靶场环境纸上谈兵没有说服力。我建议你在自己的机器上搭建一个可控的靶场环境把时间攻击完整跑一遍。这里不需要复杂的云环境本地足够。环境清单如下Python 3.9测试脚本和靶场服务共用Flask框架用于搭建模拟API一个纯Python编写的密码校验函数故意做逐字符比较方便观察侧信道模拟目标服务的关键代码如下from flask import Flask, request, jsonify import time app Flask(__name__) # 模拟一个预设的API Key实际场景中它属于某个权限较高的用户 SECRET_KEY ALICE-PRIVATE-API-KEY-2024 def insecure_equals(input_key, secret_key): 极度不安全的字符串比较逐字符比较一旦找到不同就立即返回 for i in range(len(secret_key)): if input_key[i] ! secret_key[i]: return False return True app.route(/api/validate) def validate(): input_key request.args.get(key, ) start_time time.perf_counter() result insecure_equals(input_key, SECRET_KEY) end_time time.perf_counter() # 故意把耗时差距如实体现在响应中方便观察真实攻击时不需要这一步 elapsed_us (end_time - start_time) * 1_000_000 return jsonify({result: result, elapsed_us: elapsed_us})在这个靶场里我加了elapsed_us字段返回真实耗时。为什么要这样因为我要先清楚地看到信号本身确认“这个靶场确实存在侧信道”再去思考“如果字段不返回怎么通过纯网络时间做攻击”。这一步对建立直觉极其重要。运行这个服务后直接用两个请求做初步验证curl http://localhost:5000/api/validate?keyAAAA curl http://localhost:5000/api/validate?keyALIC前一个请求在第一个字符就失配后一个匹配了四个字符才失败。不出意外的话后者的耗时明显更高。这一步就证明了侧信道存在。3.2 字符逐位猜测的完整过程确认侧信道存在后进入真正的攻击环节。这里我假设攻击者看不到elapsed_us字段只能测量HTTP请求的总返回到响应体的时间。这是更贴近现实的条件。攻击思路很简单已知密钥是一串可打印字符从第0位开始猜。对每个候选字符发送N次请求并测量响应时间我建议从100次起步。统计每个候选字符的耗时中位数。耗时最大的那个字符大概率就是正确字符。固定这个字符继续猜下一位。写自动化脚本时一个关键点是要让所有请求保持相同的参数和URL结构只改变猜测的字符值。这样可以尽量控制住服务端逻辑的额外耗时差异。下面是我在实际复现时用过的脚本核心逻辑import requests import statistics import string TARGET_URL http://localhost:5000/api/validate def measure_time(char_guess, prefix): times [] # 构造完整的猜测key未猜到的部分用填充字符 guess_key prefix char_guess A * 20 for _ in range(100): resp requests.get(TARGET_URL, params{key: guess_key}) # 记录从发出请求到收到响应的完整耗时 times.append(resp.elapsed.total_seconds()) return statistics.median(times) candidates string.ascii_uppercase string.digits string.punctuation recovered for pos in range(len(ALICE-PRIVATE-API-KEY-2024)): best_char None best_time -1 for c in candidates: elapsed measure_time(c, recovered) if elapsed best_time: best_time elapsed best_char c recovered best_char print(fPosition {pos}: best {best_char}, time {best_time:.6f}s)这个脚本跑起来后第一次很兴奋地看到它真的能逐位还原密钥。但这里我要特别提醒一个新手容易踩的坑脚本没有控制网络请求的发送间隔和连接复用。如果每次都新建TCP连接三次握手的时间会淹没微小的比较差异。我在测试中发现开启requests.Session()复用连接后信噪比提升非常明显。后来我的代码里会加类似这样的结构session requests.Session() session.keep_alive True adapter requests.adapters.HTTPAdapter(pool_connections1, pool_maxsize1) session.mount(http://, adapter)只维护一个TCP连接每次请求吃完就返回连接池减少交互相位的影响。这是我做了很多次试验后总结出来的单靠直觉想不到。3.3 从靶场到真实环境的偏差修正本地靶场跑通之后很多人直接把它搬到公网目标上结果发现完全失效。这太正常了因为公网环境里的噪声源远不止服务端比较函数公网RTT本身就是几十毫秒级而字符比较差异可能只有几微秒。路由器的排队延迟、拥塞控制、服务器并发调度都会带来随机抖动。CDN节点可能缓存响应或动态路由导致耗时曲线出现周期性漂移。针对这个难题我的实践做法有三个第一做基线校准。在每个采样周期里同时发送一组“参考请求”它的路径与目标请求完全一致但猜测的字符固定为一个已知错误的字符。用参考请求的耗时曲线做背景噪声基线再把目标请求的耗时减去基线得到“相对耗时的增量”。这样能抵消大部分共享噪声源。第二拉长采样窗口。本地测试100次就够了公网目标我把单字符采样量提到500次甚至更多。用中位数和四分位距IQR代替单纯均值进一步压掉离群点的干扰。第三时间加噪与请求速率控制。不要像脚本里那样一口气发几百个请求容易触发服务器的限流或者被WAF拦截。加一个随机sleep比如0.2到0.5秒之间让请求看起来更像正常流量。3.4 时间攻击之外一层可变异的扩展思路时间攻击如果只停留在“猜字符”它的能力和适用面就太窄了。我在实际项目中通常还会把它扩展到其他场景场景变体一用时间差异判断加密数据长度。有些系统用密码学算法加密用户数据时明文长度不同会导致密文长度不同。攻击者通过请求特定资源——比如下载某个用户文档——测量响应体大小虽然拿不到内容但能确认文档长度范围这本身可能泄露商业机密比如一份合同和一个说明书长度完全不同。场景变体二压缩比侧信道压缩加密的组合。这个思路其实更高级攻击者控制自己输入的明文的一部分系统把该明文和机密数据拼接后一起压缩再加密。如果机密数据与攻击者控制的输入内容存在重复压缩率会上升响应体变小。通过观察响应体大小或时间就能推断机密数据的内容。这在TLS中被叫做“压缩侧信道攻击”著名的CRIME/BREACH攻击就是这个门类。场景变体三缓存时序侧信道。如果目标环境是共享服务器攻击者可以通过反复访问同一个资源观察本次响应是命中缓存快还是回源慢推断其他用户是否访问过该资源。虽然很多时候这只是“是否活跃”的信号但结合业务场景也能拼凑出用户行为画像。这些变体不一定要都写代码实现但建立“时间差、响应大小差都是信息”的意识对后续挖洞很有帮助。4. 常见问题与排查技巧实录4.1 时间差异太微弱统计检验通不过怎么办这是我在做攻击复现中最常遇到的问题。本地靶场还好公网环境里经常出现一个字符的耗时差异只有0.1个毫秒而网络噪声有30毫秒。即使做了基线校准还是通不过显著检验。我的排查顺序是这样的确认服务端确实是逐字符比较先用本地做一次极慢速度的路径验证比如发送长度为1的请求和长度为500的请求如果耗时差异不明显说明比较逻辑不是简单的线性扫描可能真的用了恒定时间比较函数或者比较前有一次整体长度检查。增加单字符采样量从100次提到300到500次中位数和IQR的稳定性会上升。调整测量时间单位如果你用的是毫秒级很可能被取整误差抹平了差异。time.perf_counter()的微秒级精度在靶场够用真实HTTP请求用elapsed.total_seconds()拿到的精确度往往不够建议直接在服务端加X-Timing响应头记录微秒级耗时来做验证这只用于测试自己的靶场。如果还是不行我建议换个场景测。有些目标的侧信道窗口不在“比较”这一步而在“数据库查询”这一步这时候需要测量不同用户ID的查询响应而不是卡在单个字段的猜测上。4.2 服务器挂了触发限流与封禁的规避经验我早期跑攻击脚本时因为没控制速率把一台测试服务器打到限流所有请求都被返回“429 Too Many Requests”。更尴尬的是返回429的耗时极短完全干扰了我的采样数据。后来我彻底改了节奏请求间隔加随机延迟延迟范围控制在0.1到0.5秒。单次攻击会话不超过10分钟跑完一轮休息几分钟。使用合法的User-Agent不要用默认的Python Requests标识。虽然看起来微不足道但很多WAF会直接封禁默认UA。这里有一个安全测试的基本原则所有操作都必须在授权范围内进行。如果你攻击的是自己的靶场、CTF题目或获得授权的测试目标没问题。但如果你对公网第三方目标发起这类探测不管用意如何都是明确的违法行为。请务必在授权范围内做这类型的测试。4.3 测出来的“正确答案”不对故障定位有几次我的脚本逐位猜出来的字符耗时最高的那个其实不是正确字符。复盘后我发现原因出在字符集顺序上候选字符列表明明是string.ascii_uppercase string.digits string.punctuation但正确的密钥里有小写字母和连字符-而我的候选字符集里漏掉了string.ascii_lowercase。更隐蔽的错误是服务端比较逻辑对输入长度做了前置检查。比如密钥长度是固定的如果我的填充字符“A”让猜测key长度超过真实密钥函数可能在入参时就报错返回导致所有候选字符的耗时都一样。这种情况下字符集再全也没用。正确做法是先慢慢扩展填充长度找到“从哪些长度开始耗时变化”锁定真实密钥的长度范围再去猜字符。4.4 常见问题速查表现象原因排查与解决所有候选字符的耗时无统计差异服务端可能使用了恒定时间比较函数或前置了长度检查先测量不同长度输入的耗时差异考虑换一个侧信道场景如缓存、压缩比单个字符耗时波动极大网络噪声或服务器并发调度增加采样量、做基线校准、复用TCP连接、使用中位数而非均值请求被限流或封禁请求速率过快加随机延迟、降低单次采样量、使用正常UA、缩小攻击窗口猜测出的字符序列中间某位错误候选字符集不完整检查字符集是否覆盖大小写、数字、标点确认密钥是否含非打印字符响应时间稳定但信号方向相反可能是分支反逻辑如错误分支走更多逻辑不要盲目选最大耗时两个方向都测一下选择与对照组差异最大的方向公网测试结果与本地完全不一致公网噪声源复杂CDN或者网关代理影响大改用相对时间比较法构造参考请求做差分对比4.5 一个提升信噪比的特殊技巧最后分享一个实测非常有效的技巧使用HTTP/2多路复用同一连接并行发送多个请求。在HTTP/1.1下一个TCP连接同一时间只能处理一个请求队列化等待和头部队头阻塞会引入额外抖动。HTTP/2的多路复用允许在同一个连接上并行发多个请求只要服务端支持测量到的耗时能抹平不少调度噪声。我在自己的靶场测试中用httpx库的AsyncClient开启HTTP/2支持对比HTTP/1.1的测量结果单字符差异的P值稳定度提升了约三成。这个提升不是质变但在信号太微弱时它就是压倒骆驼的最后一根稻草。5. 防御体系建设与最佳实践5.1 开发侧恒定时间比较的正确用法开发阶段的防御是第一道防线。这里给出几种主流语言的推荐做法Pythonimport hmac def safe_equals(input_key, secret_key): return hmac.compare_digest(input_key, secret_key)Goimport crypto/subtle func SafeEquals(input, secret string) bool { return subtle.ConstantTimeCompare([]byte(input), []byte(secret)) 1 }Javaimport java.security.MessageDigest; public static boolean safeEquals(String input, String secret) { return MessageDigest.isEqual( input.getBytes(StandardCharsets.UTF_8), secret.getBytes(StandardCharsets.UTF_8) ); }这些函数的共同点是无论两个字符串在前面多少字符失配最终耗时都相同。它们通过把所有字节的异或结果合并成一个最终值再在恒定时间结束后才返回结果从根本上摧毁了时间侧信道。但要记住恒定时间比较只是解决了“比较”环节不等于整个系统对时间攻击免疫。系统在处理请求路径上的数据库访问、文件读取、缓存操作时依然可能引入时间差。防御时间攻击需要做的是“整体路径”的时长收敛而不只是某个函数的常数化。5.2 设计侧让攻击者拿不到稳定的对比基准光靠代码层面解决问题还不够。我见过很多系统即使用了恒定时间比较函数还是存在侧信道原因在于它们的设计里出现了“分支时序差异”。比如先查用户名是否存在再决定返回什么。根据用户的角色级别拼装不同长度的响应体。根据数据条数决定是否触发缓存。这些逻辑本身不是漏洞但多个分支的耗时差异组合起来就给了攻击者对比基准。从设计上降低风险的方法有以下几种统一错误响应文案与时长。用户不存在、密码错误、脱敏数据异常都返回相同的响应体和相同耗时。最简单粗暴的做法是无论什么错误服务端强制sleep(random_time)把处理时间拉平到一个随机区间。注意这里不能用固定sleep否则攻击者减去固定值后又恢复原形。限制请求速率与单位时间内的认证尝试次数。即使攻击者能做时间测量只要请求被限流到很低的速率完整恢复一个密钥需要的天数会迅速拉长到不可接受。这等于把攻击成本推高了几个数量级。在业务逻辑上避免敏感数据的可预测性。比如用户ID使用高熵的UUID而不是自增数字缓存Key使用不可预测的哈希值这样攻击者没法构造出“需要测试的候选集合”。5.3 运维侧检测和响应如果攻击已经开始运维侧的监控能不能发现异常理想情况下你可以在服务端每隔一段时间统计同一IP对敏感接口的请求耗时分布。正常用户的耗时分布是稳定且离散的而时间攻击者的请求耗时曲线往往会呈现出“阶梯式”特征——因为他在逐步逼近正确前缀正确前缀越长整体耗时就越高。这个规律可以通过耗时分位数的变化识别出来。我建议用类似下面的思路做检测对每个IP单位时间内的请求次数做阈值告警对请求耗时分布的分位数变化做突变检测。两个条件同时触发时大概率是有人在跑时间攻击。更硬核的主动防御还要在Web层面对响应时间做归一化处理。比如接入Web应用防火墙WAF后强制对认证接口的响应时间做整形把所有响应统一到比如200ms这个标准时长。这样攻击者拿到的时间曲线完全平坦任何统计方法都无效。缺点是需要额外硬件性能和响应延迟适合高频认证接口不适合所有接口。5.4 测试侧把时间攻击纳入常规安全审计防御不是上线就结束了而是持续验证的过程。我最推荐的日常做法是把时间攻击加入自动化安全测试用例。在CI/CD流程里增加一个专门的测试任务周期性地对核心认证接口发送一组“不同前缀长度”的请求测量其响应时间分位数。如果某次发布后响应时间的标准差突然变小或者前缀长度对耗时的影响消失说明这次代码改动很可能无意中引入了或修复了侧信道。我在某次项目中通过这种自动化检测发现了一条原本被忽略的时间侧信道某版本的代码为了性能优化提前对API Key的前4位做了索引缓存导致正确8位前缀和错误8位前缀的耗时有30%的差异。如果靠人工审查代码很可能发现不了这种间接引入的问题。5.5 防御不是限制功能而是提升成本最后说一个观点想彻底消灭所有时间侧信道在物理世界里几乎做不到。任何物理实现的计算装置其操作耗时都会有微小差异只是大小问题。真正成熟的防御思路是把攻击者的成本推到足够高高到他自己放弃攻击。比如一个API Key有128位熵你没法让所有比较绝对恒时但如果你把每秒尝试次数限制为10次攻击者要遍历所有可能前缀的时间是以“亿年”为单位的这时候时间侧信道在工程上就不再构成实际威胁。所以在防御设计时不要一味追求代码层面的完美恒时而是把“限制请求频率、提高密钥熵、错误响应随机化、检测与告警”作为一套组合拳来打。防住时间攻击的从来不是某一个单独机制而是整套系统综合后让攻击者望而却步的成本。6. 测试授权、工具链与经验沉淀6.1 一个必须反复强调的前提做任何时间攻击测试都必须有授权。这个授权可以是你自己搭建的靶场和虚拟机。漏洞靶场平台CTF、各类在线靶场中明确允许测试的题目。安全测试服务中签订的授权协议覆盖范围的系统。没有授权就对外部系统发起时间测量与字符猜测攻击从法律角度是违法行为。哪怕你只是“测测看”“这不是渗透只是一些请求”的想法也不能改变行为的性质。请在这个前提下实践。6.2 好用的工具与依赖库清单除了自己写Python脚本我还会备一套工具链方便快速验证requests最基础的HTTP客户端优先用Session模式复用连接。适合原型验证。httpx支持HTTP/2和异步并发采样速度更快适合公网大样本采集。curl单次请求快速排查时很方便加-w %{time_total}就能直接看到总耗时。awk/sed从响应日志或Apache/Nginx访问日志里批量提取耗时字段。scipy.stats做Mann-Whitney U检验和描述性统计。注意它只是统计工具不是攻击工具。jupyter notebook分析采样数据时用它对时间序列做可视化直方图和箱线图能让差异一目了然。写测试代码时我习惯把所有参数集中在一个配置对象里方便切换采样量、延迟区间、目标地址。一个典型配置示例config { base_url: http://localhost:5000/api/validate, sample_size: 200, delay_range: (0.2, 0.5), session: requests.Session(), candidate_charset: string.ascii_letters string.digits -_., }6.3 日志分析也是一种时间侧信道这里额外多说一句时间侧信道不只是主动测量也可以用被动日志分析。如果你拿到了目标系统的访问日志比如通过日志泄露或审计授权可以统计日志中有记时的条目看看同一个认证接口上不同来源IP的耗时分布情况。如果某个IP频繁出现“极短耗时”且“请求量异常大”的特征大概率是自动化脚本在扫描认证接口的响应时间基线或者说有人在预判侧信道条件。不过日志里的时间戳精度通常只有秒级不足以用来精细攻击但足以用来检测。6.4 如果项目要往纵深做还能怎么扩展时间攻击和侧信道是一整个家族。如果这篇文章之后想继续深入研究我建议的方向有Cache侧信道在Web上的实战研究共享缓存服务器下通过缓存命中时间差获取其他用户敏感资源是否存在的信息。虽然技术要求更高但原理与时间攻击相通。差分功耗分析DPA这是物理侧的侧信道分析通常需要接触硬件设备但它的统计思路与时间攻击一致理解好《信号与统计基本》能顺利迁移。自动化检测框架把时间攻击脚本与防御检测脚本结合起来做一个扫描器上线前自动评估Web应用的侧信道风险等级。这个项目如果做成对团队的工程价值很大。说实话每次做这类攻击的复现时最让我警醒的不是“攻击有多容易”而是“形成防御意识有多难”。许多团队在代码审查时关注的是SQL注入、XSS却很少注意到一次高效的比较函数已经泄漏了密钥的影子。好在侧信道安全的常识正在普及越来越多的框架默认提供恒定时间比较函数这也算是一点正面的趋势。如果你照这篇文章把靶场跑了一遍最有价值的收获应该是建立起这样一个直觉凡是“快”和“慢”可以被外部观察到的代码路径都有成为侧信道的可能。带着这个视角去审代码、做测试、看架构很多隐蔽问题会自然浮现出来。这也是时间攻击对Web安全从业者最大的价值。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑