網路安全 與 加密演算法
計算機中的網路安全
在本篇中介紹了以下幾個方面:
機密性
密碼學
對稱加密演算法(DES, 3DES, AES)
公開祕鑰演算法
- RSA大素數的獲取
完整性
雜湊函式(MD5, SHA-1, 並沒有提及演算法實現)
報文鑑別(MAC)
數字簽名
端點鑑別
應用
- SSL(TCP網路安全)
執行時安全
- 防火牆的基本知識
主要體現在以下幾個方面:
機密性, 即傳送的資訊只有雙方彼此能夠解讀,其他人以任何方式皆無法解讀。
報文完整性, 即接收方需要能夠驗證,當前接收到的資料是完整的,沒有被經過篡改的。機密性與完整性是相互獨立的兩個屬性。
端點鑑別, 需要知道我收到的訊息, 確確實實是來自於對方, 而不是惡意方偽裝的。
執行性安全, 需要能夠識別並阻攔惡意攻擊。如 Dos攻擊等, 其目的並非為了竊取資訊,而是使得系統癱瘓, 無法執行。
機密性
首先來看機密性問題, 小明和小紅之間傳送的有效資訊 不希望被第三方解讀。 而實現這點的方式自然是, 加密, 加密,就需要相關的密碼。
密碼學
加密所要實現的根本目的是,將資料加密,除非擁有相關的祕鑰,演算法,才能夠 也 必須能夠 將資料恢復到 原始資料。
這裡的原始資料被稱作明文, 小明使用了加密演算法加密其明文, 生成的文字為密文, 加密演算法是公知的,而祕鑰是私有的.
對稱祕鑰體系
凱撒密碼 是一種簡單的加密演算法。
對於字母而言, 約定 用 當前字母的後 第K個字母加以替換, 即可生成對應的密文。
如: a b c k=2-> c d e
只需要雙方約定好共同的K, 即可進行加密解密。
更進一步 則是將 k=2 換成只有雙方知道的演算法, 如 k = index + 1, 即 k=3
但缺點同樣明顯, 文字自身並不是沒有特點的, 如小明和小紅在溝通的時候常常會在開頭加入對方的姓名, xiao hong,
那麼經過加密之後,變成了 zkcq jqpi, 則根據習慣來推算, 很容易就得出來 K = 2.
即使是它的改進演算法:
單碼代替密碼, 也難以規避掉這個問題。
單碼代替密碼不再使用固定的K, 而是有 密碼本 將 明文一一對映替換為 密文, 如 a->h b->k c->a, 雙方都持有相應的密碼本,即可完成加解密工作。
但是依然是之前的 xiao hong 作為慣用語, 隨著接收到的密文不斷變大,變多,則能夠逐步推算, 還原出對應的密碼本。 完成解密工作。
多碼代替密碼
這是對單碼代替密碼的一種改進, 對於明文中 文字 位置的不同 採用不同的 密碼本進行匹配。
而祕鑰呢? 則是 多個密碼本, 以及 位置 和 密碼本之間的匹配關係。
對稱加密在現代社會有兩種寬泛的型別: 流密碼, 塊密碼。
我們會觀察到這樣兩個問題:
在上面提到的幾種簡單的文字加密演算法中, 僅僅能夠對文字進行加密, 而我們在網路中傳輸 可不一定是文字,更大的可能性是流。 包括協議的首部, 資料報本身。我們所需要加密的物件不僅僅是文字, 而在網路中 自然更為合適的是對 資料流進行加密。 這並不意味著是 流密碼。
可匹配的可能性依然太少, 適用性不夠強。
而塊密碼, 正是前面幾種簡單密碼的延伸。
我們將資料流進行拆分 3 6 64 128 等等 bit 為一個塊, 然後對每一個塊都進行加密。
注意到 對 3 bit塊進行加密。 可能會對映到的結果有: 000 001 010 011 100 101 110 111 即 2^3 8中可能性。
而我們的輸入同樣有8種可能性, 因此會對映為 8! = 40320 種可能的結果。 即對每一種輸入都找到其對映結果, 且與其他輸入的結果不重複。
40320 種可能的結果, 對現代計算機來說破解起來實在是一件很輕易的事情。而為了防止被破解, 因此往往會採用更大的塊 做為對映, 比如說 64位, 這樣我們的可能結果就有 (2^64)! 想要破解無疑是一件很困難的事情。
不僅僅是破解起來很是困難,實現起來也是同樣的困難,需要雙方維護一個 2^64 的輸入輸出對映表, 如果需要改變對映表, 也需要雙方都進行調整才可以。
而真實採用的方式,則是 使用函式來模擬 隨機排列表, 一個簡單的例子是:將 64bit拆分成 8 * 8 bit, 每次用一個 8bit的對映表,去置換第一個塊, 將置換後的結果 與 剩餘部分混合, 再迴圈置換 剩下的 bit塊,經過n次迴圈以後, 就提供了一個64bit的塊, 這種演算法的祕鑰是 8張排列表。
DES演算法
參考連結:資料加密演算法--詳解DES加密演算法原理與實現
DES是一個分組加密演算法,典型的DES以64位為分組對資料加密,加密和解密用的是同一個演算法。
金鑰長64位,金鑰事實上是56位參與DES運算(第8、16、24、32、40、48、56、64位是校驗位,使得每個金鑰都有奇數個1),分組後的明文組和56位的金鑰按位替代或交換的方法形成密文組。
需要注意的地方是, 如果初始祕鑰轉換成 byte之後, 如果其前7位是相同的, 那麼這兩個祕鑰所計算出來的資料就是相同的。 因為 8 16 等等 是不參與DES運算的。
參考連結:JAVA DES 祕鑰問題
將初始祕鑰 通過16輪的計算,轉換, 生成16個子祕鑰(子祕鑰長度為48位)。
而後將明文資料:
首先按照固定的置換規則, 將原資料中的64bit 進行置換。 得到新的資料。
其中置換後的資料被分為兩部分, L0、R0, L0是輸出的左32位,R0是右32位
按照一定的規則 迭代置換 運用之前計算得到的 祕鑰 加密, 16輪之後, 即得到所需的L16, R16。將兩部分合併成一個分組,進行逆置換,逆置換正好是初始置換的逆運算,由此即得到密文輸出。
其初始置換資料:
58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,
64,56,48,40,32,24,16,8,
57,49,41,33,25,17,9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7,
逆置換:
在初始置換規則表中, 觀察會發現, 原本第一位的被挪到了第40位, 而在逆置換中, 需要將第四十位置換到第一位即可。
40,8,48,16,56,24,64,32,
39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,
37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,
35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58 26,
33,1,41, 9,49,17,57,25,
正如上面所提到的:核心就是 置換,混合。 解密則是其逆過程。
3DES
3DES(即Triple DES)是DES向AES過渡的加密演算法,它使用2條56位的金鑰對資料進行三次加密。是DES的一個更安全的變形。
設Ek()和Dk()代表DES演算法的加密和解密過程,K代表DES演算法使用的金鑰,M代表明文,C代表密文
3DES加密過程為:C=Ek3(Dk2(Ek1(M)))
3DES解密過程為:M=Dk1(EK2(Dk3(C)))
即用 k1對資料加密 k2對加密過的資料解密 k3 對解密之後的資料再度加密.
K1、K2、K3決定了演算法的安全性,若三個金鑰互不相同,本質上就相當於用一個長為168位的金鑰進行加密。多年來,它在對付強力攻擊時是比較安全的。若資料對安全性要求不那麼高,K1可以等於K3。在這種情況下,金鑰的有效長度為112位。
不難發現 如果 k1=k2 的話, 與 DES演算法是等價的, 這樣有效的實現了與現有DES系統的向後相容問題。因為當K1=K2時,三重DES的效果就和原來的DES一樣,有助於逐漸推廣三重DES。
AES
- 運算速度快,在有反饋模式、無反饋模式的軟硬體中,Rijndael都表現出非常好的效能。
- 對記憶體的需求非常低,適合於受限環境。
- Rijndael 是一個分組迭代密碼, 分組長度和金鑰長度設計靈活。
- AES標準支援可變分組長度,分組長度可設定為32 位元的任意倍數,最小值為128 位元,最大值為256 位元。
- AES的金鑰長度比DES大, 它也可設定為32 位元的任意倍數,最小值為12 位元,最大值為256 位元,所以用窮舉法是不可能破解的。
- AES演算法的設計策略是WTS。WTS 是針對差分分析和線性分析提出的,可對抗差分密碼分析和線性密碼分析。
而AES的優點, 正是 DES的缺點所在。
AES的具體實現,就不再這裡提到了, 感興趣的可以看參考連結。 在本篇中, 更關注 其核心思想是什麼, 適用範圍在何處,侷限性又有哪些。
而 DES 3DES AES 其核心都是 分組, 置換, 加密混淆, 迭代。 這樣一套處理體系。
用密碼生成函式 替換了 原本固定的密碼錶。
AES參考: 密碼演算法詳解——AES
密碼塊連結
需要注意到的是, 即使我們已經擁有了很強大的對稱加密演算法,但這就能夠保證不被破解了嗎?
假設我們認為暴力破解是不可行的, 那麼在已知部分明文的情況下, 破解出密碼並不是不可能的事情, 因為在加密演算法中, 我們對於同一資料的加密結果總是相同的。而在 http傳輸中, HTTP/1.1 這必然是一個很常見的明文輸入,我們匹配了所有的輸入, 發現出現次數最多的 就可以代表其實 HTTP/1.1
考慮這樣一種情況, 在兩個人的通訊過程中,其中一個人的慣用詞彙是 你猜, 幾乎在100句聊天中, 就會出現80句以上的你猜。
那麼我們只要抓取到 出現次數最多的密文, 必然就可以認定, 這個密文所對應的明文是 你猜。這樣就能夠大大減小我們破解密碼的難度。
那麼自然的, 就要求存在這樣的方式, 使得對於相同的輸入, 其加密後的密文 是不相同的。 即使小明說了一百句你猜。 對於其表現形式來說,其密文都是不同的。
因此,根本無法從雜亂無章的密文中, 判斷出來究竟哪一句對應的明文是 小明的口頭禪, 你猜。
這怎麼實現呢?無非是在每次傳輸都附帶一串資料,僅用於本資料的加密。 這依賴的是 異或 運算。
CBC
CBC模式的全稱是Cipher Block Chaining模式(密文分組連結模式),之所以叫這個名字,是因為密文分組像鏈條一樣相互連線在一起。
明文: Mi, 密文 Ci, 加密演算法: Ks, 隨機的k 位元數: Ri, 異或運算的結果: Ti 異或運算: a⊕b
首先需要知道的是: 對於異或運算:
- a ⊕ a = 0
- a ⊕ b = b ⊕ a
- a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c
- d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c
- a ⊕ b ⊕ a = b
對於密文: Ci = Ks(Mi ⊕ Ri), 即將Mi 與 Ri執行異或運算, 通過Ks加密演算法對其進行加密, 最終得到密文 Ci。
對於解密: 根據第四條運演算法則: d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c
解密後的資料: Ti = Mi ⊕ Ri 則有 Mi = Ti ⊕ Ri, 即對密文進行解密 與 Ri做異或運算, 即可得到初始明文 Mi。
這就要求 我們對 每一個塊(在對稱加密演算法中, 正是將資料分成一個又一個的塊), 都發送相應的Ri 用於處理資料。 Ri可以明文傳送, 即使Ri被劫持到, 在沒有祕鑰的情況下, 依然是沒有用的。
但這種方式同樣會帶來一個缺點,即對於每一個塊, 我們都需要傳送等長的Ri給對方(異或預算必然要求兩者長度一樣,才能進行異或運算。) 這樣我們的資料長度就變為原來的兩倍, 這實在是一筆不小的開銷。
因此通常採用的方式是CBC, 其基本思想是, 僅隨第一個報文傳送一個隨機值, 在之後的通訊中 通過計算獲取 相應的編碼。
因此,僅需要N+1個塊, 就能夠實現 對相同的明文,產生不同的密文。
公開祕鑰加密
但在對稱祕鑰體系中, 會有這樣一個問題, 如果一切依託於現實, 我們可以彼此約定一個只有雙方知道的祕鑰, 完成加密解密的相關工作。
但在網路通訊中, 這並不現實, TCP連結時時刻刻都在被銷燬與建立中不斷迴圈, 我們不可能在路由器兩端使用固定的密碼, 如果這樣做的話 就意味著線路兩端的路由器都要完成解密 然後加密的操作。 用自己的密碼加密之後 傳送給下一個節點。
我們也不可能將密碼直接明文 在 通訊中直接傳輸, 那樣的話, 和不加密又有什麼區別呢?
這好像是個難題。
直到公開密碼的出現:
是以這樣的方式使用:
對於小B來說, 存在兩個祕鑰, 一個是 公知的 Kb+ 以及 只有自己存有的祕鑰 Kb-, 當小A想要給小B傳送訊息時, 首先會取得 Kb+ 用一個公知的 加密演算法 進行加密,得到密文 Kb+(m), 而當小B接收到 Kb+(m) 時, 用一個公知的 解密演算法 配以私鑰 Kb- 進行解密, 最終使得 Kb-(Kb+(m)) = m。 這樣需要解密密文, 就必須要兩個祕鑰才能夠解密。
雖然這樣會引入一個新的問題, 即 任何人都可以 截獲 傳送給小B的訊息, 然後用自己準備好的明文, 通過 Kb+對明文加密, 傳送給小B。
這就要求我們能夠驗證資料的來源方究竟是誰, 需要做端點鑑別, 即確確實實是小A自身傳送給小B的訊息, 而不是別人冒用名義 傳送 分手吧 這樣的悲慘訊息。
RSA演算法
對於RSA演算法, 個人比較感興趣, 在這裡描述的可能就會多一點。
對於任何資料流, 我們都不能忘記其本質 依然是 bit流, 而任何bit流 自然也能夠用 唯一的 整數 去表示。
加密這個bit流 自然實際上就是加密這個 唯一數值。
在RSA演算法中, 並沒有將資料看成是 字元的集合, 而是數值, 這樣我們就可以使用種種數學公式加以匹配。
RSA包含兩個部分:
加密解密演算法
兩個祕鑰, 公鑰和私鑰。
祕鑰的生成
- 選擇兩個大素數, 這個值越大越好, 甚至已經超出了常規意義上的 大數值。 該值越大, 破解RSA演算法越困難。 推薦公司使用時, p q 兩個數的乘積 需要 為 1024bit數量級。
- 計算 n=pq 和 z=(p - 1)(q - 1)
- 選擇小於n的一個數值 e, 且 e 和 z 互素。
求解一個數d, 使得 ed - 1 可以被 z整除。換成數值表達則是:
ed mod z = 1
則公鑰是 (n, e), 私鑰是 (n, d);
加解密過程
- 要求被加密的整數 m, m < n
- 求解 c = (m ^ e) mod n, c即是加密後的密文
- 求解 m = (c ^ d) mod n.
看上去實在是很簡單的過程。
但是 我們需要注意到的是這樣幾個問題, p q 本身就是數百bit的值。
被加密的整數一般也都不會非常小。
需要計算 m ^ e c ^ d, 這種種操作本身就是非常消耗計算力的過程。
更何況還需要求得大素數q p 本身。
工作原理
將上述 加解密過程 合併起來看:
求解m時 即是求解: ((m^e) mod n)^d mod n
在模運算中有這樣一個性質:
a ^ b mod n = ((a mod n)^b) mod n
則上述公式可以變為:
m^ed mod n
因此現在就需要證明:
m ^ ed mod n = m
在數論中, 有:
如果 p q 是素數,且有 n = pq 和 z = (p -1) * (q - 1) 則 X^y mod n = X ^ (y mod z) mod n
因此上述被替換成:
m ^ (ed mod z) mod n => m ^ 1 mod n => (m 小於 n) m
同時如果注意到另一個特點:
如果加解密流程微調:
c = (m ^ d) mod n
m = (m ^ e) mod n
原因則是: m ^ ed mod n 等價於 m ^ de mod n
這個特性意味著什麼呢?
意味著: 如果小B用自己的 私鑰 加密資料,那麼 小A 可以用 小B的公鑰進行解密, 得到原始資料。 暫時這個功能好像還看不出來什麼作用, 我們稍後再提。
RSA的大素數選擇
這同樣是一個難點. 如果不感興趣可以跳過.
參考:
RSA周邊——大素數是怎樣生成的?
數論部分第一節:素數與素性測試
RSA演算法的核心正在於 找到兩個大素數 p q 並且這個數值越大越好, 破解的難度就越高。
我們要將兩個數相乘 很簡單, 但是因式分解, 確定它是素數 又是一件很難的事情了。
慣用 也是最簡單的方法, 正是採用試除法進行處理, 即從 2 開始逐個測試, 但目前而言, 我們需要的數值有數百位, 僅僅64位的long型 9223372036854775807 已經是這樣大的一個數值, 更何況數百位?
素性測試
費馬小定理:
如果p是一個質數,而整數a不是p的倍數,則有a^(p-1)≡1(mod p)
即: a的(p-1)次方除以p的餘數恆等於1。
費馬小定理是判定一個數是否為素數的必要條件,並非充分條件,因為存在著一些偽素數滿足費馬小定理卻不是素數.
也就是說, 如果一個數是素數, 那麼必然滿足費馬小定理. 換句話說, 如果存在一個數, 不滿足費馬小定理, 此時可以斷定這個數必然不是素數.
Fermat 素性檢驗
則考慮a=2, 我們可以將選定的數用 a=2做檢驗, 如果判斷不滿足 費馬小定理. 此時必然不是素數, 比起試除法要快很多。
但遺憾的是,僅能通過不滿足來檢驗不是素數, 如果滿足我們也沒辦法確定他是素數.
因此繼續考慮a=3的情況,一個合數可能在a=2時通過了測試,但a=3時的計算結果卻排除了素數的可能。於是,人們擴充套件了偽素數的定義,稱滿足 a^(n-1) mod n = 1 的合數n叫做以a為底的偽素數(pseudoprime to base a)。
前10億個自然數中同時以2和3為底的偽素數只有1272個,這個數目不到剛才的1/4。
這告訴我們如果同時驗證a=2和a=3兩種情況,演算法出錯的概率降到了0.000025。
容易想到,選擇用來測試的a越多,演算法越準確。通常我們的做法是,隨機選擇若干個小於待測數的正整數作為底數a進行若干次測試,只要有一次沒有通過測試就可以判定這個數為合數。這就是Fermat素性測試。
人們自然會想,如果考慮了所有小於n的底數a,出錯的概率是否就可以降到0呢?遺憾的是,居然就有這樣的合數,它可以通過所有a(前提是n與a互素)的測試。Carmichael第一個發現這樣極端的偽素數,他把它們稱作Carmichael數。前10億個自然數中Carmichael數也有600個之多。這樣高的出錯率, 說明費馬素性檢驗 依然不能夠幫我們準確找到一個大素數. 依然需要加強演算法.
Miller-Rabin素性測試
基於下面的定理:
如果p是素數,x是小於p的正整數,且x^2 mod p = 1,那麼要麼x=1,要麼x=p-1。這是顯然的,因為x^2 mod p = 1相當於p能整除x^2-1,也即p能整除(x+1)(x-1)。由於p是素數,那麼只可能是x-1能被p整除(此時x=1)或x+1能被p整除(此時 x=p-1)。
以 a==2,n==341為例,演示一下該測試是如何進行的。(2^340%341==1,但是341並不是一個質數)
根據模運算的規則: a^b mod n = (a mod n)^b mod n
2 ^ 340 mod 341 = (2^170 mod 341)^2 mod 341 == 1
此時必然有: 2^170 mod 341 == 1 或 2^170 mod 341 = 340 而 2^170 mod 341 結果是等於 1的
繼續: 要求滿足: 2^85 mod 341==1 或者 2^85 mod 341 == 340 但此時 兩者都不滿足, 所以341不是素數。
所以測試的要點則是: 儘可能提取因子2, 把n-1表示成 d * 2 ^ r, 如果n是一個素數,那麼或者a ^ d mod n=1,或者存在某個i使得a ^ (d * 2 ^ i) mod n = n - 1.
但需要注意的是: Miller-Rabin 素性測試同樣是不確定演算法,我們把可以通過以a為底的Miller-Rabin測試的合數稱作以a為底的強偽素數(strong pseudoprime)。第一個以2為底的強偽素數為2047。第一個以2和3為底的強偽素數則大到1373653。
對 於大數的素性判斷,目前Miller-Rabin演算法應用最廣泛。一般底數仍然是隨機選取,但當待測數不太大時,選擇測試底數就有一些技巧了。比如,如果 被測數小於4 759 123 141,那麼只需要測試三個底數2, 7和61就足夠了。當然,你測試的越多,正確的範圍肯定也越大。如果你每次都用前7個素數(2, 3, 5, 7, 11, 13和17)進行測試,所有不超過341 550 071 728 320的數都是正確的。如果選用2, 3, 7, 61和24251作為底數,那麼10^16內唯一的強偽素數為46 856 248 255 981。這樣的一些結論使得Miller-Rabin演算法在OI中非常實用。通常認為,Miller-Rabin素性測試的正確率可以令人接受,隨機選取 k個底數進行測試演算法的失誤率大概為4^(-k)。
而 Miller-Rabin素性測試 也就是我們的終極法寶。
那麼大素數是怎麼生成的?
其實生成一個大素數非常簡單,最直觀的方法就是隨機搜尋,例如要生成一個100位的大素數,我們先隨機生成一個數字序列,然後用Miller-Rabin素性測試對其進行測試即可,如果不是素數的話再隨機生成一個,如此迴圈下去~
當然我們可以採用隨機搜尋法(每次生成一個完全不一樣的隨機數),也可以採用隨機遞增搜尋法(生成一個隨機數之後,每次對其加2)
生成一個n位十進位制大素數的步驟如下:
- 產生一個n位的隨機數p,且最高位不能為0
- 若最低位為偶數,則將它加1,保證該數為奇數以節省時間
- 測試該數能否被10000以下的素數(共1228個)整除,這樣可以快速排除許多合數,節省時間
- 在2到p-1這間隨機生成一個數a,以a為底對p進行Miller-Rabin素性測試,若不通過說明p為合數。若通過則再選取一個a對p進行測試。選取a時應該選取儘可能小的素數,以提高運算速度。大概進行5次Miller-Rabin素性測試後,精確性就比較高了
- 若p每次測試都通過,則認為p是素數。否則p←p+2,再次對p進行測試
會話祕鑰
我們已經看到了,對於對稱密碼而言,密碼本身的傳送是一個問題,再者對待千千萬萬不同的使用者, 我們需要不同的密碼去應對每一個請求。
而RSA演算法,加密起來確實無人可解, 但是運算太耗費時間, 需要的計算量是 對稱祕鑰演算法的 成百上千倍。
那麼,我們有沒有一個比較好的處理辦法能夠解決這些問題呢?
當然是將兩者結合起來使用了哇。
我們在一個會話剛剛開始時, 通過 RSA演算法 加密 祕鑰, 將祕鑰傳送給對方, 在之後的會話過程中, 使用對稱祕鑰進行會話即可。
完整性
需要驗證的是 資料未被修改過。
這就表示 對於我們的 明文, 需要有對應的資料 能夠 驗證, 確確實實沒有被變更.
密碼雜湊函式
也即雜湊函式, hash相信每個開發人員都不陌生, 但在這裡 我們對於hash的要求會更高一點:
要求對於任意兩個不同的報文, H(x) == H(y) 的概率 幾乎為0
這一點也就保證了 對於任意報文而言,通過相同的hash函式,我們幾乎不可能找到相同的報文。
MD5正是這樣這樣一個hash 函式.
SHA SHA-1 也是起到同樣的作用。
需要注意到的一點是: MD5, SHA-1 並不能夠被稱作是加密演算法。
就我個人理解來說: 凡是被加密的資料,那麼必然能夠還原回初始版本, 也即 解密, 而hash函式無疑是不具備這個特點的。
我們想要破解 hash函式 進行還原的唯一辦法是,窮舉法, 對撞。 因為對於密碼雜湊函式而言,對於不同的文字其hash值幾乎是完全不同的。那麼反過來說, 對於雜湊值必然有其唯一對應的 原始文字。
報文鑑別
對於單純的hash來說, 如果存在第三方,截獲了 A傳送的訊息, 同時自己偽造了新的訊息,並加入了新的雜湊值。偽裝成A將訊息傳送給B。
對方收到了訊息,傻傻的以為A絕情的要分手。
那麼我們就需要一種辦法, 驗證訊息確確實實是 A傳送的, 而不是來源於別人。
密令就是一個不錯的方式, 當地下黨接頭時, 可能也採用的是原始的對暗號的方式來確定對方的身份。
假定雙方已經持有一個 共享祕鑰s, 當A傳送資料時, 通過 明文 H(m + s) 生成雜湊值, 當B收到資料時, 自身已經持有s, 因此可以同樣通過 H(m + s) 驗證 資料是否是對方傳送的, 也能夠驗證資料的完整性。
而 H(m + s) 就被成為是 報文鑑別碼 (MAC).
但這就要求雙方都已經持有共享祕鑰, 在部分場景, 如 在路由器 鏈路選擇演算法中, 可以由網路管理員配置祕鑰, 以確定資料的來源.
而在伺服器和個人互動中呢? 我們如何確定共享祕鑰?
哎? 前面不是提到過會話祕鑰嗎, 這個應該就可以吧. 那麼在雙方的初次互動過程中, 又如何確定會話的物件是 你理想中的 伺服器呢? 在初次交流中, 已經偽裝成了 知心哥哥, 將祕鑰發給你, 無礙交流, 最終才發現這是又一次殘忍的欺騙.
數字簽名
看來MAC已經沒有辦法幫助我們阻擋壞人了. 那麼該怎麼辦呢?
帶數字簽名的資料報文 是面向大眾的, 就意味著任何一個人都可能要驗證資料簽名的準確性(這也意味著, 只要通過認證, 那麼我就可以確定你是我心目中的那個人.), 因此其祕鑰是周知的, 但既然是周知的, 就意味著可能會有第三方用同樣的方式, 用祕鑰生成簽名, 做以偽裝, 且無法鑑別.
這就依賴一個很有趣的特性了.
還記得在RSA 公開祕鑰演算法原理中的一個特性嗎?
c = (m ^ e) mod n
m = (m ^ d) mod n;
c = (m ^ d) mod n
m = (m ^ e) mod n;
這兩種方式是等價的嗎? 都能夠求出來最終的明文.
在需要進行數字簽名時, 即用A的私鑰簽署明文 m, 這樣唯有在明文沒有被篡改的情況下, 持有公鑰即可驗證 報文的 源, 以及報文完整性.
但僅僅是這樣還不夠好, 我們知道RSA計算對資源的消耗時相當大的, 當資料越多 消耗自然也就越大.
因此, 此時加密我們並非加密明文, 而是 加密明文對應的 雜湊值. 這樣 加密所需要的計算量會大大減小.
公鑰認證
就數字簽名的形成還有問題嗎?
有.
問題在於公鑰, 我們如何得到對方的 可信的 公鑰?
如果不能夠確定公鑰的準確性, 那麼依然會存在第三方偽造資訊的可能性.
這就需要一個第三方權威機構來做這件事情, 將公鑰與某一機構繫結 通常是由 CA(Certificate Authority)完成. 而一旦CA認證了某個實體的身份, 就會生成一個相應的證書, 證書中包含了 公鑰 以及 實體的唯一標識.
端點鑑別
也即如何證明你是你, 我是我的一個過程.
最簡單的方式, 莫過於告訴你, 我是誰, 然後你就傻傻的相信就好.
如果我們是熟悉的陌生人, 那麼我去驗證資料來源所屬的IP地址 是否是你的地址也不失為一種確定 你是你的 方式. 這種問題在於, IP地址是可以偽造的.
更近一步的方式, 我們不是有祕鑰嗎? 先傳輸祕鑰, 然後再...
等等, 祕鑰怎麼傳輸? 如果是會話祕鑰, 通過RSA傳輸的先決條件是, 對方持有你的 公鑰. 如果明文傳輸, emmm 太可怕了還是不要想.
那麼我們通過CA獲取 公鑰不就可以了麼? 雙方都經過認證. 這樣就一定可以確定 雙方身份了吧.
NONONO!道高一尺, 魔高一丈.
有一種攻擊手法叫 回放. 今天你轉了 200塊給我, 雖然資料已經加密, 身份已經確定, 此時 第三方 偷偷記錄你們的交流資訊, 雖然都看不懂, 無法解讀, 但這不重要, 在第二天, 按照順序將資料原原本本的再發送一遍. 在伺服器端看來, 一切都很正常, 對資料的加密, 解讀 都完美無誤, 然而, 你會驚訝的發現, 有人偷了你的兩百塊.
不重數是解決上述問題的一個好辦法. 不重數是在一個協議生存週期只 使用一次的數值. 當雙方開始通訊, 通過 RSA加密會話祕鑰, 使用會話祕鑰開始通訊的時候, 首先 伺服器傳送 明文 不重數 給客戶端, 客戶端使用會話祕鑰 加密 再發送回來. 服務端進行驗證. 確定對方是活躍狀態.
SSL
網路安全的技術手段, 從 機密性 完整性 到 端點鑑別都已經有所涉獵.
而現在幾乎已經成為瀏覽器強制標準的 HTTPS 也正是這種種手段的綜合運用. 也即SSL技術.
SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security, TLS)是為網路通訊提供安全及資料完整性的一種安全協議.
那麼久以上三部分來看, 如果不使用SSL會出現什麼問題呢?
在沒有機密性的前提下, 賬號密碼 這一類的東西只能夠通過明文傳輸, 如果有人獲取到了你向伺服器提交的請求, 那麼你的賬號安全問題就會受到威脅.
不要說base64, md5等演算法. 避免不了核心問題. 在網路傳輸中, 只需要瞭解你的明文是多少, 而不需要知道明文的真正含義, 就已經可以完成種種不可告人的目的了.
缺失了完整性, 報文會被別人修改, 重新發送給對方, 比如你在淘寶上本來買了一顆蘋果, 最終卻收到了一臺洗衣機. 畢竟獲取你的 RSA的公鑰是可被獲取的.
缺失了端點鑑別, 很有可能別人會利用重放攻擊, 向伺服器再次模擬你的請求流程, 重複購買你已經買過的東西.
SSL是處在傳輸層的服務, 因此它能夠使得任何基於TCP的服務安全性得到保障.
巨集觀描述
握手
- 建立TCP連結
- 在TCP連結建立以後, 客戶端向伺服器傳送hello報文, 伺服器用其證書進行響應, 證書中有其公鑰. 驗證伺服器的真實性.
- 傳送給伺服器主祕鑰, 即用 伺服器的公鑰進行加密, 將祕鑰傳送給伺服器, 在以後的通話中即使用會話祕鑰.
金鑰匯出
但金鑰並非只用一個, 對於MAC祕鑰, 會話金鑰, 從伺服器到客戶端, 以及從客戶端到伺服器,採用的是不同的祕鑰.
傳輸
但僅僅這樣就能夠使得傳輸不出現問題了嗎? 並不是, 如果存在中間人, 僅僅是在傳輸的過程中對次序進行顛倒, 調整. 這樣在伺服器端檢驗是發現不了任何問題的.
我們知道TCP報文是有序號的, 這也不能夠防止亂序嗎?
但需要知道的地方是, 加密的僅僅是從應用層傳輸下來的資料報, 而TCP自身的序號仍然是未經過加密的, 因此只需要修改TCP序號即可完成.
而處理的辦法則是, 並非在資料中實際的包含一個欄位, 而是在計算MAC的時候, 將序號納入資料 進行計算.
SSL記錄
- 型別, 用於指定該欄位是握手報文, 還是包含應用資料的報文, 關閉SSL連結也使用此報文
- 版本, 自解釋
- 長度
- 資料
- MAC (其中4, 5 會整體進行加密)
完整描述
在SSL中並沒有強制性的要求雙方究竟使用哪一種加密演算法, 無論是對稱祕鑰演算法還是公開祕鑰演算法, 又或者是某一種特定的MAC.
真正的握手階段如下:
- 客戶端傳送它自身支援的密碼演算法列表, 連同客戶的一個不重數.
伺服器選擇演算法, 即 MAC, 公開金鑰演算法, 對稱演算法. 將選擇, 自身證書, 自身的不重數返回給客戶.
由於雙向認證需求,服務端需要對客戶端進行認證,會同時傳送一個 client certificate request, 表示請求客戶端的證書;
- 客戶端驗證證書, 提取公鑰, 生成一個前主祕鑰(PMS), 之後用 公鑰加密PMS, 將PMS傳送給伺服器.
使用相同的祕鑰匯出函式, 客戶端與伺服器獨立地從 PMS中計算出 相應的 主祕鑰(MS),
之後該MS被切片生成所需要的四個密碼(兩個會話祕鑰, 兩個MAC祕鑰)由於服務端發起了 client certificate request, 客戶端將戶端的證書 clientCA一併發出;
- 客戶端傳送所有握手報文的MAC
伺服器傳送所有握手報文的MAC
而之所以在56步要做這樣的處理 是因為, 在傳送密碼演算法列表的時候, 此時雙方還沒有生成 交換密碼, 是以明文傳送的, 如果第三方從其中 刪除掉了 較強的 加密演算法, 就能夠達成自身不可告人的目的. 大大減低破解難度.
- 結束SSL連線時, 在TCP原版中, 是直接傳送 TCP FIN即可結束當前會話. 而在SSL中, 加入了型別欄位, 指示當前型別為 結束會話, 雖然 型別本身為明文傳送, 但是在 計算MAC時, 會使用型別計算MAC.
擴充套件閱讀: HTTPS、SSL、TLS三者之間的聯絡和區別
擴充套件:
參考: 圖解SSH原理
通過以上介紹, 很容易聯想到一個問題, 即我們常常會使用的git, 使用git時即需要通過 生成自己的公鑰, 私鑰, 同時將公鑰儲存在git伺服器中, 以完成我們的提交工作. 這裡即使 會話祕鑰, 非對稱公開祕鑰的聯合使用. 總算不用對著 git的操作流程, 一臉懵逼.
網路安全的保障
有這樣多可以被攻擊的手段, 並且在之前僅僅只是提到了擷取資料, 修改報文等操作, 還有更多的攻擊, 並不想要竊取你的資料, 各種各樣的病毒, 通過計算機的種種漏洞侵入到你的裝置, 控制電腦. 又或是攻擊伺服器, 致使伺服器癱瘓.
因此, 需要能夠對進入計算機的任何外來資料都做以校驗, 攔截, 才能夠有效阻止邪惡勢力的入侵.
防火牆
所謂“防火牆”是指一種將 內部網和公眾訪問網(如Internet) 分開的方法,它實際上是一種建立在現代通訊網路技術和資訊保安技術基礎上的應用性安全技術,隔離技術。越來越多地應用於專用網路與公用網路的互聯環境之中,尤其以接入Internet網路為最甚。
防火牆代主要是藉助 硬體和軟體 的作用於內部和外部網路的環境間產生一種保護的屏障,從而實現對計算機不安全網路因素的阻斷。
防火牆是在兩個網路通訊時執行的一種訪問控制尺度,能最大限度阻止網路中的黑客訪問你的網路。是指設定在不同網路(如可信任的企業內部網和不可信的公共網)或網路安全域之間的一系列部件的組合。它是不同網路或網路安全域之間資訊的唯一出入口,能根據企業的安全政策控制(允許、拒絕、監測)出入網路的資訊流,且本身具有較強的抗攻擊能力。它是提供資訊保安服務,實現網路和資訊保安的基礎設施。
防火牆具有三個目標:
從外部到內部, 以及從內向外的所有流量都需要通過防火牆
僅允許被授權的流量通過防火牆
防火牆自身需要免於滲透. 最堅固的堡壘往往是從內部被攻破.
防火牆分為三類:
傳統的分組過濾器
一個機構往往有將其內部網路 與 ISP相關聯的閘道器路由器, 所有的流量無論進出都需要通過這個伺服器, 因此它也自然承載了 分組過濾的 功能.
過濾規則一般有如下幾種方式:
- Ip源地址, 目的地址
- 協議型別欄位: TCP UDP
- TCP UDP 源, 目的埠
- TCP 的標誌bit, SYN, ACK
- ICMP報文型別
- 進出網路採取不同的規則
- 不同的路由器採取不同的規則
狀態分組過濾器
這是基於 TCP連線的相關知識進行攔截, 防火牆能夠觀測TCP連線的三次握手, 將通過三次握手的連線記錄在一張表 , 如果收到了 TCP FIN 或 超過 60s未活躍, 則認為當前連線已經結束, 從表中刪除.
正是通過這種方式, 阻攔所有的外部惡意請求, 即通過外界主動向內傳送資料的. 因為此時必然不在表中.
應用程式閘道器
如果需要進行內部使用者受限的操作又該如何呢?
在前面所提到的兩種策略中, 並不能夠探測到應用層的資料, 即不能夠對特定應用的 特定使用者 進行區分限流.
應用程式閘道器, 是特定應用程式的伺服器, 所有應用程式相關的資料都必須通過它. 如telnet伺服器, 所有使用者在向外界訪問時, 必須輸入自身的使用者名稱密碼, 如果校驗不通過, 即不能夠進行訪問. 這正是因為 應用程式閘道器將自身當做伺服器, 讀取了來自客戶端的資料, 從而決定是否擁有訪問許可權, 當校驗通過後, 又將自身當做客戶端, 向真正的伺服器發起請求, 獲取資料.
而缺點也是比較明顯的, 每個應用程式都需要對應的閘道器伺服器, 其次所有的資料都需要代為轉發, 當用戶 和 應用程式數量一旦上來, 對效能是個較大的考驗. 最後 , 不僅是客戶需要知道如何連線到閘道器伺服器, 伺服器也需要知道 如何連線到哪一個外部伺服器.
在防火牆的描述中, 我們會發現依然有侷限性, 並不能夠在執行分組過濾的同時 檢測應用層資料, 否則就需要應用程閘道器來作為中介.
我們需要一種能夠結合兩者特點的, 且並非只是針對特定的應用程式.
當裝置觀測到可疑流量, 可疑分組時, 需要向網路管理員發出警告. 能夠觀測到潛在惡意流量時產生告警的裝置 被稱為 入侵檢測系統(IDS), 濾除可疑流量的裝置被稱為 入侵防止系統(IPS).
至於更多的就不多做介紹.
總結
從最簡單的代替密碼. 當我們將密碼本進一步擴充套件, 且根據文字所處的不同位置採用不同的密碼本 就成了多碼代替, 進一步擴充套件, 我們將密碼本換成了 初始密碼 與 密碼函式的組合 就變成了 對稱祕鑰的基本雛形. 但對稱密碼不利於在網路傳輸中直接使用, 因此 公開祕鑰體系應運而生.
相應的, 為了驗證報文的完整性, 就需要 MD5, SHA-1這樣演算法 來將報文轉換成 對應的 hash值. 驗證文字與hash值的一致性即可. 由於存在可能性是將整個報文直接替換, 而非修改 生成新的 報文與hash值, 因此需要將 報文與共享祕鑰 合併 生成MAC 加以驗證資料來源.
但這依然不夠, 對於伺服器需要面對的群體物件實在太多, 很難實現和每個人都共享對應的祕鑰, 倒不如將自身的公鑰公開, 通過私鑰加密報文的hash值, 就變成了數字簽名, 客戶端只需要通過權威機構獲取其證書, 即可解析公鑰, 完成解密驗證過程.
通過同樣的方式, 我們也能夠完成 驗證 你是你(即端點鑑別)的這樣一個過程.
為了防止別人竊取到伺服器與客戶端的聊天記錄, 在第二天進行回放操作, 因此又有了不重數做以補充.
然而我們在一段會話中 不可能全部使用 RSA進行加密, 代價太過高昂, 因此通過RSA加密一段 對稱祕鑰, 用於會話中. 這即是 會話祕鑰.
而SSL SSH等 則是對上述種種技術的綜合運用.
防火牆的主要功用是, 通過分組過濾, 分組檢測等功能, 阻止惡意入侵.
網路安全中心最重要的幾個板塊.
機密性, 完整性, 端點鑑別, 執行時安全 即如是.