RSA没塌房!一文说清它的结构命门与工程避坑指南
前阵子有位做后端的朋友丢来一个链接标题写着XX秒还原RSA私钥他问我RSA是不是真的塌了要不要赶紧把系统里的算法全换掉。我点开看完之后跟他说这不是RSA被破解这是某个老系统把公钥生成过程玩脱了。真正支撑那次还原的是两把公钥共享了一个素因子攻击者做了一次最大公约数运算就撞开了门。这件事让我越想越觉得RSA这个算法最值得聊的不是能不能破而是它的结构命门到底在哪儿。标题里写但我不能说不是我知道什么独门秘诀而是因为关于RSA的讨论特别容易走极端要么告诉你绝对安全不用管要么吓唬你随时会被破。这两种说法都不诚实。真实情况是RSA的数学结构很干净但它的结构自带几个容易被误用的特征一旦上层实现踩线攻击者就能借力打力。这层东西讲透了你自然明白哪些破解是唬人的哪些风险是需要认真对待的。1. 先说结论RSA 没有塌房但它周围每年都在出洞1.1 为什么三十多年没人给出通用破解方法先回答标题里的问题RSA真的能破吗我的结论是如果讨论的是给出一种方法能从任意公钥出发在可接受时间内还原私钥、解密任意密文那到今天为止公开学术界还没有这样的方法。这个结论并不是某个机构拍脑袋定的而是整个密码学领域这么多年大量研究延续下来的结果。RSA的安全核心落在一个非常古老的数学问题上大整数分解。也就是给你一个大数n你要把它还原成两个素数的乘积。从公钥到私钥最直接的一条路就是分解n。一旦n被分解成p和q后面所有计算都是小学生的乘除运算还原出欧拉函数值再算私钥指数。反过来只要分解不了n攻击者拿着公钥也只能干瞪眼。为什么分解这么难因为目前人类已知最好的通用分解算法在大数面前的复杂度仍然是非多项式的。我常用一个生活化的类比来解释把两堆沙子搅匀变成一堆灰色沙子很容易但给你一堆灰色沙子要你分出哪些颗粒原来属于黑堆、哪些属于白堆难度完全不在一个量级。不过要特别强调目前没有通用破解不等于数学上被证明不可破解。RSA的安全性建立在计算复杂度假设上也就是大家都觉得难而不是推导证明了一定难。这就好比一把锁钥匙孔极其复杂至今没人公开打开过但它理论上并非不存在开锁路径。理解这一层你才能理解后面要说的各种参数陷阱为什么危险。1.2 结构命门到底是什么三个结构性特征很多人以为命门是个暗门、后门其实不是。RSA真正的结构特征写在自己的数学定义里再怎么防御也改变不了关键是看使用方有没有用填充和参数约束去把它管住。我总结三个最值得关注的。第一RSA的模数n被设计成且只能是两个大素数的乘积。这个两素数乘积结构是它所有安全性的来源同时也是它最脆弱的受力点一旦其中一个因子因为随机数错误或其他原因被复用、泄漏整个密钥体系当场瓦解。其他一些算法没有这么干净的结构暴露RSA却把结构直接写在公钥里等于把自己的软肋也亮了出来。第二RSA具有乘法同态性质。这是数学上天然推导出来的两个明文各自加密后再相乘等于两个明文相乘后再加密。这个性质让它可以在某些安全计算场景发光发热但也意味着如果密文没有被填充变换打断攻击者就能对密文做代数操作诱导解密端吐出有价值的信息。经典的选择密文攻击就是顺着这条路走的。第三教科书式的RSA是确定性的同一个明文、同一个公钥加密结果永远一样。这个特性让攻击者可以做选择明文猜测、频率分析甚至建立密文-明文字典。所以现代RSA实现必须引入随机化填充。看到这里你可能会问这不是三把钥匙都递给攻击者了吗别急这三把钥匙都有一道闸门正确的填充方案。OAEP和PSS这类构造本质上就是把干净整齐的数学结构打乱让攻击者无法再借力。所以我说我不能说——准确说是不存在一句能直接破开正确实现的口诀真正的攻击面全在实现细节里。2. 从钥匙开始RSA 的原理和它的数学骨架2.1 一次手算就能懂的密钥生成过程为了把后面的坑讲明白先花两分钟把RSA的骨架过一遍。整个过程可以拆成五步。选两个足够大的随机素数p、q计算np×q这个n就是公钥里的模数计算φ(p−1)×(q−1)选一个与φ互质的加密指数e工程上常用65537算出私钥指数d满足e×d除以φ余1也就是e×d mod φ1。只看数学确实有点干用一个能抄在本子上的小例子验证。取p61、q53那么n3233φ3120。选e17满足17与3120互质。找一个d使17×d mod 31201算出来d2753因为17×27534680146801除以3120商15余1。公钥是(n,e)(3233,17)私钥是d2753。加密一条消息假设m65计算65的17次方后对3233取模结果是2790解密时计算2790的2753次方对3233取模又回到65。这个例子能跑通主要是数很小真实世界里p、q至少好几百位十进制n通常有2048位甚至更多。这也是为什么RSA从来不适合直接加密大段数据大整数模幂运算极慢而且密文和模数等长效率上很不划算。2.2 安全假设为什么正向容易反向难RSA的安全方向性来自一个不对称模幂运算正向很便宜反向却极其昂贵。正向计算比如加密时算65^17 mod 3233用平方-乘的快速算法最多做几十次乘法就能出结果。反向要解决的是给我一个密文c和公钥(n,e)在没有私钥的情况下算出哪个明文m满足m^e mod nc。这个问题叫求解e次根目前公认没有高效算法绕不开对n的分解。很多初学者会把RSA理解成公钥加密、私钥解密就完了其实还有一个隐藏点私钥本身不只是解密钥匙它还能用来做数字签名。签名是把消息的摘要用私钥做一次私有变换任何人用公钥都能验证这个变换是不是私钥持有者做的。签名的安全基础和解密完全一样还是结构命门那套单向性、难以伪造。搞懂这个骨架后面讨论填充和参数才接地气。否则很多人会疑惑既然RSA本身这么难分解为什么新闻里还会有提取私钥的操作答案几乎都出在密钥生成那一步也就是随机性和参数选择。3. 最容易出事的地方不是数学公式而是现场调用3.1 教科书 RSA没填充等于裸奔我接手过的项目只要有人坚持RSA就是加密函数一把梭十有八九要出事。这类实现通常直接对明文做模幂运算完全不做填充密码学里叫它教科书RSA。它能跑通但它同时具备前面说的三个结构特征攻击者手里等于有三个现成武器。第一个武器是确定性。同一个明文永远生成同一个密文攻击者可以准备一批候选明文预先加密再和目标密文比对秒猜出内容。这就像你的保险柜密码永远是1234而且柜子上贴着说明告诉你密码就是1234。第二个武器是乘法同态。攻击者如果拿到了一个密文c想知道它对应的明文m他可以先构造cc×r^e mod n然后想办法让拥有私钥的一方去解密c。由于RSA的同态性解密结果是m×r mod n。只要把r一除m就暴露了。这个过程和数字签名结合尤其危险所以现代协议对私钥到底参与哪些运算非常敏感。第三个武器是小明文。如果明文本身很小比如0、1这类密文一眼就能识别。填充方案要解决的就是把这三种武器全部锁进保险箱。答案就是OAEP。OAEP把明文先通过一个带随机种子的双向变换打乱再送入RSA。它让相同明文每次加密结果都不同破坏了确定性和可预测性同时因为变换里有校验位任何篡改都会在解密端触发校验失败破解了乘法同态借力的可能。标准库默认加密模式就带OAEP千万别手滑关闭。3.2 参数选择的四个经典陷阱这一节是真正的避坑重点。RSA的参数选择一旦出错后果不是慢一点而是整个密钥体系从数学上塌掉。陷阱一p和q太接近。如果两个素数很接近n的平方根附近就是它们的中点。经典的平方差分解法会从sqrt(n)开始逐个整数试探一旦找到x使得x^2−y^2n立刻就能解出p(x−y)、q(xy)。两个素数差那么一点点攻击者可能几小时甚至几分钟就拆掉2048位的n。正确做法是随机独立生成素数生成后检查差值是否过小不满足就重新选。陷阱二加密指数e过小。为了性能有人把e设成3这在现代标准里是个雷。设想同一个明文被加密后发给三个不同的接收者三个公钥的e都是3那么攻击者拿到三个密文后可以通过合并同余方程恢复出明文的3次方然后直接开立方明文就裸奔了。工程上直接用固定值65537它足够大又只有两个二进制1大整数模幂运算仍然很快。陷阱三私钥指数d过小。有些实现觉得私钥指数短一点能省性能结果掉进连分数攻击的套路里。当d相对于n小到一定程度攻击者可以从公钥的连分数展开中把d一步步还原出来复杂度低得可怕。一条经验是d应该接近φ不要故意压缩。陷阱四模数重用和共享素数。这是我在真实排查里见过最多的。两个不同证书的n如果恰好包含同一个素因子那么攻击者做一次最大公约数运算gcd(n1,n2)就能把这个共享因子挖出来接着两个私钥一起被还原。为什么会出现共享因子根子几乎都在随机数生成器上如果随机源熵不足或状态可预测生成出来的随机大素数就没那么随机。历史上出过不止一次批量提取事件靠的全是这一招。3.3 随机源整条密码链路里最容易被忽略的螺丝钉密钥生成的质量九成取决于随机源。大素数不是CPU自己变换出来的而是随机生成器铺了一个基底再经过素性检验筛出来的。如果随机源出了毛病后面所有数学再漂亮也白搭。我遇到过的一个典型教训是某套容器化环境里部署脚本偷懒把包含密钥对的工作副本直接复制成多个实例。结果这些实例的密钥完全一样证书一旦被拉到一起比对立刻暴露。更隐蔽的是部分设备在恢复快照后随机状态回退所有新生成的密钥会周期性重复。这类问题的排查思路不是去查数学而是去查熵源、查快照策略、查启动时是否重新初始化随机状态。处理办法很实用优先使用操作系统或安全芯片提供的强随机接口不要在虚拟化环境里直接复制包含密钥的镜像每次密钥生成后做一次重复性碰撞检测有条件就上专门的硬件随机数发生器。4. 实操清单我平时是怎么安全使用 RSA 的4.1 密钥长度、填充、用途一项都不能少先说密钥长度。我做过一个简单的对照表方便你按场景选密钥长度安全强度性能适用场景2048位约112位安全强度当前主流快常规业务、内部系统短期到中期可接受3072位约128位安全强度中等新系统推荐起步值平衡性能与长期安全4096位约140位以上明显更慢高安全要求的签名/密钥封装但没必要当默认性能差距不是线性的大整数模幂计算量随位长增长明显。很多项目一上来就4096结果握手和解密都变慢其实3072在很多场景已经够用。更重要的一条别在自己的代码里手写先哈希再模幂直接用密码库提供的签名和加密入口。填充选型上加密用OAEP签名用PSS这是现代推荐路线旧版填充方案不是不能用但历史上有过预言机侧的攻击新系统没必要冒险。4.2 别什么场景都硬上RSA选对工具比蛮力更有效RSA不是万能钥匙。它适合的领域是短数据加密、数字签名、密钥封装。要加密几十兆的文件RSA既不合适也不划算。实际工程里最常见的正确姿势是混合加密先用手头算法的公钥加密一个随机生成的对称密钥再用对称加密算法处理真正的大块数据。对称加密快如闪电RSA只需要负责保护那把钥匙各干各的活。和RSA相比椭圆曲线系列能提供更高的单比特安全强度密钥更短、计算更快移动端尤其香。所以在很多新系统里大家更愿意用椭圆曲线做签名和密钥协商RSA仍然留在一批兼容性要求高的系统里。不过这里有个提醒椭圆曲线同样有自己的参数陷阱选用曲线必须认准经过标准化、经过充分审查的曲线不要自己发明曲线。4.3 量子计算时代要不要焦虑要不要现在动关于量子计算的讨论逐年升温。理论上看一旦量子计算机规模能支撑大整数分解算法RSA的数学根基会受影响私钥还原时间可能被压缩到可行范围。这是理论事实不是营销话术。不过当前工程界的共识是距离能攻破2048位RSA的硬件成熟还有相当距离不需要今天就把所有系统推倒重来。真正值得认真对待的是先收集、后解密。攻击者现在可以把加密流量囤起来等到未来算力跨越门槛后一次性解开。如果某些数据属于十年后仍然敏感的长期机密那么现在就要考虑更保守的策略新系统设计时最好留出算法替换的抽象层别把RSA写死在代码深处。这几年标准化组织已经放出多轮后量子算法候选合理态度是关注迁移路径而不是恐慌性替换。5. 实战排查一次由共享素数引发的密钥危机5.1 从两把公钥莫名成了亲戚说起有一次我帮某企业系统做安全审计顺手抓了一批公钥做碰撞检测。算法很简单把两两公钥的模数n拿去算最大公约数如果gcd(n1,n2)1且不等于n1、n2那说明两份公钥共享了一个素因子。结果真的抓到一个碰撞两个看似无关的证书n的公约数不是1而是一个大素数。当时我和同事的第一反应是这不是数学奇迹是随机数发生器出了问题。接下来的处理流程值得记录。第一步把所有相关证书下架确认影响面。第二步用批量公约数工具把证书集合跑一遍找出所有可能共享因子的成员。第三步依靠共享因子还原出涉及系统的私钥以验证影响程度。第四步定位随机源查证书生成时所用设备的熵源状态、系统镜像是否被反复克隆、随机数种子是否可预测。第五步更换设备、重建密钥、重新签发证书并加入公钥因子碰撞检测作为上线前检查项。这个案例之所以让我印象深刻是因为它完美演示了RSA的结构命门攻击者不需要去硬扛大整数分解只要找到整个部署里一个共享因子门就开了。而这道门能否打开和RSA数学本身无关只和你有没有遵守密钥生成纪律有关。5.2 常见问题速查表症状可能原因处理建议同一明文加密结果总是一样没启用随机化填充检查是否用OAEP别用裸模幂证书公钥只有512/1024位历史遗留弱密钥下线、重签、提升到2048/3072多张证书公钥能被公约数撞出共同因子随机数质量差/镜像克隆全量轮换修熵源加碰撞检测签名验签不稳定填充模式或摘要算法不匹配统一标准库配置别手工拼接解密/握手特别慢密钥位长过高且频繁使用3072足够或改混合加密方案私钥文件可被环境变量或日志读出密钥管理混乱上密钥管理系统限制访问与审计5.3 我的检查清单与心得最后把我的日常检查顺序列出来你接手任何带RSA的系统都可以照着过一遍。第一密钥长度低于2048位的一律视为高风险第二确认所有加密入口都走了标准填充接口第三抓一批公钥样本做公约数碰撞检测这条成本极低收益极高第四审计密钥生成环境的随机源绝不在恢复快照后直接生成密钥第五记录密钥生成时间和负责人方便未来轮换和问责。这五步做完大部分和RSA被破有关的新闻都能在你自己系统里防住。我在实际项目里发现很多人对RSA的焦虑来自把算法当成黑魔法。黑魔法当然可怕因为你不知道它什么时候失灵。但一旦你把它的数学骨架、填充逻辑、参数边界拆开看就会发现它其实是一套极其直白的规则集合。规则遵守得好它稳如磐石规则被绕过任何一条都能让你出大事。最后再分享一个小技巧如果你怀疑某个系统里存在弱RSA密钥别急着对公钥本身冥思苦想先去做公约数批量检测。我见过太多团队把时间花在指望破解算法上却忘了最简单的那把钥匙——别人家的公钥。很多所谓破解其实只是我们自己的工程纪律欠了债。

