JavaScript中最简单的字符串混淆和反混淆方法

67
我正在寻找一种在JavaScript中混淆和反混淆字符串的方法;也就是说,在安全不成问题的情况下进行加密和解密。最好是JS本地支持的(例如PHP中的base64_encode()base64_decode()),以“将一个字符串变成别的东西,然后再变回来”而无需编写函数。
欢迎任何建议!

关于“加密和解密在安全不是问题时”的部分让我感到非常困惑。如果内容的安全性无关紧要,那么加密有什么可能的价值呢? - Paul Turner
这对我来说完全没有意义。如果您使用本地函数混淆字符串,那么每个人都可以调用解密函数。根本没有任何改进,您可以将字符串保持原样。此外,这很可能会在Unicode字符串上出现问题。 - Christoph
19
@Christoph 这是一个有用的方法,可以防止普通用户检查您应用程序中给定逻辑的方式。严格来说,即使 Windows 二进制文件也可以被反向工程,因此,可以说将 C++ 源代码编译成可执行文件并没有提供额外的安全性。在我看来,这只是在不同层面上让小偷的生活更加痛苦的问题。 - John Weisz
1
有时候,我发现将包含明文参数的长URL混淆起来以便分享,这样做不仅可以提高优雅度,而且也可以增加一定的安全性。 - oskare
9
这个话题对我很有用,因为我需要一个JSON格式的“黑名单”单词列表,它将被放在客户端页面上,但我不想直接在源代码中列出详尽的不良字符串。 - Jon Church
显示剩余2条评论
5个回答

106
你可以使用btoa()atob()btoa()类似于base64_encode(),而atob()则类似于base64_decode()
以下是一个示例:
btoa('Some text'); // U29tZSB0ZXh0
atob('U29tZSB0ZXh0'); // Some text

请记住这不是保守秘密的安全方法。Base64是一种二进制到文本编码方案,通过将其转换为基数64表示法来将二进制数据表示为ASCII字符串格式。


2
似乎在大多数现代浏览器中都能正常工作,完全符合我的要求。谢谢! - Rich Jenks
3
值得注意的是,编码后的字符串比未编码的字符串要更大。 - UpTheCreek
现在跨浏览器支持看起来很好。https://caniuse.com/#search=btoa 它是安全的使用。 - Aniket Suryavanshi
谢谢。我喜欢这个的用例。 - ethancrist
非常重要的是要注意,如果字符串包含不属于ASCII字符集0-127范围内的Unicode字符,则此函数将失败,因此该函数对于几乎任何现代Web应用程序中用户输入的使用都不足够,因为人们可能会使用非ASCII字符。 MDN文档讨论了如何处理这个问题,您必须先将Unicode字符转换为字节字符串。 - Yetanotherjosh
我想为将来寻找答案的任何人添加一些信息,btoa和atob已被弃用,并且仅保留用于遗留Web API。应使用Buffer.from(str,'base64')和buf.toString('base64')执行在Base64编码字符串和二进制数据之间进行转换。 - Robby Hoover

41
值得注意的是,(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]可以在不看起来像字符串的情况下评估为字符串"fail"。真的,将它输入到Node中,你会感到惊讶。你可以通过疯狂地运用JavaScript来拼出任何东西。

2
进入节点并将其分解成其部分。它开始变得有些阴森可怖的意义。 - Gant Laborde
25
有趣!它可以与大多数字母一起使用!https://jsfiddle.net/pg07yf87/2/ 编辑:这个网站也可以为您执行此操作http://www.jsfuck.com/ - RedSparr0w

20

显然,我来晚了,但我正在为这个问题寻找另一个解决方案,而base64似乎太弱了。

它的工作原理如下:

"abc;123!".obfs(13) // => "nopH>?@."
"nopH>?@.".defs(13) // => "abc;123!"

代码

/**
 * Obfuscate a plaintext string with a simple rotation algorithm similar to
 * the rot13 cipher.
 * @param  {[type]} key rotation index between 0 and n
 * @param  {Number} n   maximum char that will be affected by the algorithm
 * @return {[type]}     obfuscated string
 */
