日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一種保護(hù)云中的密碼的加密方法

簡(jiǎn)介

成都創(chuàng)新互聯(lián)公司公司2013年成立,先為貢山等服務(wù)建站,貢山等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為貢山企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

在本文中,后端開發(fā)人員可以了解為什么使用加密很重要,以及如何有效地使用它來保護(hù)云上的用戶信息(特別是密碼),使得數(shù)據(jù)即使泄露也不會(huì)在數(shù)十年內(nèi)被破解。安全性是云中的一個(gè)非常重要的主題,它對(duì)全棧開發(fā)至關(guān)重要,而且在所有產(chǎn)品和服務(wù)上都不可或缺。

我們首先會(huì)列出一些在開發(fā)中考慮安全性時(shí)要執(zhí)行(或不執(zhí)行)的簡(jiǎn)單事務(wù):

  • 始終選擇使用經(jīng)過其他人仔細(xì)檢查和審核的非本人的哈希/加密庫。
  • 不要將密碼輸出到日志中!
  • 使用某種形式的密鑰管理服務(wù)。
  • 不要將密鑰(API 密鑰、密碼)提交到代碼存儲(chǔ)庫中。

在本文中,我將通過一個(gè)示例應(yīng)用程序來重點(diǎn)介紹加密關(guān)鍵數(shù)據(jù)的方式。對(duì)于本文中涉及的密碼存儲(chǔ),我們將使用一個(gè) SQLite 數(shù)據(jù)庫,因?yàn)樗鼛缀蹩梢栽谌魏蜗到y(tǒng)上輕松使用。幾乎所有地方都使用著相同的原則和理念,而且數(shù)據(jù)庫系統(tǒng)應(yīng)該無關(guān)緊要(但根據(jù)所選的數(shù)據(jù)庫,可能存在對(duì)用戶信息執(zhí)行哈希運(yùn)算和保護(hù)的更好方法)。我還想展示,如果您丟失了數(shù)據(jù)庫文件,但仍保持用戶哈希值完整且無法破解,結(jié)果會(huì)怎樣?

使用 bcrypt

bcrypt 是目前對(duì)密碼執(zhí)行哈希運(yùn)算的最廣泛使用的函數(shù)之一。它適用于大部分編程語言,而且通常有一些可用于特定框架和數(shù)據(jù)庫的非常特殊的模塊。讓我們看看這個(gè)存儲(chǔ)庫示例。此代碼通常與 Node.js 一起使用,而且非常簡(jiǎn)單(它允許采用 sync 或 async 的方式來調(diào)用加鹽和哈希函數(shù))。它還使您無需擔(dān)心實(shí)現(xiàn)細(xì)節(jié)和加鹽過程,使您能專注于防止意外的密碼泄露。

哈希運(yùn)算、鹽和加密是什么?

盡管哈希運(yùn)算和加密看起來可能沒什么不同,而且可以互換使用,但它們實(shí)際上有很大區(qū)別,而且有不同的用例。哈希函數(shù)接受一些輸入,并對(duì)輸出進(jìn)行單向映射。雖然有眾多的哈希技術(shù)和算法,但我推薦對(duì)密碼使用 bcrypt??梢栽诖颂庍M(jìn)一步了解加密哈希函數(shù),但通常不必了解這些函數(shù)的基礎(chǔ)細(xì)節(jié)。在執(zhí)行哈希運(yùn)算期間使用了鹽,將鹽作為提供給哈希函數(shù)的附加信息,使您(意外或通過暴力)即使找到一個(gè)哈希值,也無法校驗(yàn)其他可能具有類似輸入的哈希值。例如,user_1 有一個(gè)與 user_2 的密碼相同的密碼。如果哈希函數(shù)中使用了鹽,這兩個(gè)用戶的密碼就無法被找到。要進(jìn)一步了解此函數(shù),此處提供了各種各樣的信息和示例。

加密也是某個(gè)輸入與一個(gè)輸出之間的一對(duì)一映射。一個(gè)重要的關(guān)鍵區(qū)別是,如果您擁有加密密鑰,那么加密是可逆的。