相关新闻

微博情感分析实战:朴素贝叶斯、SVM与AdaBoost对比

微博情感分析实战:朴素贝叶斯、SVM与AdaBoost对比

简介:面向计算机相关专业学生与机器学习初学者的微博评论文本情感分析毕业设计资源,含完整项目文档,完整覆盖支持向量机、朴素贝叶斯与AdaBoost三种经典分类算法,项目基于真实微博评论数据,实现了从文本清洗、分词去停…

2026/10/13 4:52:16 阅读更多 →
NLMS自适应滤波实现胎儿心电提取:MATLAB完整流程与参数调优

NLMS自适应滤波实现胎儿心电提取:MATLAB完整流程与参数调优

简介:NLMS(归一化最小均方)算法提取胎儿心电的MATLAB实现,面向生物医学信号处理学习者和胎儿健康监测相关研究者,用于从孕妇胸导联与腹部混合心电信号中分离出胎儿心电(FECG)。代码完整覆盖自适…

2026/10/13 4:52:16 阅读更多 →
2026最新Java面试八股文:原理拆解与避坑实战指南

2026最新Java面试八股文:原理拆解与避坑实战指南

又到了招聘季,后台私信里堆得最多的一个问题就是“有没有2026最新Java面试八股文大全”。很多人以为把网传题库背一遍就能上岸,但这两年我给身边求职的朋友做模拟面试,明显感觉到一个变化:面试官早就不满足于“你背过没”&#xf…

