一、文档结构
<!DOCTYPE html> <!-- HTML5 声明 -->
<html>
<head>
<meta charset="UTF-8"> <!-- 字符编码 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>页面标题</title>
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>
要点: 影响浏览器解析字节的方式;
二、常用标签
什么是标签:
- 是由一对尖括号包裹的单词构成 例如: <html> *所有标签中的单词不可能以数字开头.
- 标签不区分大小写,<html> 和 <HTML>
- 标签分为两部分: 开始标签和结束标签两个标签之间的部分 我们叫做标签体
- 有些标签功能比较简单,使用一个标签即可。这种标签叫做自闭和标签,例如:
<br/><hr/><input/><img/> - 标签可以嵌套,但是不能交叉嵌套
<a><b></a></b>
文本与结构
<h1>~<h6> 标题
<p> 段落
<br> 换行(自闭合)
<hr> 分割线
<div> 块级容器
<span> 行内容器
<pre> 预格式化
<code> 代码
链接与媒体
<a href="url">链接</a>
<img src="x" alt="图">
<video src="v.mp4" controls></video>
<audio src="a.mp3" controls></audio>
<iframe src="url"></iframe>
<object data="x"></object>
<embed src="x">
表单
<form action="/submit" method="POST" enctype="multipart/form-data">
<input type="text" name="user" value="">
<input type="password" name="pass">
<input type="hidden" name="token" value="abc">
<input type="file" name="file">
<textarea name="msg"></textarea>
<select name="opt"><option>1</option></select>
<button type="submit">提交</button>
</form>
要点:
- method=”GET” 参数在 URL 中,会进日志、可被篡改。
- method=”POST” 参数在 body 中,但也可被篡改。
- enctype=”multipart/form-data” 是文件上传的必要条件。
<input type="hidden">的值可被前端修改,不能作为唯一信任来源。
脚本与样式
<script>...</script>
<script src="x.js"></script>
<style>...</style>
三、属性与事件
常见属性
| 属性 | 说明 | 关注 |
|---|---|---|
href |
链接地址 | 可被指向恶意站点或伪协议 |
src |
资源地址 | 可加载外部脚本/图片,用于外带 |
action |
表单提交地址 | 可被篡改为攻击者服务器 |
value |
表单值 | 可被篡改,不可信 |
name |
参数名 | 后端按此接收数据 |
type |
输入类型 | hidden 仍可被改 |
style |
内联样式 | 老 IE 可执行表达式 |
data-* |
自定义数据 | 前端 JS 常读取,可能成为 DOM 注入源 |
事件处理器(常用于触发 JS)
onclick onerror onload onfocus onmouseover
onsubmit onchange oninput ontoggle onanimationstart
要点:事件处理器本质是内联 JS,若服务端把用户输入拼进事件属性,就会产生 XSS
四、特殊字符与实体编码
| 字符 | 实体 | 用途 |
|---|---|---|
< |
< |
防止标签注入 |
> |
> |
同上 |
" |
" |
防止属性闭合 |
' |
' |
同上 |
& |
& |
实体起始 |
| 空格 | |
不换行空格 |
要点:HTML 实体编码是输出编码的核心手段。服务端在把用户数据输出到 HTML 时,应对 < > “ ‘ & 做实体编码,这是防御 XSS 的第一道防线。但编码要匹配上下文:HTML 正文、属性值、JS 字符串、URL 各有不同的编码规则。
数值实体:a 和 a 都表示 a,可用于绕过简单的关键字过滤,也说明黑名单过滤不可靠。
五、HTML 解析特性
1. 标签闭合与容错
浏览器对畸形 HTML 有容错解析。未闭合的标签可能被自动补全,这会影响注入 payload 的实际结构。分析注入点时,要以浏览器实际解析后的 DOM 为准,而不是源码文本。
2. 注释
<!-- 注释内容 -->
若服务端把用户输入拼进注释,可用 –> 闭合注释,把后续内容变成可执行结构。
3. 属性值引号
属性值可用双引号、单引号或不加引号。无引号时遇到空格即结束,这决定了注入时是否需要空格分隔新属性。
4. 标签
<base href="http://evil.com/">
若攻击者能注入
六、表单与请求相关
GET 和 POST
- GET:参数在 URL,长度有限,会被记录在浏览器历史、服务器日志、Referer 中。
- POST:参数在请求体,不显示在 URL,但同样可被篡改。
<input type="hidden" name="price" value="100">
用户可用开发者工具改成 1,服务端若直接信任该值,就是参数篡改漏洞。
CSRF 相关
表单可跨站提交:
<form action="http://target.com/transfer" method="POST">
<input name="to" value="attacker">
<input name="amount" value="1000">
</form>
<script>document.forms[0].submit()</script>
这说明仅靠表单无法防 CSRF,需要 Token、SameSite Cookie、Referer 校验等。
七、iframe 与跨域
<iframe src="http://other.com"></iframe>
· 同源策略限制父页面读取 iframe 内容。 · 但 window.postMessage 可跨域通信,若接收方不校验 origin,可被利用。 · X-Frame-Options 和 CSP frame-ancestors 用于防点击劫持。
八、一些结论
- HTML 是输出上下文:服务端把数据输出到 HTML 时,必须按上下文做编码,否则产生注入。
- 前端数据不可信:hidden 字段、表单值、URL 参数都可被修改,服务端必须重新校验。
- 浏览器容错解析:分析注入不能只看源码字符串,要看浏览器实际构建的 DOM。
- HTML 不是孤立的:它与 HTTP 请求、Cookie、同源策略、CSP 共同构成 Web 安全模型。