跳到主要内容

转义、编码和加密

转义、编码和加密是开发中很常见也很基础的概念。对于初学开发的开发者,可能有时会无法准确的区分着几个词。我们将通过这篇文章来了解一下“转义、编码和加密”这几个词的关联和区别。

转义

第一种转义场景

绝大多数的开发者都曾经在自己学习第一个编程语言时,就遇到了这个概念。以经典的C语言中字符串中的字符转义为例。

如果在一个字符串中存在一个",那么就需要在"前添加\才能够正常的表示,比如下面这样。

char* universal_law = "月老板说:\"世界上本也不存在'银弹'。一套框架解决不了所有问题。\""

之所以需要这样,是因为对于字符串来说,"本身就是表示一个字符串的起止符号。如果不进行转义,那么编译器将无法正确的识别其中的"哪些是分隔符,哪些是字符串内部的"

所以,第一种需要转义的场景就是:如果不进行转义就可能与语法规定的某些内容产生混淆,所以这些内容都被设计为需要转义。

基于这种场景,可以在很多的编程语言和概念中找到这种场景的体现:

  • java

    String honor = "月老板-\"赛博坦首席技术官\"";

    "进行转义

  • C#

    var proverbs = "月老板:\"这里不要写死,下次需求必改\"";

    "进行转义

  • XML

    <nb>月老板的衬衫价格&gt;99磅6便士</nb>

    &gt;是对>的转义,>是XML的边界符

  • 正则表达式

    \d+\\\.\d+

    \.表示一个.,因为在正则表达式中.表示匹配除\n\r之外的任何单个字符。 \\表示一个\,转义字符的转义表示。

第二种转义场景

当然,另外还有一种场景,同样还是以C语言为例,看一下下面这个例子:

char* hammurabi_no1 = "月落大佬:\"业务复杂度不会因为系统设计变化而减少,\r\n它只是从一个地方转移到了另外的地方。\""

其中的\r\n也是一种转义场景的使用。他们分别表示一个回车符和换行符。之所以要转义,是因为正常情况下,这样的字符是不可见的,对于这种字符,不过不采用转义的形式进行表达,那么会比较困难,因为语言设计者设计了这种转义的方式来表达不容易表达的字符。

因此,可以总结出第二种需要转义的场景:转义可以使得表达内容的方式更加容易,更加容易理解,所以设计了这类转义规则。

基于这种场景,也可以在很多编程语言和概念中找到对应的体现:

  • C#

    var colorOfYueluoShirt = 0xFFFFFF;

    0xFFFFFF表示一个十六进制数,对应的十进制数是16777215。0xFFFFFF的表达形式更容易阅读。

  • HTML

    <nb>月老板的衬衫价格&gt;966&yen;</nb>

    &yen;是对的转义,因为在期初的HTML中,只能用ASCII表中的字符进行表达,所以当时设计了这种方式。

除了在IT领域,在其他领域其实也存在类似第二场景的应用。例如在中国的航空领域,对于数字的念法有特殊的处理:7读作拐,0读作洞,1读作幺,2读作两。经过这样的“转义”处理,可以避免误听而造成的困扰。

转义的总结

总结来说,转义规则的设计,主要解决了两种场景下对代码的表达问题:

  1. 如果不进行转义就可能与语法规定的某些内容产生混淆,所以这些内容都被设计为需要转义。
  2. 转义可以使得表达内容的方式更加容易,更加容易理解,所以设计了这类转义规则。

值得一提的是,很多名称中包含有escape或者unescape的函数或者方法都表明了它们与转义有关。

编码

编码也是一个非常常见的概念。比如经常会听到UTF8编码、GBK编码、Base64编码、URL编码、HTML编码、摩斯电码等等一些和编码有关的概念。

生活化地理解编码

在了解编码之前,首先通过一个生活化的例子来了解一下“什么是信息,什么是信息的载体”。

全世界,对于“我爱你”这样一句话的表达方式千差万别。口头表达,书面表达,肢体表达,普通话表达,英语表达,音乐表达,绘画表达。甚至有生之年我们可以脑电波表达。但不论表达方式是如何的,其中包含的信息可以是一致的。都是为了传达“我爱你”这样的一个核心价值。

在以上这段表述中,可以将“我爱你”这样的概念理解为“信息”。而各种表达方式理解为这个信息的各种载体。

那么,回到编程的世界中来。计算机中的信息主要的载体是以电磁信号的物理载体存在于计算机世界中。那么如果要将现实世界复杂的内容都依靠这种载体来表达,就需要进行转化,我们可以将这种转化理解为编码。结合前文生活化的例子,使用普通话来表达“我爱你”这个信息,就可以理解为使用普通话来编码这个信息。

因此,编码,其可以理解为,采用一种新的载体来表示前一个载体所表达的信息。

可以套用类似这样一个公式来理解:XX编码,将A编码为B,以实现通过B进行存储或传输传输的目的。

技术相关的编码

那么,采用这样的概念,我们来理解一下以往见到的各种技术概念:

  • 文本文件编码,将“文本数据”编码为“二进制数据”,以实现通过“二进制数据”进行存储或者传输的目的

    文本文件在计算机中,最终的载体是二进制文件的形式存在。早起,由于计算机诞生在美国,文本内容也只包含有英文内容。因此当时只要使用ASCII进行编码就可以了。但是后来随着计算机的普及,需要表达的信息越来越多了。因此诞生了Unicode、GB2312等等编码形式。但不论如何,这些编码其实都是对文本信息的编码形式。

  • Base64编码,将“二进制数据”编码为“64个可打印字符的组合”,以实现通过“可打印字符的形式”进行存储或者传输的目的

    在Web场景中,在有些地方限制了数据传输的方式。例如,在URL,只能传递文本。因此,如果想要传输一组二进制数据。那么可以选用Base64编码,将二进制数据编码为可打印的字符串。这样才能完成URL上二进制数据的传输。

  • URL编码,将“非数字字母字符”编码为“十六进制转义序列”,以实现通过“十六进制转义序列”进行传输的目的

    如果需要在URL中传递中文作为参数,或者需要在URL中传递空格、&?=等等特殊符号。这个时候就需要进行URL编码。例如月老板会被编码为%E6%9C%88%E8%80%81%E6%9D%BF。编码的目的HTTP协议的内在要求,通过这种形式,可以浏览器表单数据的打包。

总的来说,通过编码,可以转化信息表达的载体。这样就可以利用新载体带来的好处。这里也有一些生活化的例子:

  • 摩斯电码,将“文本数据”编码为“点横组成的电信号”,以实现通过“电报”进行传输的目的。

    例如:

    -·-- ··- · ·-·· ··- ---   ·· ···   - ···· ·   -- --- ··· -   ··-· ·- -- --- ··- ···   -·· ·- ·-·· ·- ---
  • 社会主义核心价值观编码,将“文本数据”编码为“社会主义核心价值观组成的字符”,以实现通过“社会主义核心价值观”进行传输的目的。

    例如:

    诚信自由公正敬业友善公正爱国爱国友善爱国爱国爱国富强爱国民主友善爱国公正敬业诚信和谐诚信民主友善敬业友善爱国公正诚信民主富强诚信民主爱国友善爱国爱国诚信民主友善敬业敬业诚信文明友善爱国公正敬业爱国诚信富强诚信平等诚信自由公正敬业诚信文明爱国富强诚信自由平等诚信民主友善公正诚信民主友善自由诚信自由法治敬业友善自由爱国自由

    社会主义核心价值观编码工具:http://www.atoolbox.net/Tool.php?Id=850

值得一提的是,很多名称中包含有encode或者decode的函数或者方法都表明了它们与编码有关。

什么是乱码

根据上文提到的公式,编码是完成A->B的载体转化过程。那么同样可以定义A->B的逆过程B->A为“解码”。

一般,如果解码之后无法正确还原原来A所表达的信息,我们会说出现了乱码。例如,使用GB2312的方式去解码一个UTF8编码的文件,那么就会出现乱码。

当然,更加常见的情况是,当开发者,特别是初入的新晋工程师,看到自己无法理解的文本,就说:“这是乱码。”

