我的一直在努力推進git在公司內部的普及和使用,前些日子在公司內部作了一次分享課,給你們介紹了下項目發佈流程相關的內容,順便普及了一些git的相關知識。對git是什麼,以及怎樣配置和使用它作了一些說明。但過後,不少同事的反饋,讓我意識到他們不少人都卡在ssh免密鑰登陸的配置上。咱們常說,學習一個新的東西應該遵循3W1H法則--WAHT(是什麼),WHEN(何時用),HOW(怎樣用)和 WHY(爲何這樣用)。我想你們應該是由於不知道爲何這樣用,因此纔會感到困惑。恰好,最近也在整理「使用Python相關模塊進行數據加密」的文檔,須要作些理論性的鋪墊,因此纔想寫這篇文章,但願對你們有所幫助。html
另外須要說明的是,網絡安全涉及不少方面的不少內容,本文只是針對網絡數據傳輸過程當中的安全性發表一下我的認識和見解。若是描述的有什麼不妥之處,歡迎你們留言交流和指正。git
咱們說的數據加密與解密一般是爲了保證數據在網絡傳輸過程當中的安全性。在網絡發展初期,網絡的數據安全性是沒有被足夠的重視的。事實上,當時爲了實現數據能夠經過網絡進行傳輸已經耗費了科學家大部分男細胞,所以在TCP/IP協議設計的初期,他們也實在沒有太多精力去過多考慮數據在網絡傳輸過程當中可能存在的安全性問題。隨着TCP/IP協議及相關技術的日漸成熟,網絡數據傳輸技術愈來愈穩定,人們才慢慢開始重視這個問題,美國國家標準與技術研究院(National Institue of Standard and Technology,簡稱NIST)也開始制定相關的安全標準。算法
網絡安全涉及到不少個方面,咱們這裏僅僅討論下網絡數據傳輸過程當中可能受到的威脅,其中常見的有:瀏覽器
針對以上威脅,咱們介紹下網絡數據傳輸的安全性涉及的幾個方面:安全
機密性是指對要傳輸的數據進行加密和解密,防止第三方看到通訊數據的明文內容。其對應的通訊過程以下:服務器
數據發送方:網絡
plaintext(明文) ==> 轉換算法 ==> ciphertext(密文)
數據接收方:ssh
ciphertext(密文) ==> 轉換算法 ==> plaintext(明文)
數據完整性是指不容許數據在傳輸過程當中被修改(第三方惡意篡改或電平信號形成的部分數據丟失),可是它不要求數據的機密性,也就是說容許其餘人看到明文數據。咱們一般經過以不可逆的算法對數據提取特徵碼(也叫數據指紋),經過驗證特徵碼的一致性來判斷數據是否被修改過,通訊過程以下:post
數據發送發:性能
plaintext(明文) ==> 轉換算法 ==> plaintext(明文) + footprint(數據指紋A)
數據接收方:
plaintext(明文) + footprint(數據指紋A) ==> 轉換算法 ==> footprint(數據指紋B) ==> 對比數據指紋A與B是否一致
身份驗證一般是指數據接收方須要確認發送數據給本身的數據是本身想要通訊的那一方,防止他人冒充通訊對方的身份進行通訊。身份驗證的大致原理是:數據發送方與數據接收方約定一種特殊的數據加解密方式,數據發送方將一個經過約定的加密方式進行加密後的數據發送給數據接收方,數據接收方如能按照約定的加密方式正確解密該數據就表示對數據發送方的身份驗證成功。其對應的通訊過程以下:
數據發送方:
plaintext(明文) ==> 轉換算法 ==> ciphertext(密文)
數據接收方:
ciphertext(密文) ==> 轉換算法 ==> plaintext(明文)
上面提到的網絡數據傳輸所涉及到的幾個方面都須要特定的轉換算法來實現,經常使用的轉換算法(數據加密/解密算法)大致上能夠分爲如下幾類:
對稱加密是指數據加密與解密使用相同的密鑰。
一般用於保證數據的機密性。
須要說明的是,祕鑰長度越長,數據加密與解密的時間就越久。
單向加密是指只能對明文數據進行加密,而不能解密數據。
一般用於保證數據的完整性。
可能出現中間人攻擊,中間人能夠對原始內容進行修改以後從新生成數據指紋,數據接收方驗證數據指紋時會發現數據是正常的。此時,數據發送方只能把生成的數據指紋進行加密後再發送給數據接收方,那麼問題就又回到了加密密鑰的傳輸和管理上。
公鑰加密,也被稱做非對稱加密,也就是說加密和解密所使用的密鑰是不一樣的。
一般用於保證身份驗證。
咱們發現公鑰加密「貌似」已經解決了密鑰管理的問題--全部人只須要知道本身的那一對兒密鑰便可,須要跟誰通訊就去獲取對方的公鑰,而後經過這個公鑰對數據進行加密和機密就能夠了。咱們能夠用它來完成如下兩件事情:
事實上,公鑰加密算法不多用於數據加密,它一般只是用來作身份認證,由於它的密鑰太長,加密速度太慢--公鑰加密算法的速度甚至比對稱加密算法的速度慢上3個數量級(1000倍)。
實際上,已經存在一種專門用於祕鑰交換的算法--Diffie-Hellman加密算法。該加密算法自己僅限於祕鑰的交換用途,被許多商用產品用做祕鑰交換技術。這種祕鑰交換技術的目的在於使得兩個用戶安全的交換一個密鑰,以便用於以後的數據對稱加密。也就是說,通訊雙方能夠經過這個技術,動態的協商生成一個用於對稱加密的密鑰,而不用管理不少靜態的密鑰,這樣就解決了密鑰的管理問題。
須要說明的是,在經過祕鑰交互技術動態協商生成密鑰以前,一般須要先經過公鑰加密算法對對方的身份進行驗證。實際上,https就是這樣工做的。
公鑰實際上也是一段文本,驗證公鑰的合法性涉及到兩個方面:
其實,這個已經不是靠純技術能解決的問題了,這須要藉助一些機構和人爲約定來解決。常見的解決方案有兩種:
咱們常見的對於上面這些加密算法的經典應用就是ssh和https了,它們都是使用這些加密算法實現的網絡協議。下面咱們對ssh和https的工做原理進行下介紹,一方面當作上面這些加密算法的實例講解,幫助你們瞭解這些算法的經典應用;另外一方面,也幫助你們更深刻的理解ssh和https是什麼,以及它們是怎樣工做的。
簡單來講,SSH就是一種網絡協議,主要用於計算機之間的加密登陸與數據傳輸,使用方式以下:
# ssh user@host
表示要以user這個用戶的身份登陸host這臺網絡機器。也能夠省略前面的user,這樣來用ssh host
,表示以當前本地登陸的用戶名登陸host這臺網絡機器。
早期,人們主要是經過telnet協議進行計算機之間的登陸操做,可是它有一個很嚴重的安全隱患就是「數據是明文傳輸的」,登陸時傳輸的包括用戶名和密碼在內的全部信息都有可能會被惡意攔截而暴露。而SSH則是將登陸信息所有加密後進行傳輸的,所以使用SSH進行登陸時安全的,即便數據在傳輸過程當中被截獲,裏面的密碼已經被加密而不會泄露。
如今SSH做爲互聯網安全的一個基本解決方案,已經在全世界得到推廣,且目前已經成爲Linux系統的標準配置。須要說明的是,SSH只是一種協議,它有多種軟件實現,既有商業的,也有開源的。OpenSSH是當前使用最爲普遍的一個SSH協議的開源實現。
其實SSH是充分利用了公鑰加密/非對稱機密 、對稱加密 和 單向加密 來實現數據安全登陸的。在使用SSH進行通訊時,通訊過程分爲如下幾個步驟:
下面來看具體解析。
上面提到,SSH是經過對數據進行加密後進行傳輸來保證數據安全的。可是,SSH的數據加密採用的是對稱加密算法,只是對稱加密所使用的密鑰是經過公鑰加密/非對稱加密實現加密後的安全傳輸的。另外,每臺Linux機器都有本身的密鑰對兒(一般放在/etc/ssh目錄下),這個密鑰對兒跟具體的用戶無關。其工做流程是:
這樣即使有人結果了帳號密碼信息,也是密文信息,並不能知道里面是什麼內容。貌似已經OK了,可是,主機A怎麼驗證主機B的身份呢?若是有主機C冒充主機B截獲了登陸請求,將本身僞造的公鑰發送給主機A,怎麼辦?儘管信息是加密過的,通訊過程也是合法的,可是通訊信息都被主機C截獲了,其實這就是所謂的「中間人攻擊」(Man-in-the-middle attack)。其實,對主機B進行驗證就是對主機B發送過來的公鑰的合法性進行驗證的過程。
上面咱們提到過,驗證公鑰的合法性有兩種方式:
SSH主要用於機器之間的安全登陸,所以一般不會經過權威的機構去簽發證書,它主要是經過驗證數據指紋的方式來驗證公鑰的合法性的。公鑰的合法性驗證是發生在主機A接收到主機B發送的公鑰以後,主機A向主機B協商產生會話密鑰以前,也就是上個部分所列舉的數據機密時間的第2個步驟和第3個步驟之間。具體的工做流程以下:
每一個用戶都有本身的kown_hosts文件,它們是相互獨立的。咱們也能夠爲全部用戶保存一份公共的可信賴的遠程主機的公鑰,這個文件一般是/etc/ssh/ssh_known_hosts。
當機器A接收到機器B的公鑰指紋時,發現knowns_hosts文件中雖然有機器B的公鑰,可是計算得出的公鑰指紋與機器B發送過來的公鑰指紋不一致。這確定是不一致的,由於每臺機器的密鑰對都是隨機生成的,幾乎不可能出現重複。所以,咱們會看到以下提示信息:
上面的大概意思是,主機A發現主機B的公鑰指紋對不上了,懷疑咱們正在遭受中間人攻擊(即有人在冒充主機B),而且密碼驗證方式和鍵盤交互驗證方式都被禁止使用了。其實,咱們本身知道是由於IP被綁定到其餘機器上引發的這個問題,因此咱們若是想繼續登陸新的主機B,只須要在.ssh/known_hosts文件中把原來保存的主機B的公鑰刪掉就能夠了。
你們都知道,SSH免密鑰登陸是經過公鑰認證的,用戶登陸時只須要提供用戶名,而不須要輸入密碼。其實其優勢不止這一個,咱們來總結下:
其實登陸的過程就是被登陸端對登陸用戶進行「身份驗證」的過程,前面是經過帳號和密碼來驗證用戶身份,由於密碼應該只有該帳號的擁有者才知道。而咱們知道公鑰加密算法中,用公鑰加密的數據只能由與其配對的私鑰才能解密,而私鑰只有用戶本身才有。那麼,咱們是否能夠經過這種方式來驗證用戶身份呢?實際上SSH免密鑰登陸就是這樣的原理。好比,咱們想在主機A上以root用戶以SSH免密鑰的方式登陸主機B,登陸驗證過程是這樣的:
root@192.168.1.2
),發送的信息包括用戶名root和root的公鑰指紋,且全部信息都是經過會話密鑰加密過的。那麼主機A是怎樣獲取root用戶的私鑰的呢?主機B又是怎樣獲取root用戶的公鑰的呢? 這個就是實現SSH免密鑰登陸所要配置的內容:
ssh-keygen
命令生成一個ssh密鑰對兒,一路回車就能夠;生成的密鑰對兒默認保存在當前登陸用戶家目錄下的.ssh目錄,也能夠指定保存目錄。咱們當前是以root用戶登陸,所以是保存在/root/.ssh目錄:ssh root@hostB
進行登陸時,主機A會嘗試讀取登陸用戶的家目錄下的私鑰文件(這裏是以root用戶登陸主機B,所以主機A會讀取/root/.ssh/id_rsa文件做爲私鑰),也能夠經過-i選項指定要使用的私鑰文件;ssh-copy-id root@hostB
命令直接完成這個操做,也能夠經過複製粘貼的方式來完成;咱們在管理git倉庫中的項目時,可使用http/https協議,也可使用ssh協議來管理咱們的項目代碼:
http/https協議:
http://192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git https://192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git
ssh協議:
ssh://git@192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git
不管使用http/https協議仍是ssh協議來管理項目倉庫,對於非公開的倉庫都是須要進行登陸(即帳戶身份驗證)的。若是咱們使用http/https協議的話,就須要提供用戶名和密碼進行驗證;若是咱們使用ssh協議的話,就能夠把咱們公鑰保存到項目倉庫機器的指定位置,來經過非對稱加密的方式進行身份驗證,驗證的原理上面已經詳細說明過了。
HTTPS實際上就是HTTP協議和SSL/TSL協議的組合,能夠把HTTPS大體理解爲「HTTP over SSL」或「HTTP over TSL」。關於它們的相關介紹,能夠參考這篇文章。對於HTTPS咱們應該有如下幾個認知:
那麼使用HTTPS與網站服務器進行交互的流程和原理究竟是怎樣的呢?讓咱們先以逆向思考的方式來進行說明:
咱們說過,公鑰加密/非對稱加密方式雖然安全,可是因爲密鑰過長,加密和解密速度都遠遠低於對稱加密。所以,出於對性能方面的考慮,HTTPS並非把全部傳輸的數據都使用公鑰加密的方式進行機密性的保護,而是繼續使用對稱加密的方式來加密數據。還有一個緣由就是,使用公鑰機密算法來保證數據機密性的話,須要通訊雙方都要有密鑰對兒,不然總有一方發出的數據是能被對方公佈的公鑰解密的。
既然時使用對稱加密的方式加密數據,就須要有一個通訊雙方都知道的加解密所使用的密鑰。HTTPS是經過上面提到的密鑰交換技術來動態協商這個密鑰的,實際上就是由客戶端生成一個隨機密鑰,而後發送給服務器端,這樣就解決了密鑰的管理問題。
既然說HTTPS是安全的,那麼客戶端生成的這個隨機密鑰確定不能以明文的方式發送給服務器端啊。是的,當客戶端以https的方式訪問一個站點時,該站點會自動下發其公鑰信息。客戶端會使用這個公鑰對產生的隨機密鑰進行加密,而後傳送給服務器端。服務器端以本身的私鑰對這個密文進行解密,而後獲得這個密鑰的明文內容。至此,客戶端與服務端用於對稱加密和解密的密鑰協商與傳輸工做已經安全的完成了。
那麼要經過網絡獲取服務器端的公鑰信息,那麼怎麼驗證該公鑰信息的合法性呢?咱們上面說過,不是全部問題都能依賴技術來解決的。這裏要驗證公鑰信息的合法性就要依靠CA證書籤發機構了,網站服務的提供者必須找一個你們都信任的機構來對他提供的公鑰進行簽名,用戶獲得一個網站下發的公鑰後看到有這個機構的簽名就認爲這個公鑰是合法的,是可信賴的。
那麼CA機構的簽名要以什麼樣的形式來提供呢?實際上網站服務器下發給客戶端(一般是瀏覽器)的公鑰已經不只僅是密鑰對兒中公鑰的內容了,而是包含了證書籤發機構寫入的其餘信息的CA證書。這個CA證書中包括證書籤發機構的標識和公鑰的數據指紋,固然還有包含網站服務提供者的公鑰信息以及證書到期時間等等。可是,咱們前面提到過,單向加密只能保證數據的完整性,不能保證數據機密性。CA證書的僞造者徹底能夠僞造公鑰信息並生成相應的數據指紋,而後發送給用戶。那麼如今的問題就變成了要驗證CA證書中公鑰的合法性以及CA證書提供者的身份了。貌似問題只是轉移了,而沒有被解決。
其實每一個CA證書的簽發機構也都有本身的密鑰對兒,他們放在CA證書中的公鑰的數據指紋時經過本身的私鑰加密過的,而這些CA證書籤發機構的公鑰是被各瀏覽器廠商內置在瀏覽器內部的。當瀏覽器接收到某網站服務器下發的CA證書後會根據CA證書中籤發機構的標識來讀取瀏覽器內置的相應CA簽發機構的公鑰信息,經過這個公鑰信息對公鑰數據指紋的密文進行解密就能夠獲得CA證書中包含的公鑰信息的真實數據指紋。瀏覽器再經過單向加密的方式本身計算一次CA證書中包含的公鑰信息的數據指紋,兩個數據指紋一致則說明這個CA證書確實是該CA機構簽發的,同時也證實了CA證書中的公鑰信息沒有被篡改過。至此,全部的問題就都解決了。
如今咱們再來以正常的順序描述一下使用HTTPS與網站服務器進行交互的過程: