跳转到内容

安全跳转页面·插件版

更新于: 2024-12-26
LiuShen
7 分钟
2,776 字
PV --
UV --

这里是清羽AI,这篇文章主要介绍了作者开发的一个名为`hexo-safego`的Hexo插件,用于在生成静态网站时自动完成外链的替换工作,以增强博客的安全性。作者最初尝试使用JavaScript实现安全跳转页面,但后来发现搜索引擎检测风险网站时不执行JavaScript。因此,作者开发了一个Hexo插件,该插件通过在静态网站生成过程中替换外链来实现安全跳转,并支持丰富的个性化配置,如自定义文件名称、白名单域名、Base64编码等。文章还详细介绍了插件的使用教程和配置方法,包括如何安装插件、配置插件参数以及进行进阶操作。此外,作者还讨论了插件开发过程中遇到的问题和挑战,如如何处理夜间模式、白名单链接等。最终,作者希望通过这个插件帮助其他博主增强网站的安全性,并提供了详细的配置指南和进阶操作说明。

碎碎念

在之前的工作中,我曾两次发布了安全跳转页面。原本我以为自己用JavaScript实现的跳转功能已经相当不错,但随着进一步的学习,我意识到搜索引擎在检测风险网站时,通常是通过直接获取HTML内容并进行链接匹配,而这个过程中并不涉及JavaScript的执行。这让我意识到,我之前的JavaScript实现,实际上只是自娱自乐罢了(真是让人哭笑不得)。

洪哥提供的思路

6月10日,我突然萌生了自己开发一个插件的想法,并以此为契机,深入学习了Hexo插件的开发流程。起初,我在网上找到了一个替代方案,即hexo-external-link插件,它解决了外链跳转的问题。该插件的GitHub链接在文章尾部,然而,在进一步研究后,我发现这个插件也是通过在网页中嵌入JavaScript来实现跳转的,尽管它是以Hexo插件的形式集成的。因此,我决定自行对它的底层代码进行深度改造,最终成功创建了我自己的第一个npm插件:hexo-safego。这个插件能够在生成静态网站的过程中自动完成外链的替换工作,并且支持丰富的个性化配置。如果你熟悉HTML、CSSJavaScript,还可以对跳转页面进行修改,使其更加契合你的主题。后面我也会写几套模板,供大家自行选择。

站外引用 · 引用站外地址,不保证站点的可用性和安全性hexo-safego,👻基于hexo-external-link二次开发的改进版外链跳转插件github.com@willow-god

接下来,我将分享这个插件的详细使用教程,以及在开发过程中遇到的一些问题和挑战。

插件介绍

主要特性

  • 外部链接跳转:将外部链接替换为自定义的跳转页面,可以自定义文件名称,增加安全性。
  • 灵活配置:支持多个容器,使用css选择器进行选择、支持白名单域名和生效页面路径的配置。
  • Base64 编码:可选将外链链接编码为Base64加密,在跳转时再使用js转为正常网站地址,增强安全性能。
  • 调试模式:调试模式输出详细信息,便于开发和调试。
  • 自定义页面:支持设置标题、副标题、头像、暗黑模式,如果有前端基础,还可以自己定义跳转页面进行美化。

效果展示

  • 外联替换

    Base64编码

  • 夜间模式

    夜间模式

  • 白天模式

    白天模式

安全跳转必要性

在着手开发Hexo-SafeGo插件之际,确实遭遇到不少初始的困惑与不解。有朋友问,为何要增设这样一个看似多余的步骤?“直接浏览不更直接吗?何必增添一个看似拖沓的跳转环节?”还有人,将其误解为纯粹的技术冗余,误以为这是效仿某些平台所设置的“用户不便”之举。

