主頁 > 軟體設計 > 哈希函式(Hash Functions - 散列函式)的基本介紹(SHA-2,SHA-256,MD-5,Scrypt,BCrypt等)

哈希函式(Hash Functions - 散列函式)的基本介紹(SHA-2,SHA-256,MD-5,Scrypt,BCrypt等)

2020-10-13 03:02:29 軟體設計

Table of Contents

哈希函式的基本介紹(SHA-256,MD-5等)

為什么要使用哈希函式?

確定性地加擾資料

輸入無關緊要,輸出大小相同

它們如何作業?

免責宣告

什么是MD5哈希?

SHA-2的作業原理(SHA-256)

什么是哈希函式?

SHA-2和SHA-256

SHA-256“ hello world”;步驟1 –預處理

步驟2 –初始化哈希值(h)

步驟3 –初始化舍入常數(k)

步驟4 –區塊回圈

步驟5 –建立郵件時間表(w)

步驟6 –壓縮

步驟7 –修改最終值

第8步-連接最終哈希

偽碼

Scrypt哈希的基本介紹

什么是Scrypt?

為什么不使用密碼直接加密?

加密屬性

什么是BCrypt?

OWASP - 開放式Web應用程式安全專案

相關文章


Hash,一般翻譯做散列、雜湊,或音譯為哈希,是把任意長度的輸入(又叫做預映射pre-image)通過散列演算法變換成固定長度的輸出,該輸出就是散列值,這種轉換是一種壓縮映射,也就是,散列值的空間通常遠小于輸入的空間,不同的輸入可能會散列成相同的輸出,所以不可能從散列值來確定唯一的輸入值,簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式,

哈希函式根據選擇的演算法回傳輸入資料的128位,160位,256位或512位哈希,

表示要散列的字串值的運算式,該運算式可以回傳任何內置或不同的資料型別,唯一型別被視為其源資料型別,如果值為數字或日期時間,則在評估函式之前,將其隱式轉換為VARCHAR,如果值為XML,則在對函式求值之前執行隱式的XMLSERIALIZE到CLOB(2G)CCSID 1208,

表1.哈希演算法
功能名稱演算法結果大小回傳值數結果長度HASH函式中使用的對應演算法值
HASH_MD5MD5128位2^128160
HASH_SHA1SHA1160位2^160201
HASH_SHA256SHA-256256位2^256322
HASH_SHA512SHA-512512位2^512643

空格會影響哈希;帶有尾隨空格的固定長度字串將產生與沒有尾隨空格的可變長度字串不同的結果,運算式的CCSID 可以使比較相等的字串生成不同的結果值,

SHA1和MD5演算法均已發現安全漏洞,您可以在適用的法規遵從性檔案中找到可接受的哈希演算法,例如美國國家標準技術研究院(NIST)特殊出版物800-131A,

語法替代:具有單個引數的HASH函式類似于HASH_MD5,可以為HASH指定第二個引數,以指示要使用的演算法,演算法值顯示在表1中,第二個引數可以是一個運算式,該運算式必須回傳任何內置數字,字串或圖形字串資料型別的值,在評估函式之前,將字串引數轉換為整數,HASH的結果資料型別為VARBINARY,如果只有一個引數,則結果的length屬性為16,如果第二個引數由整數常量指定,則結果的length屬性為表1中所示的結果長度,,否則,結果的length屬性為64,如果任一引數可以為null,則結果可以為null,如果任何一個引數為null,則結果為null值,

例子

使用MD5演算法生成哈希資料,