2026/10/13 4:51:16 阅读更多 →

最新新闻

IIS管理器打开全攻略:本机启动、远程连接与排错实战

IIS管理器打开全攻略:本机启动、远程连接与排错实战

搞Windows服务器的同学都清楚,IIS管理器这个窗口,看着不起眼,却是撑起大量Web业务的关键工具。很多人以为它就是个“打开就能用”的图形界面,但在实际运维里,光是怎么把它顺利打开、正常连上远程站点,就能筛…

2026/10/13 5:33:32 阅读更多 →
从compose到组合上下文:函数组合的工程化实战复盘

从compose到组合上下文:函数组合的工程化实战复盘

函数组合不是新东西,但真正把它做到"极致"和"优雅",我用了将近一年的时间反复打磨。这篇文章是我对这段时间的完整复盘。我不打算讲枯燥的范畴论,也不打算罗列一堆库的API,我想说的是:我如何从一个…

2026/10/13 5:33:32 阅读更多 →
充电器空载发热、待机功耗异常怎么办?温度保险电阻排查维修实战

充电器空载发热、待机功耗异常怎么办?温度保险电阻排查维修实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:33:32 阅读更多 →
fio-3.8完整指南:从解压编译到IOPS与延迟分析实战

fio-3.8完整指南:从解压编译到IOPS与延迟分析实战