您可以在以后使用哈希運(yùn)算來檢查一個(gè)輸入與另一個(gè)輸入的映射,但您可能并不想直接存儲(chǔ)該輸入(密碼、pin 編號(hào)等)。在發(fā)送消息時(shí)(雙方都有一個(gè)用于編碼/解碼的密鑰),或者在您想存儲(chǔ)一些隱私信息(比如家庭地址或信用卡),但需要在以后通過某種方式檢索此信息時(shí),可以使用加密。

前端

因?yàn)楸疚牡闹攸c(diǎn)不是前端,所以我們不打算采用任何會(huì)增加復(fù)雜性的內(nèi)容或引入另一個(gè)令人擔(dān)憂的框架。我們將在同一個(gè)頁面上采用兩個(gè)用于登錄/注冊(cè)的表單。除了使用超級(jí)簡(jiǎn)單的引導(dǎo)指令外,我們不會(huì)對(duì)這些表單執(zhí)行任何操作,因?yàn)檫@不是本文的重點(diǎn)。

 
 
 
  1.  
  2.   
  3.   
  4.      
  5.        
  6.          
  7.          
  8.       
 
  •        
  •   
  •   
  •          
  •       
  •  
  •        
  •         sign in 
  •       
  •  
  •      
  •   
  •  
  •   
  •   
  •  
  •   
  •      
  •        
  •          
  •          
  •       
  •  
  •        
  •           
  •          
  •       
  •  
  •        
  •         register 
  •       
  •  
  •     
  •  
  •    
  •  
  • 我們還將輸入從表單提交到后端,而且不打算校驗(yàn)/創(chuàng)建/設(shè)置會(huì)話,因?yàn)檫@不屬于本文的討論范圍,而且根據(jù)應(yīng)用程序的目標(biāo)或目的,涉及的內(nèi)容可能很廣泛。

    創(chuàng)建后端

    接下來,我們將在 Node.js 中運(yùn)行后端,方法是使用 Express 框架和 SQLite 來實(shí)現(xiàn)本文所需的最基本的系統(tǒng)。

     
     
     
    1. const path = require('path') 
    2. const bcrypt = require('bcrypt') 
    3. const bodyParser = require('body-parser') 
    4. const sqlite = require('sqlite') 
    5.   
    6. const express = require('express') 
    7. const app = express() 
    8. app.use(bodyParser.json()) 
    9. app.use(bodyParser.urlencoded({ extended: true })) 
    10.   
    11. const dbPromise = sqlite.open('./database.sqlite', { Promise }) 
    12. const saltRounds = 10 

    我們?cè)谶@里執(zhí)行的操作包括:為數(shù)據(jù)庫創(chuàng)建一個(gè) promise,生成一個(gè)鹽,并創(chuàng)建應(yīng)用程序和簡(jiǎn)單中間件來獲取用戶名/密碼,加載一些我們想要使用的庫。

    路徑

    對(duì)于我們的服務(wù)器將要執(zhí)行的操作,我們將有一個(gè)登錄路徑和一個(gè)供用戶進(jìn)行注冊(cè)的路徑。為了理解系統(tǒng)中正在發(fā)生的事情,我們將這兩條路徑分開了,但它們不會(huì)執(zhí)行任何操作(與會(huì)話/cookie 等相關(guān)的任何操作)。一旦密碼匹配,我們將(非常簡(jiǎn)單地)展示如何對(duì)一個(gè)密碼執(zhí)行哈希運(yùn)算,然后執(zhí)行校驗(yàn)。登錄路徑與注冊(cè)路徑幾乎是相同的,盡管我們會(huì)在該 HTML 表單上檢查電子郵件,但我們不會(huì)在任何路徑上執(zhí)行任何數(shù)據(jù)驗(yàn)證。

     
     
     
    1. app.get('/', async (req,res) => { 
    2.  res.sendFile(path.join(__dirname, '/main.html')) 
    3. }) 
    4.   
    5. app.post('/register', async (req, res) => { 
    6.   const db = await dbPromise 
    7.   
    8.   // check if user already exists 
    9.   const checkUser = await db.get('SELECT * FROM Users WHERE email = ?', req.body.email) 
    10.   if (checkUser) { 
    11.     return res.send('user already exists') 
    12.   } 
    13.   
    14.   const hashedPassword = await bcrypt.hash(req.body.password, saltRounds) 
    15.   const resp = await db.run(`INSERT INTO Users VALUES(?,?)`, req.body.email, hashedPassword) 
    16.   res.send('registered') 
    17. }) 

    注冊(cè)路徑檢查用戶是否存在于數(shù)據(jù)庫中,以及我們是否已使用一個(gè)經(jīng)過哈希運(yùn)算的密碼將其插入數(shù)據(jù)庫中。請(qǐng)記住,我們不會(huì)執(zhí)行任何操作來減少 SQL 注入或其他各種形式的攻擊/濫用。如果該用戶不存在,我們會(huì)使用 bcrypt 哈希函數(shù)對(duì)密碼執(zhí)行哈希運(yùn)算,該函數(shù)會(huì)在密碼中添加鹽,因?yàn)槲覀兿螓}提供了運(yùn)算的輪數(shù)。這種哈希運(yùn)算使我們能夠以這樣一種方式存儲(chǔ)用戶的密碼 - 將來,如果用戶輸入了密碼,我們就可以檢查密碼。我們自己無法查找該密碼。另外,我們不應(yīng)將密碼輸出到用戶的日志中,而且我們可能希望能夠使用數(shù)據(jù)庫模型來檢查密碼,并將用戶的密碼保存到哈希值中。

    盡管登錄路徑幾乎相同(而且我們可以輕松重構(gòu)此路徑來讓它更 DRY,但在這里提供它是為了便于理解),但有一行稍有不同:

     
     
     
    1. const passwordMatch = await bcrypt.compare(req.body.password, user.password) 

    此代碼使用 bcrypt 將經(jīng)過哈希運(yùn)算的密碼與用戶在前端輸入的密碼進(jìn)行比較,并返回 true 或 false。因?yàn)辂}已合并到哈希值中,所以我們不需要顯式使用它來進(jìn)行比較。下面是要運(yùn)行的完整的 server.js:

    盡管登錄路徑幾乎相同(而且我們可以輕松地重構(gòu)此路徑來讓它更 DRY,但在這里提供它是為了便于理解),但有一行稍有不同:

     
     
     
    1. const passwordMatch = await bcrypt.compare(req.body.password, user.password) 

    上面這行使用 bcrypt 將經(jīng)過哈希運(yùn)算的密碼與用戶在前端輸入的密碼進(jìn)行比較,并返回 true 或 false。因?yàn)辂}已合并到哈希值中,所以我們不需要顯式使用它來進(jìn)行比較。下面的代碼清單是要運(yùn)行的完整的 server.js:

     
     
     
    1. const bcrypt = require('bcrypt') 
    2. const bodyParser = require('body-parser') 
    3.   
    4.   
    5. const express = require('express') 
    6. const app = express() 
    7.   
    8. app.post('/register', async (req, res) => { 
    9.   const db = await dbPromise 
    10.   
    11.   
    12.   
    13.   const hashedPassword = await bcrypt.hash(req.body.password, saltRounds) 
    14.   const resp = await db.run(`INSERT INTO Users VALUES(?,?)`, req.body.email, hashedPassword) 
    15.   res.send('registered') 
    16. }) 
    17.   
    18.   
    19. app.post('/signin', async (req, res) => { 
    20.   const db = await dbPromise 
    21.   const user = await db.get('SELECT * FROM Users WHERE email = ?', req.body.email) 
    22.   
    23.   if (!user) { 
    24.     return res.send('user doesnt exist') 
    25.   } 
    26.   
    27.   
    28.   const passwordMatch = await bcrypt.compare(req.body.password, user.password) 
    29.   if (passwordMatch) { 
    30.   
    31.     return res.send('signed in') 
    32.   } 
    33.   res.send('password does not match') 
    34. }) 
    35.   
    36.   
    37. app.listen(PORT, async () => { 
    38.   
    39.   console.log(`app listening at http://localhost:${PORT}`) 
    40. }) 

    現(xiàn)在安裝依賴項(xiàng):

     
     
     
    1. yarn add bcrypt express body-parser sqlite。 

    運(yùn)行服務(wù)器 Node server.js,打開 http://localhost:8080。然后嘗試登錄,創(chuàng)建一個(gè)用戶,并再次登錄。

    通過網(wǎng)絡(luò)發(fā)送未加密的密碼!

    盡管本文僅展示了如何存儲(chǔ)密碼并對(duì)其執(zhí)行哈希運(yùn)算,而且您不會(huì)保存用戶的明文密碼,但我們?nèi)栽跒g覽器與后端之間發(fā)送明文,因?yàn)槲覀儧]有使用 HTTPS。如果將此示例用在生產(chǎn)環(huán)境中,當(dāng)黑客進(jìn)入此通信渠道時(shí),他們很容易看到在服務(wù)器與客戶端之間發(fā)送的密碼(包括登錄和注冊(cè)密碼)。有許多不同的方法可用來實(shí)際阻止中間人攻擊,但為了簡(jiǎn)單起見,我們將在 Express 中處理它,生成自簽名 SSL 證書作為示例,以說明此工作原理。請(qǐng)記住,這些證書的簽署方式與從 LetsEncrypt 或其他各種 SSL/TLS 證書提供者獲取證書的方式不同。

    首先,我們需要通過包管理器或通過 OpenSSL 的官方網(wǎng)站安裝 OpenSSL。在 macOS 上,如果您已安裝 homebrew,可以簡(jiǎn)單寫入以下代碼:

     
     
     
    1. brew-install Openssl 

    接下來,需要運(yùn)行以下命令來生成一個(gè)密鑰和一個(gè)證書:

     
     
     
    1. openSSL req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 30 

    此命令會(huì)要求您輸入一些信息,但在最后,您將獲得一個(gè) key.pem 和一個(gè) cert.pem。有了這兩個(gè)文件,就可以將以下代碼添加到 server.js 的頂部(請(qǐng)注意,我們現(xiàn)在使用的是來自 Node.js 的 https 標(biāo)準(zhǔn)庫):

     
     
     
    1. const fs = require('fs') 
    2. const https = require('https') 
    3.   
    4. const options = { 
    5.   key: fs.readFileSync('key.pem'), 
    6.   cert: fs.readFileSync('cert.pem') 

    在我們的代碼底部,以前包含以下代碼:

     
     
     
    1. const PORT = 8080 
    2. app.listen(PORT, async () => { 
    3.   const db = await dbPromise 
    4.   await db.run("CREATE TABLE IF NOT EXISTS Users (email TEXT, password TEXT)") 
    5.   console.log(`app listening at http://localhost:${PORT}`) 
    6. }) 

    我們將上述以前的代碼更改為:

     
     
     
    1. const PORT = 8081 
    2. https.createServer(options, app) 
    3.   .listen(PORT, async () => { 
    4.     const db = await dbPromise 
    5.     await db.run("CREATE TABLE IF NOT EXISTS Users (email TEXT, password TEXT)") 
    6.     console.log(`app listening at https://localhost:${PORT}`) 
    7.   }) 

    此刻,我們將僅使用 HTTPS 并將加密后的密碼發(fā)送到服務(wù)器,而且會(huì)在將密碼保存到數(shù)據(jù)庫時(shí)執(zhí)行哈希運(yùn)算。

    最糟的情況:數(shù)據(jù)庫被泄露

    設(shè)想我們的服務(wù)器被黑客攻擊,或者出現(xiàn)了其他一些漏洞,而且我們的 SQLite(或任何數(shù)據(jù)庫)被泄露。盡管這種情況很糟糕,但我們至少可以確信,用戶密碼本身應(yīng)該是安全的,不會(huì)被使用,而且我們最大限度降低了從其他地方要求用戶更改密碼的可能性。 例如,圖 1 顯示,除非看到用戶 graham@test.xyz 的密碼 secret,否則哈希值對(duì)嘗試使用它的黑客毫無用處。

    結(jié)束語:其他替代性云安全方法


    本文標(biāo)題:一種保護(hù)云中的密碼的加密方法
    文章起源:http://www.dlmjj.cn/article/djjijeo.html