然而,在深思熟虑之后,我坚持了自己的方向。Hexo-SafeGo插件的核心目的,并非直接进行安全检测,而是作为一种自我保护机制,默默守护着网站的声誉与访问者的信任。现在的插件并没有能力能够主动扫描并消除网络中的所有威胁,但却能有效避免自身网站因缺少必要的安全协议而被浏览器标记为“不安全”,这一小步跳跃,实则是维护网站形象与信誉的一大步。

此插件的实施,更像是一份无形的“免责声明”,它向访问者无声宣告:作为网站管理者,我已经采取措施确保连接的安全性,即便遭遇外部链接可能带来的不确定性,也已事先提醒,尽到了告知的责任。在这个信息错综复杂的时代,这样的透明度与责任感显得尤为重要,在网上,我们碰到的很多东西都是不安全的,甚至有些我们只能规避,因为我们承受不住(比如ddos呜呜呜),基于此目的,我还是完成了这个插件,首先这是我在hexo插件方向的一个学习,其次,我还是希望这个插件能够对一些站长有作用,那是我的乐趣。

Akilar的糖果屋
咕咕怪
咕咕怪搞什么跳转页面
咕咕怪
咕咕怪你说连接不安全,你自己加上去的还不安全嘛?
咕咕怪
咕咕怪这么不自信呀
咕咕怪
咕咕怪咕咕
LiuShen
LiuShen呜呜呜

使用说明

安装

在使用该插件之前,需要先安装 cheeriocheerio 是一个轻量级的库,用于在服务器端快速、灵活地实现 jQuery 核心功能。在 hexo-safego 插件中,cheerio 被用来解析和操作生成的静态 HTML 内容,类似于在浏览器中使用 jQuery 处理 DOM 元素。这使得插件能够在生成静态页面时,处理和替换外部链接,增强博客的安全性,而不需要在客户端引入 jQueryHexo 一般都有这个插件,可以在 node_modules 查看,如果没有,请先执行:

npm install cheerio --save

然后即可安装该插件:

npm install hexo-safego --save

此时,我们就安装好了该插件。

配置

hexo根目录的_config.yml文件中添加以下配置:

# hexo-safego安全跳转插件
# see https://blog.liushen.fun/posts/1dfd1f41/
hexo_safego:
  # 基本功能设置
  general:
    enable: true # 启用插件
    enable_base64_encode: true # 使用 Base64 编码
    enable_target_blank: true # 打开新窗口
  # 安全设置
  security:
    url_param_name: "u" # URL 参数名
    html_file_name: "go.html" # 重定向页面的文件名
    ignore_attrs: # 忽略处理的 HTML 属性
      - "data-fancybox"
  # 容器与页面设置
  scope:
    apply_containers: # 应用的容器选择器
      - "#article-container"
    apply_pages: # 应用的页面路径
      - "/posts/"
      - "/devices/"
    exclude_pages: # 排除的页面路径
  # 域名白名单
  whitelist:
    domain_whitelist: # 允许的白名单域名
      - "qyliu.top"
      - "liushen.fun"
  # 页面外观设置
  appearance:
    avatar: /info/avatar.ico # 头像路径
    title: "清羽飞扬" # 页面标题
    subtitle: "安全中心" # 页面副标题
    darkmode: true # 是否启用深色模式
    countdowntime: -1 # 倒计时秒数
  # 调试设置
  debug:
    enable: false # 启用调试模式

如果你前方安装正确,此时你应该可以先直接尝试使用hexo三件套查看效果了!如果遇到了问题,请开启debug查看输出,如果无法解决欢迎提交issue

配置项

