webpack 在导入之前混淆文件名

问题描述 投票:0回答:1

我正在使用 webpack 为多个客户捆绑一个部署在多个位置的 React 应用程序。重要的是应用程序的每个版本都适用于所有客户。换句话说,只有一个构建过程。

这些客户(可以)拥有自定义翻译文本。这些以 JSON 文件的形式存储在存储库中。

比方说:

client_translations/en.ford.json
client_translations/en.tesla.json
client_translations/de.porsche.json

当用户登录时,应用程序会收到 customerId,从而知道要加载哪个翻译文件(使用

import
)。

const getClientTranslations = async (customerId: string, language: string) => {
  try {
    const clientTranslations = await import(
    /* webpackChunkName: "client_translation-[index]" */
    /* webpackMode: "lazy" */
      `client_translations/${language}.${customerId}.json`
    )
    return clientTranslations ?? {}
  }
}

因此,webpack 所做的就是生成像这样的漂亮块

client_translation-5318-bundle.js
,然后应用程序确定将其中哪一个注入到页面中。到目前为止一切顺利。

现在,主包中的某个位置存在文件名(包括客户名称)和

client_translation-XX-bundle.js
文件之间的映射。这样当我导入时 webpack 就可以找到该文件。但这也意味着我们的客户(例如“福特”)可以通过查看这些文件名来挖掘主包并发现我们的其他客户是“特斯拉”和“保时捷”。

这显然对我的客户来说是一个问题,所以我想做的是,导入带有哈希名称的 json:

  `client_translations/${language}.${md5Hash(customerId)}.json`

因此导入将解析为

client_translations/en.80ca06abfa1a5104af9a770f485dad07.js
但是在存储库中,我希望保持文件名未散列,因为显然对于开发人员来说,当文件名全部散列时查找内容是非常烦人的。

那么我们可以在构建时进行这种散列或任何其他类型的混淆吗

ps。我知道 MD5 不安全,但这不是重点。另一种类型的(快速)哈希对我来说也很好,但这个问题与此无关。

javascript webpack
1个回答
0
投票
任何数量或类型的哈希都无法为您解决这个问题。但话虽如此,您可以完全从主捆绑代码中混淆对翻译文件的引用,以便您的客户可以查看其他可用的翻译,除非他们知道客户 ID。

要实现此目标,您可以将翻译视为

普通资产,而不是使用动态import()

表达式导入它们。并且,我还将更改翻译下载机制:

function getClientTranslations<T>(customerId: string, language: string): Promise<T> { // Sample hashing. But not useful as hashing algorithm will be seen by the client. const hashed = btoa(customerId); const translations = fetch(`/public/client_translations/${language}.${hashed}.json`) .then(response => response.json()) .catch(() => ({})); return translations; }
通过使用 

fetch

 而不是 
import()
,Webpack 将不会看到这些文件并将它们添加到包中。现在第二步将使用
资产模块,如下所示:

import { btoa } from 'node:buffer'; import path from 'node:path'; const config = { mode: 'production', // Entry point and output entry: './src/index.js', output: { path: process.cwd() + '/dist', filename: 'output.js', assetModuleFilename(pathData, _assetInfo) { const { filename } = pathData; // For each, en.ford.json, we get ['en', 'ford', 'json'] const [lang, customerId, ext] = path.basename(filename).split('.'); // We want to output the file as dist/translations/lang.{hashedId}.json // Use base64 as a dummy hashing function const hash = btoa(customerId); return `translations/${lang}.${hash}.${ext}`; }, }, module: { rules: [ { test: /\.json$/, type: 'asset/resource', // Added additional condition so that other imported // JSON files are not included. Change it accordingly. include: /client_translations/ }, ], }, }; export default config;
这里重要的配置是 

assetModuleFilename

 配置中的 
output
 以及使用 
asset/resource
 来处理 JSON 文件。

最后,请记住,您需要告诉 Webpack 获取资源文件。为此,我们将使用

side-effect import

。副作用导入 + asset/resource
 将确保您的主包不包含对翻译文件的任何类型的引用。

在这种情况下,任何类型的散列所面临的挑战是,您必须使用相同的散列算法在客户端(捆绑代码)上映射

customerId

。所以,没关系。只要客户端知道其他客户的 ID,无论有或没有哈希,安全含义都是相同的。这里唯一的措施是通过删除对翻译文件的引用来进行一定程度的混淆。而且,还要注意,从缓存的角度来看,这是脆弱的。您应该使用基于文件内容哈希的正确哈希密钥。

为了获得完全 100% 的安全性,您可以执行以下两件事之一:

    让服务器通过 API 返回翻译。它可以添加适当的授权。您可以继续在开发模式下使用本地翻译文件,但在生产中,请将获取 URL 替换为正确的 API URL。然后,您的构建/部署脚本可以将这些文件上传到受保护的云存储,并且 API 可以在运行时简单地从中提取。
  1. 保留哈希算法
  2. 秘密并使用盐。并且,以某种方式让 API 在应用程序加载时在初始用户信息调用中返回此哈希值,以便您的客户端代码可以简单地使用此哈希值,而不是在前端计算它。
© www.soinside.com 2019 - 2024. All rights reserved.