web隐写术

620 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天

了解web隐写术之前,先了解一下什么是零宽字符。下面用到的分别是零宽不连字和零宽连字。

  1. 零宽不连字,全称Zero Width Non Joiner,是一个不打印字符,放在电子文本的两个字符之间,抑制本来会发生的连字(与‍相反)。在html中的编码(‌)
  1. ‍零宽连字,全称Zero Width Joiner,是不打印字符,使两个本不会发生连字的字符产生了连字效果,在html中的编码(‌)
  2. 零宽空格zero-width space, ZWSP)是一种不可打印的Unicode字符,用于可能需要换行处。在html中编码(​)

零宽字符串加密原理:

上面三个字符在前端都是不渲染的,我们就利用其中的两个来进行加密,分别是零宽不连字和零宽空格。他们在浏览器中都是不渲染的,但又实际存在,然后利用上面的两个零宽字符分别代表0和1编码。首先我们对目标字符串转换成二进制字符串,然后在分别用两个零宽字符替换掉0和1,并且插入到浏览器的元素中,这样,通过零宽字符串加密的文本就生成了。

1.零宽加密

<div>有内鬼,<span id="badman">是你吗?</span></div>

//加密
const zeroPad = num => '00000000'.slice(String(num).length) + num;
//把字符串转换为二进制字符串
const textToBinary = username => (
  username.split('').map(char =>
    zeroPad(char.charCodeAt(0).toString(2))).join(' ')
);
//把二进制字符串转换为零宽字符串
const binaryToZeroWidth = binary => (
  binary.split('').map((binaryNum) => {
    const num = parseInt(binaryNum, 10);
    if (num === 1) {
      return '​'; // 零宽空格
    } else if (num === 0) {
      return '‌'; // 零宽不连字
    }
    return '‍'; // zero-width joiner
  }).join('') // zero-width no-break space
);

let binary=textToBinary("123")  //这个'123'就是隐藏起来的实际内容
let zeroWidth=binaryToZeroWidth(binary)


let obj=document.getElementById('badman')
 obj.innerText=zeroWidth+obj.textContent

2.如何逆向解码

也比较简单,首先把零宽字符串转换成二进制字符串

const zeroWidthToBinary = string => (
  string.split('').map((char) => { // zero-width no-break space
    if (char === '​') { // 零宽空格
      return '1';
    } else if (char === '‌') {  // 零宽不连字
      return '0';
    }
    return ' '; // add single space
  }).join('')
);

然后再把二进制字符串转换成普通字符串就行

const binaryToText = string => (
  string.split(' ').map(num =>
    String.fromCharCode(parseInt(num, 2))).join('')
);

3.如何生成unicode编码的零宽字符

上面判断条件里面的就有unicode编码的零宽字符,只是因为当前编辑器没有用unicode解码,所以在一些编辑器只显示了一个红点,或者直接不显示

那么如何生成unicode编码的零宽字符进而用到代码中去的呢?

tool.chinaz.com/tools/unico…

首先找到比如零宽链接符的ASCII码,点击转换就行了,

转换成功后,右边的结果宽里不会显示,因为浏览器不显示零宽字符,但是确实是存在的,点击右边结果框,ctrl+A 复制就行了,然后添加到代码的条件判断里面。