如果你可以正常运行,下面你可以配置相关配置项对你的博客进行适配,下面是每个配置项的说明

  • enable : Boolean, 默认值: false, 描述: 是否启用 hexo-safego 插件。

  • enable_base64_encode : Boolean, 默认值: true, 描述: 是否对跳转链接进行 Base64 编码,如上面展示图像所示,如果关闭,则不对参数进行处理,直接放置目标路径。

  • enable_target_blank : Boolean, 默认值: true, 描述: 是否在跳转链接中添加 target=“_blank” 属性,在新页面跳转。

  • url_param_name : String, 默认值: “u”, 描述: 跳转页面的 URL 参数名称,可自行定义。

  • html_file_name : String, 默认值: “go.html”, 描述: 生成的跳转页面文件名。

  • ignore_attrs : Array, 默认值: [‘data-fancybox’], 描述: 需要忽略的链接属性列表,这里默认忽略灯箱,如果你有其他需要忽略的可以继续添加。

  • apply_containers : Array, 默认值: [‘#article-container’], 描述: 指定要处理的容器列表,这里默认为butterfly文章部分。

  • domain_whitelist : Array, 默认值: [], 描述: 域名白名单列表,使用字符串匹配,如果跳转链接中包含该字符串,则忽略。

  • apply_pages : Array, 默认值: [‘/posts/’], 描述: 生效页面路径列表。

  • avatar : String, 默认值: “https://fastly.jsdelivr.net/gh/willow-god/hexo-safego@latest/lib/avatar.png”, 描述: 跳转页面的头像图片链接,可以使用相对地址。

  • title : String, 默认值: “网站名称”, 描述: 跳转页面的标题。

  • subtitle : String, 默认值: “网站副标题”, 描述: 跳转页面的副标题。

  • darkmode : Boolean, 默认值: false, 描述: 是否启用夜间模式,可选auto,可以自动切换亮暗模式,true锁定暗色模式。

  • debug : Boolean, 默认值: false, 描述: 是否启用调试模式,开启后会输出详细的调试信息。

注意,以上配置项中未设置空值判断,请不要留空。如果您不需要某个配置项并希望使用默认值,请自行填写为默认值或直接删除对应配置项!

进阶操作

如果你有前端基础,除了以上配置 ,你还可以自行定义相关页面,打开插件中的go.html,这里我为了方便大家修改,没有进行代码压缩,其中CSS分为三部分:通用配置,夜间专用,白天专用:

  1. 通用配置:这里包含除了夜间和白天配色,其余所有css配置:

    body {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
      font-family: Arial, sans-serif;
      overflow: hidden;
      flex-direction: column;
    }
    .avatar-placeholder,
    .avatar {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      margin-bottom: 15px;
      display: block;
    }
    .avatar {
      display: none;
    }
    .description {
      font-size: 18px;
    }
    .subtitle {
      font-size: 12px;
      margin-bottom: 20px;
      color: #c4c4c4;
    }
    .loading {
      text-align: center;
      padding: 30px;
      border-radius: 18px;
      animation: fadein 2s;
      width: 400px;
      max-width: 90%;
    }
    @keyframes fadein {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    .content {
      margin-bottom: 20px;
    }
    .url-text {
      margin-bottom: 10px;
      font-size: 16px;
      letter-spacing: 1px;
    }
    .jump-url {
      font-size: 20px;
      display: block;
      margin-top: 5px;
      margin-bottom: 25px;
      padding: 15px;
      border-radius: 8px;
      height: 25px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .countdown-text {
      margin-top: 12px;
      font-size: 12px;
    }
    .button-container {
      display: flex;
      justify-content: center;
      gap: 20%;
      margin-top: 20px;
    }
    .button {
      padding: 10px 20px;
      border-radius: 16px;
      border: none;
      cursor: pointer;
      font-size: 16px;
      width: 120px;
      height: 40px;
    }
    .cancel-button {
      color: black;
    }
    .confirm-button {
      color: white;
    }
    .progress-bar {
      width: 100%;
      border-radius: 5px;
      overflow: hidden;
      height: 10px;
      margin-top: 20px;
    }
    .progress {
      width: 100%;
      height: 100%;
      transition: width 1s;
    }
  2. 夜间配置:夜间配置主要配置夜间的一些配色:

    {% if darkmode %}
            body {
                background: linear-gradient(135deg, #364f6b, #222831);
            }
            .loading {
                background: #393e46;
                color: #EFEFEF;
                box-shadow: 0 4px 8px rgba(100, 100, 100, 0.1);
            }
            .description {
                color: #F3F3F3;
            }
            .url-text, .countdown-text {
                color: #EFEFEF;
            }
            .jump-url {
                border: 1px solid #777;
                background-color: #333;
                color: #EFEFEF;
            }
            .cancel-button {
                background-color: #872C2C;
                color: #FFF;
            }
            .confirm-button {
                background-color: #28566F;
                color: #FFF;
            }
            .progress-bar {
                background-color: #444;
            }
            .progress {
                background-color: #888;
            }
            {% endif %}
  3. 白天配置:同上,包含白天配色

    {% if not darkmode %}
            body {
                background: linear-gradient(135deg, #fce38a, #eaffd0);
            }
            .loading {
                background: rgba(255, 255, 255, 0.7);
                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            }
            .url-text {
                color: #333;
            }
            .jump-url {
                border: 1px solid #ccc;
                background-color: #F7F9FE;
                color: #333;
            }
            .countdown-text {
                color: #515151;
            }
            .cancel-button {
                background-color: #a6e3e9;
            }
            .confirm-button {
                background-color: #3fc1c9;
            }
            .progress {
                background-color: #abedd8;
            }
            {% endif %}
  • 注意,上面的{% if not darkmode %}不能删除,这个是模板文件的配置,表示当在符合要求时将其包裹的内容放置到文件中,否则抛弃,我将夜间和白天的配色分开目的是尽量压缩生成的html页面代码量,加快加载速度。下面的JS选项,如果无必要,请不要删除。
  1. 除此之外,你还可以更改其中的结构,但是请尽量不要修改类名,有些类名可能绑定有特定的跳转。

后面我会写一些模板文件,在github上更新,感兴趣的欢迎star

杂记

在开发过程中,我曾使用时间来判断白天或者夜间,添加对应的类来调整暗色和亮色,但是我发现在加载后切换亮暗的一瞬间总会有一部分闪烁,很影响观感,于是我去掉了按照时间自动切换的功能,改为选择亮暗,尽可能给不想改源码的童鞋更多的,更个性化的选择。

在白名单链接方面,我使用字符串匹配,这样可能不如通配符的匹配性那么强,但是优点在于好理解,但是后面又改成了URL判断,希望不要出问题QAQ

在原作者中还有一些配置项,比如额外参数:external nofollow noopener noreferrer经过考虑后,我选择直接将这个添加到网站中,因为这个选项非常常用,下面是解释:

  1. external:指示链接指向外部网站。这通常是为了便于样式和 JavaScript 控制,但对搜索引擎爬虫没有直接影响。
  2. nofollow:告诉搜索引擎不要跟踪这个链接,也就是说,不要将链接目标的权重传递给目标页面。因此,使用 nofollow 可以防止搜索引擎通过这个链接爬取目标页面并将其权重传递。
  3. noopener:用于防止新打开的页面能够通过 window.opener 属性获得对原页面的引用。这主要是为了防止某些安全风险,例如页面篡改和钓鱼攻击。
  4. noreferrer:告诉浏览器在导航到链接目标时不发送 HTTP Referer 头信息。这对于保护隐私和安全有一定帮助。

这些功能都是非常常用的,可以进一步保护我们的网站,并且也不会有什么副作用,并且经过go.html包裹了的地址也显然没有了被爬取的必要,所以我将这个配置项直接添加到了代码中,减少参数量。

每日一图

芜湖,还是老习惯!

参考链接

站外引用 · 引用站外地址,不保证站点的可用性和安全性hexo-external-link,😀一个Hexo插件,解决外链跳转问题github.com@hvnobug

--- 柳影曳曳,清酒孤灯,扬笔撒墨,心境如霜

Previous
2024,清风入梦,扬帆待明年
Next
华为通用软件开发工程师面经