总的来说,乱码通常来说只是因为选用的解码方式和编码方式不同,而导致信息失真的情况。选用正确的编码就能够解读出正确的信息。

加密

加密很好理解,在日常生活中也不乏加密的使用场景。特别是在以前的战争中的无线电技术应用历史中,确保己方军事信息不被敌方破解,采用优秀的加密算法是极为重要的军事内容。

加密,可以这样概括:按照一定的算法,将需要表达的信息进行处理,以达到除了信息的发送者和接收者之外,其他人无法识别信息真实内容的目的。

技术上,有需要使用加密的场景:

  • HTTPS,安全的HTTP通信通道,通过加密算法来确保浏览器接收到的数据没有被篡改,未被泄露
  • SSH,为建立在应用层基础上的安全协议。SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
  • SSR。SSR是各种集换式卡牌游戏中,卡牌稀有度级别分类的一种。(大雾)

这里需要特别说的是编码和加密的区别和联系:

  • 编码的目的是为了转换信息的载体,使得转换后的载体更好传输或者存储。但是加密是为了安全,防止被识别。
  • 加密需要一个或者一份密钥进行加密和解密处理。安全是加密算法,在没有密钥的情况下,几乎不可能被破解。但是编码并不需要密钥。

所以要简单区分是编码还是加密,可以简单套用这个理解:在算法完全公开的情况下,如果还需要密钥,那么是加密。如果不需要密钥,只能算是编码。

结合生活例子理解一下加密和编码的区别:存在这样一段字符串Мистер Мун, Навсегда Бог.这并不是加密,因为这是一段正常的俄语。不能因为看不懂就说他是加密,因为如果懂俄语,会用俄语解码这段信息,就能知道他表达的意思是:“月先生,永远的神”。

值得一提的是,很多名称中包含有encrypt或者decrypt的函数或者方法都表明了它们与加密有关。

下饭小测

以下是关于本文章的一些概念的测试题,以便读者更好的理解。

不必担心这些语言你没有学过,因为概念其实和语言关系不大。

所有的问题都只有三个选项:

  1. 转义
  2. 编码
  3. 加密

小测1

在很多编程语言中都存在“字符串内插”的语法,例如:C#、ES6、Powershell。

以C#为例,以下就是一个示例:

var dalao = "月落大佬";
var hammurabi_no1 = $@"{dalao}:
""业务复杂度不会因为系统设计变化而减少,
它只是从一个地方转移到了另外的地方。""
";
Console.WriteLine(hammurabi_no1);

那么,以上代码中""输出时只表示一个",这是(A)处理。

如果需要在$@开头的“多行字符串内插”字符串中,输出一个},那么需要使用}}来进行(B)处理。

A:转义

B:转义

小测2

在Powershell中如果要定义一个多行字符串变量,那么需要采用下面这样的写法:

$template = @"
## [version]

[content]

"@

那么,如果需要在这个字符串中插入一个@或者",可以直接写进去,因为powershell是使用@""@,作为多行字符串的起止符,而且要求起止符需要单行。因此中间出现的@#都不需要进行(A)处理。

A:转义

小测3

在javascript中有一个函数名称为escape。按照MDN的解释,该函数已经被标记为弃用了。建议使用encodeURIencodeURIComponent代替。从相应的函数解释上也可以看出,原来的escape是进行表达的意思是进行(A)处理。或许就是大佬们意识到这个名字其实不对,所以换了函数?新函数看名字直接理解应该是对URI进行(B)处理,似乎更加准确哟。

A:转义

B:编码

小测4

曾经有的网站使用 base64 的方式,处理登录票据,并且保存在 Cookie 中。尽管这似乎比明文保存要高明一点,但这是不安全的,因为 base64 只是一种(A)算法,不能够安全的防止信息被篡改。可以选用例如 DES 这样的(B)算法,来确保信息不被篡改。

A:编码

B:加密

总结

转义、编码和加密都是在开发过程中常常遇到的概念。注意区分学习,进行正确的表达能够更好沟通。


欢迎关注的我微信公众号,第一时间获取我的最新文章。