简介:FIO(Flexible I/O Tester)3.8 版本完整源代码压缩包,面向存储性能测试工程师、系统运维与内核/驱动开发者,用于在 SSD、HDD、RAID、NVMe 等场景下评估读写吞吐、IOPS 与延迟,并开展压力测试与瓶颈定位…

2026/10/13 5:33:32 阅读更多 →
python -v 和 python -V 的区别:命令行参数大小写敏感与解释器启动排查

python -v 和 python -V 的区别:命令行参数大小写敏感与解释器启动排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 5:33:32 阅读更多 →
目标类型new表达式:现代编程语言的类型推断演进

目标类型new表达式:现代编程语言的类型推断演进

1. 目标类型new表达式的前世今生第一次看到var list new List<string>();这种写法时&#xff0c;我还在用Java写ArrayList<String> list new ArrayList<String>();。这种重复的类型声明总让我觉得像在说废话——明明右边已经写了类型&#xff0c;为什么左边…

2026/10/13 5:32:32 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目&#xff0c;我最大的感受是&#xff0c;大部分坑不是出在技术前沿&#xff0c;而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节&#xff0c;最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了&#xff0c;很难不碰到舵机控制这道坎。做智能小车要转方向&#xff0c;做机械臂要抬关节&#xff0c;做云台要偏航俯仰&#xff0c;背后都是同一个东西在干活&#xff1a;舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”&#xff1f;——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台&#xff1f;或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜&#xff1f;又或者&#xff0c;在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →