天天看點

轉義、編碼和加密

轉義、編碼和加密是開發中很常見也很基礎的概念。對于初學開發的開發者,可能有時會無法準确的區分着幾個詞。我們将通過這篇文章來了解一下“轉義、編碼和加密”這幾個詞的關聯和差別。

轉義

第一種轉義場景

絕大多數的開發者都曾經在自己學習第一個程式設計語言時,就遇到了這個概念。以經典的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的解釋,該函數已經被标記為棄用了。建議使用encodeURI和encodeURIComponent代替。從相應的函數解釋上也可以看出,原來的

escape

是進行表達的意思是進行(A)處理。或許就是大佬們意識到這個名字其實不對,是以換了函數?新函數看名字直接了解應該是對URI進行(B)處理,似乎更加準确喲。

A:轉義

B:編碼

小測4

曾經有的網站使用 base64 的方式,處理登入票據,并且儲存在 Cookie 中。盡管這似乎比明文儲存要高明一點,但這是不安全的,因為 base64 隻是一種(A)算法,不能夠安全的防止資訊被篡改。可以選用例如 DES 這樣的(B)算法,來確定資訊不被篡改。

A:編碼

B:加密

總結

轉義、編碼和加密都是在開發過程中常常遇到的概念。注意區分學習,進行正确的表達能夠更好溝通。

成稿粗淺,定有缺漏。承蒙君閱,還望指教。