```html xss漏洞代码 xss漏洞代码 一个搜索框,你输入 <script>alert(1)</script>,洞代页面直接弹窗。洞代这可能是洞代最古老的XSS演示,但二十年过去,洞代类似代码还在生产环境里跑着。洞代 上周帮朋友看个小程序后台,洞代用户昵称字段直接输出到页面,洞代没做任何转义。洞代我填了个 <img src=x onerror=alert(document.cookie)>,洞代管理后台的洞代会话cookie就出现在我面前。开发者的洞代解释是:“测试环境,没在意。洞代” 问题在于,洞代这套代码后来原封不动上了生产。洞代 XSS本质是浏览器把用户输入当代码执行了。反射型、存储型、DOM型,分类不重要,重要的是那段能跑起来的payload。看个真实案例——某电商评论区的过滤逻辑: // 后端伪代码 let comment = req.body.comment; comment = comment.replace(/<script>/gi, ''); db.save(comment); // 前端直接 innerHTML 渲染 过滤只删了 <script>,但 <img src=x onerror=alert(1)> 照样弹。更离谱的是,有人用 <scr<script>ipt>alert(1)</script> 嵌套绕过,正则替换一次后剩下的字符又拼成了新标签。这种“黑名单”思维在XSS防御里基本等于没防。 DOM型XSS更隐蔽。有次我审一个前端路由,代码长这样: const hash = location.hash.slice(1); document.getElementById('content').innerHTML = hash; 用户访问 page.html#<img src=x onerror=alert(1)>,代码直接执行。服务器日志里看不到这段payload,WAF也拦不住——因为请求根本没到后端。这种漏洞在前端框架里尤其常见,开发者以为“只是操作DOM”,忘了 innerHTML 会解析HTML。 防御其实不复杂。输出到HTML上下文时,把 & < > " ' 转义成实体。用 textContent 代替 innerHTML。如果非要渲染富文本,上DOMPurify这类库,别自己写正则。CSP也能兜底,但别把它当唯一防线——绕过CSP的姿势每年都在更新。 一个细节:很多开发者知道转义,但只转义了双引号,忘了单引号。属性值用单引号包裹时,' onmouseover='alert(1) 照样能注入。上下文决定转义规则,HTML标签内、属性内、script标签内、CSS内,规则都不一样。 去年某CMS爆过一个存储型XSS,payload藏在用户签名的 onfocus 事件里。管理员查看用户列表时,鼠标划过就触发。代码审计发现,签名输出时用了 htmlspecialchars($sig, ENT_QUOTES),看起来没问题。但问题出在另一个地方——用户头像的 alt 属性没转义,攻击者把payload塞进了文件名。这种边角料位置,往往是XSS的温床。 如果你在写代码,记住一条:任何用户能控制的数据,输出到页面时都要按上下文编码。别信“前端已经校验过了”,攻击者可以直接发请求。也别信“这个参数没人会改”,自动化扫描器每天在互联网上爬,你的表单早被盯上了。 最后看个最简单的反射型例子,URL参数直接回显: <?php $name = $_GET['name']; echo "<h1>Hello, $name</h1>"; ?> 访问 ?name=<script>alert(1)</script>,弹窗。修复就一行:echo "<h1>Hello, " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "</h1>";。但现实中,很多人连这一行都懒得加。 ``` |