Node.js應(yīng)用中常用安全保護機制和加密算法實現(xiàn)

當(dāng)你知道如何在應(yīng)用中針對不同的使用場景使用不同的加密算法蒸眠,你的應(yīng)用才是安全的杆融。因此,這篇文章將會介紹平常工作中比較常用的幾種加密方式蒋腮,并給出對應(yīng)的Node.js代碼藕各。

保護密碼

用戶在注冊應(yīng)用的時候難免會使用一些過于簡單的密碼,同時也傾向于在不同的站點使用相同的密碼作彤。最可怕的是用來存儲用戶密碼的數(shù)據(jù)庫可能被黑客侵入乌逐。因此,對于用戶密碼的保護是最基礎(chǔ)的防護措施绢慢。(ps: 大家可以使用這個網(wǎng)站來檢查自己的密碼是否被泄露了洛波。)

對于密碼的加密,通常使用的是哈希(hash)算法缚窿。比較常見的哈希算法有Argon2焰扳、PBKDF2够话、scrypt和bcrypt等女嘲。關(guān)于這些加密算法的介紹诞帐,大家可以參考Password Storage Cheat Sheet這篇文章。

node.js中提供了crypto模塊愕鼓,該模塊主要用于實現(xiàn)基礎(chǔ)的加解密算法慧起。接下來就來介紹一下如何使用該模塊來實現(xiàn)對于密碼的保護:

// 這里是最基礎(chǔ)的md5算法
const crypto = require('crypto');

const hash = crypto.createHash('md5'); // 最基本的md5算法

hash.update('password1'); // update用來更新數(shù)據(jù)

hash.digest('hex'); // 以string格式輸出密文
hash.digest('sha256');

對于md5算法,這里推薦使用https://hashtoolkit.com/這個網(wǎng)站進行調(diào)試。普通的md5算法對于程序員來說就是明文的磺送,因此我們一般還會對它加鹽(salt the hash):

const crypto = require('crypto');
const password = 'ddd';
const salt = crypto.randomBytes(256).toString('hex');

// 這里使用pbkdf2算法
const hashedPwd = crypto.pbkdf2Sync(password, salt, 100000, 512, 'sha512');

console.log(hashedPwd.toString('hex'));

保護存儲數(shù)據(jù)

對稱加密算法(Symmetric Encryption)是一種使用同一密鑰進行加密和解密文本的算法估灿,這也意味著通信雙方要使用同一密鑰進行加解密缤剧。對稱加密算法對于大型數(shù)據(jù)的加密來說速度很快,因此它也主要用于存儲數(shù)據(jù)的加密汗销。比較常用的對稱加密算法有AES抵窒、Blowfish、DES和RC4等钦奋。

crypto模塊中主要利用以下方法來實現(xiàn)對稱加密:

  • createCipheriv: 提供對稱加密, 該方法接收三個參數(shù)疙赠,第一個是加密算法、第二個是密鑰厌衔,而第三個是初始向量(initialization vector)

  • update 和 final: 先更新數(shù)據(jù)捍岳,然后獲得密文

const crypto = require('crypto');
const algorithm = 'aes-256-cbc';

const password = 'Hello world';
const salt = crypto.randomBytes(32);
cnst key = crypto.scryptSync(password, salt, 32);

const iv = crypto.randomBytes(16);
const cipher = crypto.crateCipheriv(algorithm, key, iv);
let ssn = '111-000-2342';
let encrypted = cipher.update(ssn, 'utf8', 'hex');
// 獲得加密密文
encrypted += cipher.final('hex');

// 解密算法是反向操作
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.final('utf8');
console.log(decrypted)

同時用于對稱加密的密鑰也需要有合適的密碼管理策略進行處理,否則一旦密鑰被破解页徐,數(shù)據(jù)的安全性就無從保障变勇。通常我們會使用一個密鑰管理系統(tǒng)(KMS)進行管理密鑰。所有的加密密鑰都由該系統(tǒng)進行統(tǒng)一分配和管理搀绣,而用于數(shù)據(jù)加密的密鑰由一個主密鑰(master
key)進行加密链患。比較流行的KMS有https://cloud.google.com/kms/https://aws.amazon.com/kms/,當(dāng)然你可以選擇自己實現(xiàn)纲仍。

保護通信信道

存儲數(shù)據(jù)的保護使用的是對稱算法芯肤,與之相對應(yīng)的非對稱算法則主要用于保護通信信道压鉴。

const crypto = require('crypto');

// 加密方法
exports.encrypt = (data, key) => {
  // 公鑰加密
  return crypto.publicEncrypt(key, Buffer.from(data));
};

// 解密方法
exports.decrypt = (encrypted, key) => {
  // 私鑰解密
  return crypto.privateDecrypt(key, encrypted);
};

在數(shù)據(jù)傳輸過程中油吭,我們還會使用Diffie-Hellman算法進行交換密鑰:

const crypto = require('crypto');
const sally = crypto.createDiffieHellman(2048);
const sallKeys = sally.generateKeys();
const bob = crypto.createDiffieHellman(sally.getPrime(), sally.getGenerator());

const bobKey = bob.generateKeys();
const sallySecret = sally.computeSecret(bobKey);
const bobSecret = bob.computeSecret(sallyKeys);

console.log(sallySecret.toString('hex'));
console.log(bobSecret.toString('hex'));

接下來介紹一下HMAC算法的使用,這個算法主要用于身份認證和生成消息摘要:

const hmac = crypto.createHmac('sha256', 'a secret');

hmac.update('some data');

console.log(hmac.digest('hex'));

雙因子認證

雙因子認證(Two-factor authentication歌豺,也叫2FA)是一種組合使用兩種不同的驗證機制來確認用戶身份的機制心包。主要是通過手機等設(shè)備來生成token,具體到代碼實現(xiàn)層面痕惋,可以在服務(wù)端和客戶端之間生成一個臨時的代碼序列來校驗娃殖。

這里推薦使用speakeasy這個npm庫來實現(xiàn)2FA:

const express = require('express');
const app = express();
const speakeasy = require('speakeasy');
const qrcode = require('qrcode');
const bodyParser = require('body-parser');

app.use(bodyParser.urlencoded( { extended: true } ));

var router = express.Router();

var user = {
    two_factor_temp_secret: null,
    two_factor_secret: null,
    two_factor_enabled: false
};

router.get('/2fa', function(req, res){
    // 生成私鑰
    var secret = speakeasy.generateSecret();

    user.two_factor_temp_secret = secret.base32;

    qrcode.toDataURL(secret.otpauth_url, function(err, data_url){

        res.send('<img src="' + data_url + '">');
    });
});

// 認證頁面
router.get('/authenticate', function(req, res){

    res.send('<form action="/app/verify" method="post">Enter Token: <input type="text" name="token"><br><input type="submit" value="submit">');

});

//校驗用戶輸入
router.post('/verify', function(req, res){
    var userToken = req.body.token; 

    var base32secret = user.two_factor_temp_secret;

    var verified = speakeasy.totp.verify({
        secret: base32secret,
        encoding: 'base32',
        token: userToken
    });

    if(verified){
        user.two_factor_secret = user.two_factor_temp_secret;
        user.two_factor_enabled = true;

        console.log('Successfully verified');

        res.send('<p>Your token has been verified!</p>');
    } else {
        console.log('verification failed');

        res.send('<p>verification failed</p>');
    }
});

app.use('/app', router);

app.listen(3000);
console.log('App is running on port 3000');

總結(jié)

這篇文章主要介紹了如何在Node.js中使用crypto模塊來保護密碼堕虹、存儲數(shù)據(jù)和通信信道。最后還介紹了如何使用speakeasy模塊來實現(xiàn)雙因子驗證機制逼裆,希望這篇文章對大家有所幫助螟炫。

參考資料

Crypto In Node.js

Zero to Hashing in Under 10 Minutes: Argon2 in Nodejs – Hunter2: AppSec Training

Symmetric Encryption in JavaScript - Ekene Izukanne - Medium

深入理解雙因子認證

Practical Cryptography in Node.js

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昼钻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仅财,更是在濱河造成了極大的恐慌碗淌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碎罚,死亡現(xiàn)場離奇詭異纳像,居然都是意外死亡竟趾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門玫鸟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來犀勒,“玉大人,你說我怎么就攤上這事枚碗≈荆” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵怨规,是天一觀的道長波丰。 經(jīng)常有香客問我,道長掰烟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮先馆,結(jié)果婚禮上煤墙,老公的妹妹穿的比我還像新娘。我一直安慰自己仿野,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布葫哗。 她就那樣靜靜地躺著鳖枕,像睡著了一般宾符。 火紅的嫁衣襯著肌膚如雪灭翔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天哄褒,我揣著相機與錄音煌张,去河邊找鬼。 笑死链嘀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茫藏。 我是一名探鬼主播霹琼,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼务傲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枣申?” 一聲冷哼從身側(cè)響起售葡,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糯而,沒想到半個月后天通,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡熄驼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年像寒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓜贾。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡诺祸,死狀恐怖祭芦,靈堂內(nèi)的尸體忽然破棺而出筷笨,到底是詐尸還是另有隱情,我是刑警寧澤龟劲,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布胃夏,位于F島的核電站,受9級特大地震影響昌跌,放射性物質(zhì)發(fā)生泄漏仰禀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一蚕愤、第九天 我趴在偏房一處隱蔽的房頂上張望答恶。 院中可真熱鬧,春花似錦萍诱、人聲如沸悬嗓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽包竹。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間周瞎,已是汗流浹背悟狱。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堰氓,地道東北人挤渐。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像双絮,于是被迫代替她去往敵國和親浴麻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354