String.prototype.obfs = function(key, n = 126) {
  // return String itself if the given parameters are invalid
  if (!(typeof(key) === 'number' && key % 1 === 0)
    || !(typeof(key) === 'number' && key % 1 === 0)) {
    return this.toString();
  }

  var chars = this.toString().split('');

  for (var i = 0; i < chars.length; i++) {
    var c = chars[i].charCodeAt(0);

    if (c <= n) {
      chars[i] = String.fromCharCode((chars[i].charCodeAt(0) + key) % n);
    }
  }

  return chars.join('');
};

/**
 * De-obfuscate an obfuscated string with the method above.
 * @param  {[type]} key rotation index between 0 and n
 * @param  {Number} n   same number that was used for obfuscation
 * @return {[type]}     plaintext string
 */
String.prototype.defs = function(key, n = 126) {
  // return String itself if the given parameters are invalid
  if (!(typeof(key) === 'number' && key % 1 === 0)
    || !(typeof(key) === 'number' && key % 1 === 0)) {
    return this.toString();
  }

  return this.toString().obfs(n - key);
};

3
这段代码会破坏字符串的for...in枚举,不要在生产环境中使用。 - Patrick Roberts
1
@PatrickRoberts 在使用 for ... in 时应该始终与 .hasOwnProperty() 捆绑使用。您还可以在不修改 String.prototype 的情况下定义 obfsdefs - Gan Quan
1
@GanQuan 这就是我的观点。答案根本不应该污染内置原型。.hasOwnProperty() 的“良好实践”(/s) 是由于污染内置对象的频率而产生的,而不是因为语言设计本身需要它。由于库经常使用任意扩展来污染内置对象,所以我认为 for...in 已经很少被用来枚举任何东西,包括字符串。 - Patrick Roberts
1
你有一个不错的混淆器,但是它被全局暴露在字符串原型上供任何人查看。这有点违背了初衷。 - Etienne Martin

1

1. 使用奇怪的字符串

访问 http://www.jsfuck.com/,输入代码后在下面的文本框中查看结果。

在控制台中测试,将返回“hi”:

(+(+!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+[+!+[]])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]

console.log("Original: hi")
console.log("Converted: " + (+(+!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+[+!+[]])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]])

它甚至看起来不像一个字符串!

2. 使用 atobbtoa

使用这种方法,只需使用 atob("string") 将字符串转换为 base64,然后使用 btoa("encoded") 解密字符串即可。


0
一个简单的字符串混淆方法是使用像这样的脚本,使用Node.js。这段代码是用Typescript编写的。
import readline from 'readline';

const rl = readline.createInterface({
    input:process.stdin,
    output:process.stdout
});
const randNum = (max:number=10000)=>Math.floor(Math.random() * max);
// finds an equation that will make the target number.
const findEquation = (target:number)=>{
    let equation = "";
    const rand = randNum();
    const diff = target - rand;
    const rand2 = randNum()
    const product = diff * rand2;
    equation = `${rand}+(${product} / ${rand2})`;
    return equation;
}
const randCharSequence = (length:number)=>{
    let str = "";
    for(let i = 0; i < length; i++){
        str += String.fromCharCode(randNum(256));
    }
    return str
}
const sep = randCharSequence(8)
rl.question("Enter the string to obfuscate:\n", (str)=>{
    let obfuscated = "(''";
    str.split("").forEach(char=>{
        const code = findEquation(char.charCodeAt(0));
        obfuscated += `+(String.fromCharCode(${code})+\"${sep}\")`
    })
    obfuscated += `).split(\"${sep}\").join('')`;
    
    console.log("Obfuscated String:");
    console.log(obfuscated);
    rl.close();
});

当您运行此脚本时,会提示您输入要混淆的字符串。然后,脚本会打印出一个混淆后的字符串。它使用涉及高达10000的数字的方程来生成数字,然后将其转换并连接成一个字符串。但这还不是全部。它还会添加一个随机生成的8个字符的字符串到输出中,在运行时被删除。这使得在阅读代码时更难看到字符串,但请记住,有权访问代码的人可以轻松地添加一个console.log语句,然后获取该字符串。请注意,这不是加密,只是使代码更难理解和阅读。

另外,一旦您获得了字符串,您可以对其进行Base64解码/编码,以使其更难以理解。 - Fighter178

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接