VALUES HEX(HASH_MD5('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

回傳以下值:

5156BECBC019E3F0F9520B143435427E

使用SHA1演算法生成哈希資料,

VALUES HEX(HASH_SHA1('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

回傳以下值:

55324E3DD1FA95040F65709D193E82575237EF86

使用SHA-256演算法生成哈希資料,

VALUES HEX(HASH_SHA256('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

回傳以下值:

011F7AD1ECD8E5A4CC8533D1ECD497DC5D95E848B14F8BCFD56A73D7F41843E2

使用SHA-512演算法生成哈希資料,

VALUES HEX(HASH_SHA512('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

回傳以下值:

D8AC4B838921A83C4207B62B8B63628F8FBE836EB012167310331FFC070FC977D224F39148
  8806CB1FE2AA9C8C739E5104CAD1C4C6E97967DA6223D657CD9295

哈希函式的基本介紹(SHA-256,MD-5等)

https://dev.to/wagslane/very-basic-intro-to-hash-functions-sha-256-md-5-etc-399j


這將是哈希函式的基本介紹,我將假定我的大多數讀者都在這里,以了解為什么使用哈希函式以及它們為什么起作用的基本概念,我的目標是從一般意義上解釋它,我將省略證明和實作細節,而將重點放在高級原則上,

為什么要使用哈希函式?

哈希函式在整個Internet上使用,以安全地存盤密碼,查找重復記錄,快速存盤和檢索資料等等,例如,Qvault使用哈希將主密碼擴展為專用加密密鑰,

  1. https://en.wikipedia.org/wiki/Hash\_function#Uses
  2. https://en.wikipedia.org/wiki/Hash_function#Uses

我想關注散列函式的幾個重要功能,可以說是最重要的功能,

  • 哈希函式確定性地加擾資料
  • 無論輸入如何,哈希函式的輸出始終具有相同的大小
  • 無法從加擾資料中檢索原始資料(單向功能)

確定性地加擾資料

想想一個魔方,

我從無雜亂無章的多維資料集開始,如果我開始隨機扭曲,到最后,我將得到的東西與我剛開始的東西幾乎沒有任何相似之處,另外,如果我要重新開始并做完全相同的一系列動作,我將能夠反復獲得完全相同的結果,即使結果may_出現_random,也完全不是,這就是確定性*的意思,

確定性對于安全存盤密碼很重要,例如,假設我的密碼是“ iLoveBitcoin”

我可以使用哈希函式對其進行加擾:

iLoveBitcoin→“ 2f5sfsdfs5s1fsfsdf98ss4f84sfs6d5fs2d1fdf15”

現在,如果有人要查看加密版本,他們將不知道我的原始密碼!這很重要,因為這意味著作為網站開發人員,我只需要存盤用戶密碼的哈希(加密資料)即可進行驗證,當用戶注冊時,我對密碼進行哈希處理并將其存盤在資料庫中,當用戶登錄時,我只是對他們鍵入的內容進行哈希處理,然后比較兩個哈希值,由于給定的輸入始侄訓產生相同的哈希,因此每次都有效,

如果網站以純文本形式(而不是散列的形式)存盤密碼,則將嚴重違反安全性,如果有人要入侵該站點的資料庫并找到所有使用純文本密碼存盤的電子郵件,則他們可以使用這些組合并在其他網站上嘗試使用,

輸入無關緊要,輸出大小相同

如果我對單個單詞進行哈希處理,則輸出將具有一定的大小(對于SHA-256,則為特定的哈希函式,大小為256位),如果我對一本書進行哈希處理,輸出將是相同大小

這是另一個重要功能,因為它可以節省我們的計算時間,一個經典的例子是使用哈希作為資料映射中的鍵,資料映射是計算機科學中用于存盤資料的簡單結構,

當程式將資料存盤在映射中時,鍵和值將被賦予映射,當程式要訪問該值時,它可以將適當的鍵提供給映射并接收相應的值,資料映射之所以不錯,是因為它們可以立即找到資料,_鍵用作計算機可以立即找到的地址,而不是花費數小時來搜索數百萬條記錄,

因為鍵就像地址,所以不能太大,如果我想將書籍存盤在資料映射中,則可以對書籍的內容進行哈希處理并將哈希值用作鍵,作為程式員,我可以簡單地使用哈希來查找書中的內容,而不必嘗試按標題,作者等對數千條記錄進行排序,

它們如何作業?

這是撰寫本文的真正挑戰,我將使其保持極其簡單,并省略實際的實作細節,同時讓您基本了解計算機在處理某些資料時的實際作業,

讓我們來看一下我正在為這個演示動態撰寫的示例演算法 LANEHASH:

  • 我們從一些要散列的資料開始

iLove位元幣

  • 我將字母和數字轉換為1和0(計算機中的所有資料都存盤在1和0中,不同的1和0表示不同的字母)

iLoveBitcoin→100010100000101111

  • 在這一點上,我們經歷了各種預定步驟來轉換我們的資料,這些步驟可以是任何步驟,重要的是,每當我們使用LANEHASH時,我們都需要使用相同的步驟,以便我們的演算法具有確定性,
  • 我們將前四位從左側移到右側

1000 10100000101111→10100000101111 1000

  • 我們隔著一點

1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0→110011110&000001100

  • 我們將這兩部分轉換為以10為底的數字,以10為基數是我們在學校都學過的“正常”數字系統,(所有二進制資料實際上只是數字,您可以在其他地方在線查找如何將二進制輕松轉換為以10為基數)

110011110→414

000001100→12

  • 我們將兩個數字相乘

414 * 12 = 4968

  • 我們對該數字求平方

4968 ^ 2 = 24681024

  • 我們將該數字轉換回二進制

24681024→1011110001001101001000000

  • 我們從右側切掉9位以得到16位

1011110001001101 001000000 →1011110001001101

  • 我們將二進制資料轉換回英語

1011110001001101→“ 8sj209dsns02k2”

如您所見,如果在開頭以相同的單詞開頭,那么在結尾始終將得到相同的輸出,但是,即使您只更改一個字母,結果也將發生巨大變化,

免責宣告

在我從英語轉換為二進制,以及從二進制轉換為英語的步驟中,我沒有遵循任何模式,不要讓那讓您感到困惑,有很多不同的方法可以將二進制資料轉換為英語,然后再轉換回英語,我只是不想在本文中對此感到困惑,以下是有關該主題的一些參考資料:

https://zh.wikipedia.org/wiki/ASCII

https://zh.wikipedia.org/wiki/Unicode

什么是MD5哈希?

https://www.md5hashgenerator.com/


通過采用任意長度的字串并將其編碼為128位指紋來創建MD5哈希,使用MD5演算法編碼相同的字串將始終導致相同的128位哈希輸出,當在資料庫(例如流行的MySQL)中存盤密碼,信用卡號或其他敏感資料時,MD5哈希通常與較小的字串一起使用,該工具提供了一種快速簡便的方法,可以從長度最多為256個字符的簡單字串中編碼MD5哈希,

MD5哈希還用于確保檔案的資料完整性,由于MD5哈希演算法始終為相同的給定輸入產生相同的輸出,因此用戶可以將源檔案的哈希值與目標檔案的新創建的哈希值進行比較,以檢查其是否完整且未修改,

MD5哈希不是加密的,它只是給定輸入的指紋,但是,這是單向事務,因此幾乎不可能對MD5哈希進行反向工程以檢索原始字串,

SHA-2的作業原理(SHA-256)

https://dev.to/wagslane/how-sha-2-works-step-by-step-sha-256-11ci

https://qvault.io/2020/07/08/how-sha-2-works-step-by-step-sha-256/


SHA-2(安全哈希演算法2)是SHA-256的一部分,是其中最流行的哈希演算法之一,在本文中,我們將盡可能簡單地分解演算法的每個步驟,并手工完成一個真實的示例,

SHA-2以其安全性(它沒有像SHA-1一樣崩潰)和速度而聞名,在未生成密鑰的情況下(例如挖礦位元幣),像SHA-2這樣的快速哈希演算法通常占據上風,

什么是哈希函式?

如果您想全面了解散列函式,請在此處閱讀,也就是說,為了前進,讓我們回顧一下哈希函式的三個主要目的:

  • 確定性地加擾資料
  • 接受任意長度的輸入并輸出固定長度的結果
  • 不可逆地操縱資料,輸入不能從輸出派生

SHA-2和SHA-256

SHA-2是一種演算法,是有關如何對資料進行哈希處理的通用思想,SHA-256設定其他常量,這些常量定義SHA-2演算法的行為,這樣的常數之一就是輸出大小,“ 256”和“ 512”以位元為單位表示它們各自的輸出摘要大小,

讓我們逐步介紹一下SHA-256的示例,

SHA-256“ hello world”;步驟1 –預處理

將“ hello world”轉換為二進制:

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100

附加一個1:

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 1

用0填充,直到資料為512的整數倍,然后減去64位(本例中為448位):

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 10000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

在末尾附加64位,其中64位是big-endian整數,表示二進制原始輸入的長度,在我們的例子中,為88,或二進制為“ 1011000”,

01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111
01110010 01101100 01100100 10000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01011000

現在我們有了輸入,它將始終被512平均整除,

步驟2 –初始化哈希值(h)

現在,我們創建8個哈希值,這些是硬編碼的常數,代表前8個素數的平方根的小數部分的前32位:2、3、5、7、11、13、17、19

h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

步驟3 –初始化舍入常數(k)

與第2步類似,我們正在創建一些常量(在此處了解有關常量以及何時使用它們的更多資訊),這次有64個,每個值(0-63)是前64個素數(2 – 311)的立方根的小數部分的前32位,

0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5 0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5
0xd807aa98 0x12835b01 0x243185be 0x550c7dc3 0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf174
0xe49b69c1 0xefbe4786 0x0fc19dc6 0x240ca1cc 0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da
0x983e5152 0xa831c66d 0xb00327c8 0xbf597fc7 0xc6e00bf3 0xd5a79147 0x06ca6351 0x14292967
0x27b70a85 0x2e1b2138 0x4d2c6dfc 0x53380d13 0x650a7354 0x766a0abb 0x81c2c92e 0x92722c85
0xa2bfe8a1 0xa81a664b 0xc24b8b70 0xc76c51a3 0xd192e819 0xd6990624 0xf40e3585 0x106aa070
0x19a4c116 0x1e376c08 0x2748774c 0x34b0bcb5 0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff3
0x748f82ee 0x78a5636f 0x84c87814 0x8cc70208 0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2

步驟4 –區塊回圈

對于來自我們輸入的每個512位“塊”資料,將執行以下步驟,在我們的案例中,由于“ hello world”非常短,因此我們只有一個塊,在回圈的每次迭代中,我們將使哈希值h0-h7突變,這將是最終輸出,

步驟5 –建立郵件時間表(w)

將步驟1中的輸入資料復制到一個新陣列中,其中每個條目都是一個32位字:

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000

再添加48個初始化為零的單詞,這樣我們就有了一個陣列w [0…63]

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
...
...
00000000000000000000000000000000 00000000000000000000000000000000

使用以下演算法在陣列末尾修改零位索引:

對于從W [16 ... 63]:

s0 =(w [i-15]右旋7)xor(w [i-15]右旋18)xor(w [i-15]右移3)

s1 =(w [i-2]右旋17)xor(w [i-2]右旋19)xor(w [i-2]右移10)

w [i] = w [i-16] + s0 + w [i-7] + s1

s0 = (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
s1 = (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift 10)
w[i] = w[i-16] + s0 + w[i-7] + s1

讓我們做w [16]以便我們看一下它是如何作業的:

w[1] rightrotate 7:
  01101111001000000111011101101111 -> 11011110110111100100000011101110
w[1] rightrotate 18:
  01101111001000000111011101101111 -> 00011101110110111101101111001000
w[1] rightshift 3:
  01101111001000000111011101101111 -> 00001101111001000000111011101101

s0 = 11011110110111100100000011101110 XOR 00011101110110111101101111001000 XOR 00001101111001000000111011101101

s0 = 11001110111000011001010111001011

w[14] rightrotate 17:
  00000000000000000000000000000000 -> 00000000000000000000000000000000
w[14] rightrotate19:
  00000000000000000000000000000000 -> 00000000000000000000000000000000
w[14] rightshift 10:
  00000000000000000000000000000000 -> 00000000000000000000000000000000

s1 = 00000000000000000000000000000000 XOR 00000000000000000000000000000000 XOR 00000000000000000000000000000000

s1 = 00000000000000000000000000000000

w[16] = w[0] + s0 + w[9] + s1

w[16] = 01101000011001010110110001101100 + 11001110111000011001010111001011 + 00000000000000000000000000000000 + 00000000000000000000000000000000

// addition is calculated modulo 2^32

w[16] = 00110111010001110000001000110111

這使我們在訊息時間表(w)中留下了64個單詞:

01101000011001010110110001101100 01101111001000000111011101101111
01110010011011000110010010000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000000000000
00000000000000000000000000000000 00000000000000000000000001011000
00110111010001110000001000110111 10000110110100001100000000110001
11010011101111010001000100001011 01111000001111110100011110000010
00101010100100000111110011101101 01001011001011110111110011001001
00110001111000011001010001011101 10001001001101100100100101100100
01111111011110100000011011011010 11000001011110011010100100111010
10111011111010001111011001010101 00001100000110101110001111100110
10110000111111100000110101111101 01011111011011100101010110010011
00000000100010011001101101010010 00000111111100011100101010010100
00111011010111111110010111010110 01101000011001010110001011100110
11001000010011100000101010011110 00000110101011111001101100100101
10010010111011110110010011010111 01100011111110010101111001011010
11100011000101100110011111010111 10000100001110111101111000010110
11101110111011001010100001011011 10100000010011111111001000100001
11111001000110001010110110111000 00010100101010001001001000011001
00010000100001000101001100011101 01100000100100111110000011001101
10000011000000110101111111101001 11010101101011100111100100111000
00111001001111110000010110101101 11111011010010110001101111101111
11101011011101011111111100101001 01101010001101101001010100110100
00100010111111001001110011011000 10101001011101000000110100101011
01100000110011110011100010000101 11000100101011001001100000111010
00010001010000101111110110101101 10110000101100000001110111011001
10011000111100001100001101101111 01110010000101111011100000011110
10100010110101000110011110011010 00000001000011111001100101111011
11111100000101110100111100001010 11000010110000101110101100010110

步驟6 –壓縮

初始化變數a,b,c,d,e,f,g,h,并將它們分別設定為等于當前的哈希值,h0,h1,h2,h3,h4,h5,h6,h7

運行壓碩訓圈,壓碩訓圈將使a…h的值發生變化,壓碩訓圈如下:

我從0到63

S1 =(e右旋轉6)xor(e右旋轉11)xor(e右旋轉25)

ch =(e和f)xor((not e)和g)

temp1 = h + S1 + ch + k [i] + w [i]

S0 =(右旋轉2)xor(右旋轉13)xor(右旋轉22)

maj =(a和b)xor(a和c)xor(b和c)

temp2:= S0 + maj

h =克

g = f

e = d +溫度1

d = c

c = b

b = a

a = temp1 + temp2

S1 = (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch = (e and f) xor ((not e) and g)
temp1 = h + S1 + ch + k[i] + w[i]
S0 = (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj = (a and b) xor (a and c) xor (b and c)
temp2 := S0 + maj
h = g
g = f
e = d + temp1
d = c
c = b
b = a
a = temp1 + temp2

讓我們進行第一次迭代,所有加法都是以2 ^ 32為模的:

a = 0x6a09e667 = 01101010000010011110011001100111
b = 0xbb67ae85 = 10111011011001111010111010000101
c = 0x3c6ef372 = 00111100011011101111001101110010
d = 0xa54ff53a = 10100101010011111111010100111010
e = 0x510e527f = 01010001000011100101001001111111
f = 0x9b05688c = 10011011000001010110100010001100
g = 0x1f83d9ab = 00011111100000111101100110101011
h = 0x5be0cd19 = 01011011111000001100110100011001

e rightrotate 6:
  01010001000011100101001001111111 -> 11111101010001000011100101001001
e rightrotate 11:
  01010001000011100101001001111111 -> 01001111111010100010000111001010
e rightrotate 25:
  01010001000011100101001001111111 -> 10000111001010010011111110101000
S1 = 11111101010001000011100101001001 XOR 01001111111010100010000111001010 XOR 10000111001010010011111110101000
S1 = 00110101100001110010011100101011

e and f:
    01010001000011100101001001111111
  & 10011011000001010110100010001100 =
    00010001000001000100000000001100
not e:
  01010001000011100101001001111111 -> 10101110111100011010110110000000
(not e) and g:
    10101110111100011010110110000000
  & 00011111100000111101100110101011 =
    00001110100000011000100110000000
ch = (e and f) xor ((not e) and g)
   = 00010001000001000100000000001100 xor 00001110100000011000100110000000
   = 00011111100001011100100110001100

// k[i] is the round constant
// w[i] is the batch
temp1 = h + S1 + ch + k[i] + w[i]
temp1 = 01011011111000001100110100011001 + 00110101100001110010011100101011 + 00011111100001011100100110001100 + 1000010100010100010111110011000 + 01101000011001010110110001101100
temp1 = 01011011110111010101100111010100

a rightrotate 2:
  01101010000010011110011001100111 -> 11011010100000100111100110011001
a rightrotate 13:
  01101010000010011110011001100111 -> 00110011001110110101000001001111
a rightrotate 22:
  01101010000010011110011001100111 -> 00100111100110011001110110101000
S0 = 11011010100000100111100110011001 XOR 00110011001110110101000001001111 XOR 00100111100110011001110110101000
S0 = 11001110001000001011010001111110

a and b:
    01101010000010011110011001100111
  & 10111011011001111010111010000101 =
    00101010000000011010011000000101
a and c:
    01101010000010011110011001100111
  & 00111100011011101111001101110010 =
    00101000000010001110001001100010
b and c:
    10111011011001111010111010000101
  & 00111100011011101111001101110010 =
    00111000011001101010001000000000
maj = (a and b) xor (a and c) xor (b and c)
    = 00101010000000011010011000000101 xor 00101000000010001110001001100010 xor 00111000011001101010001000000000 
    = 00111010011011111110011001100111

temp2 = S0 + maj
      = 11001110001000001011010001111110 + 00111010011011111110011001100111
      = 00001000100100001001101011100101

h = 00011111100000111101100110101011
g = 10011011000001010110100010001100
f = 01010001000011100101001001111111
e = 10100101010011111111010100111010 + 01011011110111010101100111010100
  = 00000001001011010100111100001110
d = 00111100011011101111001101110010
c = 10111011011001111010111010000101
b = 01101010000010011110011001100111
a = 01011011110111010101100111010100 + 00001000100100001001101011100101
  = 01100100011011011111010010111001

整個計算又進行了63次,從而始終修改了變數ah,我們不會手工完成,但是我們將提供ender:

h0 = 6A09E667 = 01101010000010011110011001100111
h1 = BB67AE85 = 10111011011001111010111010000101
h2 = 3C6EF372 = 00111100011011101111001101110010
h3 = A54FF53A = 10100101010011111111010100111010
h4 = 510E527F = 01010001000011100101001001111111
h5 = 9B05688C = 10011011000001010110100010001100
h6 = 1F83D9AB = 00011111100000111101100110101011
h7 = 5BE0CD19 = 01011011111000001100110100011001

a = 4F434152 = 001001111010000110100000101010010
b = D7E58F83 = 011010111111001011000111110000011
c = 68BF5F65 = 001101000101111110101111101100101
d = 352DB6C0 = 000110101001011011011011011000000
e = 73769D64 = 001110011011101101001110101100100
f = DF4E1862 = 011011111010011100001100001100010
g = 71051E01 = 001110001000001010001111000000001
h = 870F00D0 = 010000111000011110000000011010000

步驟7 –修改最終值

在壓碩訓圈之后,但仍然在回圈中,我們通過將哈希值添加到變數ah中來修改哈希值,像往常一樣,所有加法都是模2 ^ 32,

h0 = h0 + a = 10111001010011010010011110111001
h1 = h1 + b = 10010011010011010011111000001000
h2 = h2 + c = 10100101001011100101001011010111
h3 = h3 + d = 11011010011111011010101111111010
h4 = h4 + e = 11000100100001001110111111100011
h5 = h5 + f = 01111010010100111000000011101110
h6 = h6 + g = 10010000100010001111011110101100
h7 = h7 + h = 11100010111011111100110111101001

第8步-連接最終哈希

最后但并非最不重要的一點是,將它們全部拍打!

digest = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
       = B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9

做完了!我們已經仔細研究了SHA-256的每個步驟(沒有重復),🙂

偽碼

如果您想以偽代碼形式查看上面剛剛完成的所有步驟,那么直接來自WikiPedia:

Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232
Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
Note 3: The compression function uses 8 working variables, a through h
Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
    and when parsing message block data from bytes to words, for example,
    the first word of the input message "abc" after padding is 0x61626380

Initialize hash values:
(first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

Initialize array of round constants:
(first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
k[0..63] :=
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2

Pre-processing (Padding):
begin with the original message of length L bits
append a single '1' bit
append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits

Process the message in successive 512-bit chunks:
break message into 512-bit chunks
for each chunk
    create a 64-entry message schedule array w[0..63] of 32-bit words
    (The initial values in w[0..63] don't matter, so many implementations zero them here)
    copy chunk into first 16 words w[0..15] of the message schedule array

    Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
    for i from 16 to 63
        s0 := (w[i-15] rightrotate  7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift  3)
        s1 := (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift 10)
        w[i] := w[i-16] + s0 + w[i-7] + s1

    Initialize working variables to current hash value:
    a := h0
    b := h1
    c := h2
    d := h3
    e := h4
    f := h5
    g := h6
    h := h7

    Compression function main loop:
    for i from 0 to 63
        S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
        ch := (e and f) xor ((not e) and g)
        temp1 := h + S1 + ch + k[i] + w[i]
        S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
        maj := (a and b) xor (a and c) xor (b and c)
        temp2 := S0 + maj
 
        h := g
        g := f
        f := e
        e := d + temp1
        d := c
        c := b
        b := a
        a := temp1 + temp2

    Add the compressed chunk to the current hash value:
    h0 := h0 + a
    h1 := h1 + b
    h2 := h2 + c
    h3 := h3 + d
    h4 := h4 + e
    h5 := h5 + f
    h6 := h6 + g
    h7 := h7 + h

Produce the final hash value (big-endian):
digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

Scrypt哈希的基本介紹

https://dev.to/wagslane/very-basic-intro-to-the-scrypt-hash-7l5


這將是Scrypt哈希函式或更準確地說是KDF函式的基本介紹,我將假定我的大多數觀眾都在這里,以了解使用Scrypt原因以及其作業原理基礎,我的目標是從一般意義上解釋它,我將省略證明和實作細節,而將重點放在高級原則上,

在密碼學中,scrypt(發音為“ ess crypt” [1])是由Colin Percival創建的基于密碼的密鑰派生功能,最初用于Tarsnap在線備份服務,[2] 該演算法經過專門設計,使其需要大量記憶體,因此執行大規模自定義硬體攻擊的成本很高,IETF在2016年將scrypt演算法發布為RFC 7914,scrypt的簡化版本被許多加密貨幣用作作業量證明方案,首先由位于Tenebrix的名為ArtForz的匿名程式員實作,隨后不久又由Fairbrix和Litecoin實作,[3] -- https://en.wikipedia.org/wiki/Scrypt

什么是Scrypt?

Scrypt是一種設計緩慢的 哈希函式,其目的是獲取一些輸入資料,并為該資料創建指紋,但是要非常緩慢地進行,Qvault如何使用其真實案例的最佳示例之一,即,使用密碼并創建256位私有密鑰

例如,假設您的密碼為password1234,通過使用scrypt,我們可以確定性地將其擴展為256位密鑰:

password1234- >
AwEEDA4HCwQFAA8D
AwwHDQwPDwUOBwoO
CQACAgUJBQ0JAAYN
BAMCDQ4JCQgLDwcG
DQMDDgMKAQsNBAkL
AwsACA ==

現在可以將該長256位密鑰用作私有密鑰,以使用AES-256密碼對資料進行加密和解密,

為什么不使用密碼直接加密?

大多數加密演算法,包括AES-256,都要求使用足夠長的密鑰,通過對密碼進行哈希處理,我們得到了更長且固定大小的密鑰,

此外,出于兩個原因,我們選擇使用scrypt演算法,而不是使用SHA-256之類的更快的哈希值:

  • 慢一點
  • 它使用記憶體以及CPU資源

我們想要慢速散列的原因是,攻擊者很難猜測用戶的密碼,如果攻擊者試圖強行闖入金庫,則意味著他們只是反復猜測密碼以進行破解,AES-256速度非常快,因此,攻擊者將能夠嘗試許多密碼在現代計算機上每秒傳輸一次,

由于攻擊者必須先對每個密碼運行一個scrypt哈希,然后才能嘗試對庫進行解密,因此攻擊變得如此緩慢,幾乎不可能猜出密碼,在功能相對強大的臺式計算機上,散列Qvault密碼大約需要1.5秒,因為我們將記憶體和計算要求設定得很高,

加密屬性

像所有散列函式一樣,scrypt具有以下屬性:

  • 確定性的(每次相同的輸入都會產生相同的輸出)
  • 固定尺寸的輸出
  • 不可逆的(通過使用輸出,攻擊者無法找到輸入)

此外,Scrypt具有以下屬性:

  • 計算昂貴且速度慢(計算機運行哈希需要很長時間)
  • 記憶體密集型(可能使用數GB的RAM來運行哈希)

什么是BCrypt?

https://dev.to/sylviapap/bcrypt-explained-4k5c


BCrypt是由OpenBSD專案的Niels Provos和DavidMazières在1999年設計的一種哈希演算法,B代表...

如果您是初學者密碼學的專家,那么您來對地方了,也許您只是進入Rails并想添加用戶登錄/注銷功能,也許您真的很喜歡加密哈希演算法,我肯定是!如果您真的是一個初學者,那么一個名為Khan Academy的小型網站上有一些關于加密的特別出色的視頻,

這并不是真正的教程,但是在使用BCrypt時,請始終記住取消注釋Rails Gemfile中的gem,

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.1'

...

# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7'

...

現在,您可以做一些很酷的事情:

# Encrypts password
my_password = BCrypt::Password.create('iLOVEdogs123')
 => "$2a$10$kypbnGGCpJ7UQlysnqzJG.6H.dUewn7UPVWA3Ip.E.8U4jlVnFNnu"

# Tests if input matches
my_password == 'iLOVEdogs123'
 => true 

my_password == 'ilovedogs12'
 => false

# Not super important for this post, but this is why the above crypt begins with "$2a$"
my_password.version
 => "2a" 

# "Cost" factor - how quickly the password is encrypted
my_password.cost
 => 10 

現在,您可以使用BCrypt對應用程式執行很多操作-身份驗證,授權,登錄,注銷等!但是,已經有很多博客文章和有關如何撰寫代碼的有用檔案,我對幕后動作更感興趣,

Bcrypt是怎么加密的?

Bcrypt有四個變數:

  1. saltRounds: 正數,代表hash雜湊次數,數值越高越安全,默認10次,
  2. myPassword: 明文密碼字串,
  3. salt: 鹽,一個128bits隨機字串,22字符
  4. myHash: 經過明文密碼password和鹽salt進行hash,個人的理解是默認10次下 ,回圈加鹽hash10次,得到myHash

每次明文字串myPassword過來,就通過10次回圈加鹽salt加密后得到myHash, 然后拼接BCrypt版本號+salt鹽+myHash等到最終的bcrypt密碼 ,存入資料庫中,

這樣同一個密碼,每次登錄都可以根據自省業務需要生成不同的myHash, myHash中包含了版本和salt,存入資料庫,
bcrypt密碼圖解:(此部分來源:https://www.jianshu.com/p/2b131bfc2f10)

如Spring Security crypto 專案中實作的BCrypt方法加密:BCrypt.hashpw(myPassword, BCrypt.gensalt())

那即使黑客得到了bcrypt密碼,他也無法轉換明文,因為之前說了bcrypt是單向hash演算法

OWASP - 開放式Web應用程式安全專案


開放式Web應用程式安全專案(OWASP,Open Web Application Security Project)是一個組織,它提供有關計算機和互聯網應用程式的公正、實際、有成本效益的資訊,其目的是協助個人、企業和機構來發現和使用可信賴軟體,

OWASP Top 10是針對開發人員和Web應用程式安全性的標準意識檔案,它代表了對Web應用程式最嚴重的安全風險的廣泛共識,

相關文章


  • (非常)格的基本介紹
  • (非常)橢圓曲線密碼學基礎介紹
  • Bcrypt逐步
  • 《哈希函式(Hash Functions - 散列函式)的基本介紹(SHA-2,SHA-256,MD-5等)》
  • 《關于布隆過濾器的所有資訊:利用Hash實作的索引方案》
  • 《(Very) Basic Intro to Hash Functions (SHA-256, MD-5, etc)》
  • Scrypt哈希的基本介紹
  • BCrypt解釋
  • 《維基百科:scrypt》

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/170015.html

標籤:其他

上一篇:曲速未來 發布:您的網路安全策略是否合理?

下一篇:flutter下拉重繪上拉加載 簡單使用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more