亚洲步兵一区二区三区-日韩精品伦理在线一区-亚洲色诱视频免费观看-久久人妻视频免费观看

廣州總部電話:020-85564311
廣州總部電話:020-85564311
20年
互聯網應用服務商
請輸入搜索關鍵詞
知識庫 知識庫

優網知識庫

探索行業前沿,共享知識寶庫

安全:生產環境不要在 JS 中暴露后端接口地址,麻煩給寫一個 vite 插件處理下

發布日期:2025-07-30 08:55:57 瀏覽次數: 864 來源:前端路引
推薦語
前端安全新思路:用Vite插件巧妙隱藏生產環境API地址,兼顧安全與開發效率。

核心內容:
1. 安全需求背景與前端API地址暴露問題分析
2. 基于異或加密的輕量級解決方案實現
3. Vite插件開發全流程與自動化替換技巧
小優 網站建設顧問
專業來源于二十年的積累,用心讓我們做到更好!

脑壳痛,最近莫名其妙的安全抓得严,有安全团队就提了个要求,生产环境下的 JS 中不想看到后端接口地址。

说实话,就算 JS 文件中看不到接口地址,也没办法掩饰前端往后端发送网络请求的事实,只是做了一个掩耳盗铃的效果而已。

既然人家安全专家提出了要求,那就只有改吧改吧了~~

由于项目已经上线有一段时间了,有一大堆的后端 API 接口地址存在,必然不可能一个一个的去修改!!

就只能折腾一下 vite 插件,让 JS 插件在构建时候自动替换接口地址了。

准备加解密方法

第一步,肯定需要一对加解密方法,用来处理字符串的加解密,由于咱只需要掩盖接口地址,而且代码在浏览器端运行,安全性啥的没办法保证,就用一个最简单的异或加密就行了:

123456789101112131415161718192021222324252627282930313233// 简单的 XOR 加密函数function encrypt(str, key) {  let result = '';  for (let i = 0; i < str.length; i++) {    const charCode = str.charCodeAt(i) ^ key.charCodeAt(i % key.length);    // 转换为16进制字符串,确保可打印字符    result += ('00' + charCode.toString(16)).slice(-2);  }  return result;}// 解密函数function decrypt(encrypted, key) {try {    let result = '';    for (let i = 0; i < encrypted.length; i += 2) {      const hex = encrypted.substr(i, 2);      const charCode = parseInt(hex, 16) ^ key.charCodeAt((i/2) % key.length);      result += String.fromCharCode(charCode);    }    return result;  } catch(e) {    console.error('[API Decrypt Error]', e);    return'';  }}/* 测试代码 */var key = 'test-string-xxx'var code = encrypt('/api/login', key)console.log(code);var str = decrypt(code, key)console.log(str)

有了上面两个加解密方法,那就可以开始折腾 vite 插件了~~

vite 插件

这一步一言难尽,各种折腾,具体过长就不摆了,最后有了一个 vite-plugin-api-encrypt.js 插件文件,内容如下:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576// 简单的 XOR 加密函数function encrypt (str, key) {  let result = '';  for (let i = 0; i < str.length; i++) {    const charCode = str.charCodeAt(i) ^ key.charCodeAt(i % key.length);    // 转换为16进制字符串,确保可打印字符    result += ('00' + charCode.toString(16)).slice(-2);  }  return result;}// 生成解密函数function generateDecryptFunction (key, functionName = 'decrypt') {  return `// API路径解密函数const ${functionName} = (encrypted) => {  try {    let result = '';    for (let i = 0; i < encrypted.length; i += 2) {      const hex = encrypted.substr(i, 2);      const charCode = parseInt(hex, 16) ^ '${key}'.charCodeAt((i/2) % ${key.length});      result += String.fromCharCode(charCode);    }    return result;  } catch(e) {    console.error('[API Decrypt Error]', e);    return '';  }};`;}export default function (options = {}) {  const {    key = 'api-encode-key',    decryptName = '__decryptApi' // 全局解密函数名  } = options;  return {    name: 'vite-plugin-api-encrypt',    transform (code, id) {      // 只处理JS/TS文件      if (!/\.(js|ts|vue)$/.test(id)) return;      // 匹配 /api/xxx 格式的字符串      const regex = /['"`](\/api\/[^'"`]+)['"`]/g;      let transformedCode = code;      let match;      while ((match = regex.exec(code)) !== null) {        const [fullMatch, apiPath] = match;        // 加密路径        const encrypted = encrypt(apiPath, key);        // 替换为解密函数调用        transformedCode = transformedCode.replace(          fullMatch,          `${decryptName}('${encrypted}')`        );      }      return transformedCode;    },    transformIndexHtml (html) {      // 注入全局解密函数到HTML头部      return html.replace(        '<head>',        `<head>          <script>            // 运行时解密函数            ${generateDecryptFunction(key, decryptName)}          </script>`      );    }  };}

然后在 vite.config.js 中配置使用插件:

123456789101112131415161718192021222324import { fileURLToPath, URL } from 'node:url'import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import vueDevTools from 'vite-plugin-vue-devtools'import apiEncrypt from './vite-plugin-api-encrypt'; // 插件路径// https://vite.dev/config/export default defineConfig({  plugins: [    vue(),    vueDevTools(),    apiEncrypt({      key: 'key', // 自定义加密 key      decryptName: '__decrypt' // 自定义全局函数名    })  ],  resolve: {    alias: {      '@': fileURLToPath(new URL('./src', import.meta.url))    },  },})

启动项目后,效果还不错,会将所有 /api 前缀的字符串都进行加密,再套一个解密方法,就像下面这样:

到这一步已经能解决接口地址暴露问题了,但还是不够完美,解密方法被全局暴露在 index.html 文件中,这也太明显了,有没有办法在需要解密的文件中注入一个解密方法,不要全局暴露??

完善插件

解决问题:在需要的位置插入解密方法,不要在 index.html 中全局暴露解密方法!!

修改 vite-plugin-api-encrypt.js 文件:

123456789101112131415161718192021222324252627282930313233343536373839404142// 其他部分不变,只需要修改暴露的插件对象export default function (options = {}) {  const {    key = 'api-encode-key',    decryptName = '__decryptApi' // 全局解密函数名  } = options;  return {    name: 'vite-plugin-api-encrypt',    transform (code, id) {      // 只处理JS/TS文件      if (!/\.(js|ts|vue)$/.test(id)) return;      // 匹配 /api/xxx 格式的字符串      const regex = /['"`](\/api\/[^'"`]+)['"`]/g;      let transformedCode = code;      let match;      let hasApiPath = false;      while ((match = regex.exec(code)) !== null) {        const [fullMatch, apiPath] = match;        // 加密路径        const encrypted = encrypt(apiPath, key);        // 替换为解密函数调用        transformedCode = transformedCode.replace(          fullMatch,          `${decryptName}('${encrypted}')`        );        hasApiPath = true;      }      // 如果文件中有API路径,注入解密函数      if (hasApiPath) {        const decryptCode = generateDecryptFunction(key, functionName);        transformedCode = `${decryptCode}\n${transformedCode}`;      }      return transformedCode;    },  };}

执行 build 命令构建之后,代码就是这样的:

每次插入的解密方法会造成代码重复,不过影响不大,解密方法就那么几行而已。如果实在有代码洁癖,还是可以考虑将解密方法抽离出来插入到 index.html 入口文件中!!


这里有一个小小的问题:解密方法插入的文字在文件开头,按照 ES 规范来说,文件开头应该是所有的 import 语句,但代码在浏览器运行没报错,这里就没管他了。

就像这样:


優網科技,優秀企業首選的互聯網供應服務商

優網科技秉承"專業團隊、品質服務" 的經營理念,誠信務實的服務了近萬家客戶,成為眾多世界500強、集團和上市公司的長期合作伙伴!

優網科技成立于2001年,擅長網站建設、網站與各類業務系統深度整合,致力于提供完善的企業互聯網解決方案。優網科技提供PC端網站建設(品牌展示型、官方門戶型、營銷商務型、電子商務型、信息門戶型、微信小程序定制開發、移動端應用(手機站、APP開發)、微信定制開發(微信官網、微信商城、企業微信)等一系列互聯網應用服務。


我要投稿

姓名

文章鏈接

提交即表示你已閱讀并同意《個人信息保護聲明》

專屬顧問 專屬顧問
掃碼咨詢您的優網專屬顧問!
專屬顧問
馬上咨詢
掃一掃馬上咨詢
掃一掃馬上咨詢

掃一掃馬上咨詢

主站蜘蛛池模板: 成人亚洲综合91精品国产成人| 最新中文字幕不卡av| 美女国产精品久久久久久久久| 久久日韩精品中文字幕| 老司机深夜福利视频在线观看| 91人妻人人澡人人爽天天摸| 精品一区二区三区蜜桃| 不卡一区二区中文字幕视频| 青青草中文字幕在线观看| 熟女精品少妇一区二区| 欧美一级和欧美三级在线观看| 日韩精品美女在线观看| 国产91丝袜香蕉在线播放| 国产高清欧美激情一区| 污污污视频在线观看网站| 欧美在线视频精品一区二区| 麻豆成人免费视频入口| 精品欧美日韩中文字幕在线一区 | 粉嫩一区二区三区久久| 国产熟女一区二区91| av天堂中文在线高清| 男女爱爱av免费网站| 中文字幕精品一区二区三| 日本少妇性视频一区二区| 中文字幕视频免费一区二区三区| 国产av精品一区二区三区免费视频| 国产精品三级女人国产香蕉| 欧美黑人人妻精品一区| 精品国产中文字幕懂色| 欧美日韩一区二区三区一| 亚洲欧美日韩在线成人| 变态av一区二区三区| 国产成人免费av在线播放欲色| 五月天女婷婷在线观看网站| 亚洲国产区一区二区三区| 亚洲一区在线中文播放| 黄片男的插女的免费视频| 亚洲最新网址一区二区| 亚洲黄色的网站在线观看| 国产一区二区三区亚洲综合| 麻豆黄色在线免费观看|