客戶端或前端將用戶的憑據作為輸入。然后,它將這些憑據發送到后端。為此,它會向身份驗證端點發出 HTTP 請求。這可能是/login/signup,分別表示登錄和注冊 API 調用。 

服務器從請求中接收憑據并對其進行驗證。如果憑據正確,它將為該會話創建一個身份驗證令牌。它將此身份驗證或 auth 令牌發送回客戶端??蛻舳藢⒋肆钆拼鎯υ谇岸?,并在每次后續請求中發送它。auth 令牌指定兩件事:它保存經過身份驗證的用戶的簽名,并代表處于經過身份驗證狀態的用戶。

身份驗證失敗的情況

此工作流程中可能存在多種漏洞。讓我們簡單討論一下。 

會話管理不佳

從您創建身份驗證令牌的那一刻起,它就成為驗證用戶是否登錄的唯一實體。這意味著您需要考慮以下問題: 

這些問題的答案共同決定了應用程序會話管理的強度。如果用戶的身份驗證令牌泄露給攻擊者,該用戶的帳戶和私人資源可能會受到損害。 

攻擊者可以以用戶的名義發出虛假請求并訪問他們的私人資源。 

還有其他場景,比如當用戶在公共網絡或設備上時。如果用戶忘記退出賬戶怎么辦?或者如果惡意的客戶端腳本從前端訪問身份驗證令牌怎么辦? 

如果您的工作流程沒有解決上述三個問題,您的用戶帳戶可能會受到損害。最終,由于應用程序中的會話管理不善,您將面臨身份驗證漏洞。

憑證薄弱

如果攻擊者設置的密碼很容易被猜到,那么他們如何才能阻止他們訪問用戶帳戶?弱憑證是身份驗證失敗的主要原因。但您可能會想,用戶設置的密碼實際上不受您的控制,對嗎? 

你說得對,他們不是。但這并不意味著你對此無能為力!弱憑證可以在很多方面被利用。當用戶生成全新密碼時,它可能會在創建帳戶時發生?;蛘?,如果你讓用戶重置舊密碼,它可能會在密碼重置期間發生。 

例如,假設用戶需要重置密碼,他們可以重新使用舊密碼之一。如果攻擊者過去曾截獲過該舊密碼,并且您允許用戶選擇舊密碼,那么同一個攻擊者就更容易猜出密碼,因為他們知道用戶經常重復使用密碼。這使得攻擊者更容易侵入用戶的帳戶。 

因此,評估密碼存儲方式、驗證密碼強度以及在身份驗證工作流中重置密碼非常重要?,F在讓我們繼續學習如何防止 Node.js 應用程序中的身份驗證失敗。

使用哈希存儲密碼

散列法可能看起來很明顯,但在身份驗證系統中仍然經常被忽略。您永遠不應該將密碼存儲為純文本。相反,您應該將它們散列為安全的加密值。另一個重要的做法是,您不應該著手創建自己的散列算法。 

加密是一個復雜的主題。最好留給專家去做,所以最安全的做法是使用一個值得信賴且流行的哈希庫。例如,您可以使用類似bcrypt 的東西。

const bcrypt = require('bcrypt');

//Generate Hashed Passwords when saving them to db
userSchema.pre('save', async function(next) {
const salt = await bcrypt.genSalt();
this.password = await bcrypt.hash(this.password, salt);
next();
});

//Validate passwords using bcrypt on login
userSchema.statics.login = async function(email, password) {
const user = await this.findOne({ email });
if (user) {
const auth = await bcrypt.compare(password, user.password);
if (auth) {
return user;
}
throw Error('incorrect password');
}
throw Error('incorrect email');
};

在上面的代碼中,我們使用 Mongoose 模型,使用 bcrypt 對密碼進行哈希處理。然后我們將這個哈希密碼保存在我們的數據庫中。對于登錄,我們讓 bcrypt 解密哈希密碼并將其與存儲的憑據進行比較,以驗證用戶的登錄詳細信息。

在整個過程中,服務器、數據庫開發人員或 bcrypt 都不知道用戶的密碼。這個標準流程是正確實施身份驗證的第一步,以防止身份驗證被破壞!

NodeJS 中的會話管理

會話管理在塑造身份驗證工作流程中起著至關重要的作用?,F在我們將看看如何通過對身份驗證 API 進行一些小改動來加強會話管理。 

以下是 Node.js 中登錄 REST API 的控制器: 

module.exports.LOGIN = async (req, res) => {
const { email, password } = req.body;

try {
const user = await User.login(email, password);
const token = uuidv4();
res.cookie('auth_token', token);
res.status(200).json({ user: user._id });
}
catch (err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}

}

在上面的 API 控制器中,我們使用 Mongoose 和 MongoDB 驗證憑據。如果憑據有效,我們將從 MongoDB 獲取用戶詳細信息。然后,在響應中,我們發送 UUID作為身份驗證令牌。 

使用安全可靠的 JWT 和 TTL

JWT代表 JSON Web Token。它是一個 JSON 對象,其中包含一些編碼信息,例如簽名。這是創建安全可靠的身份驗證令牌的標準方法。因此,在上面的控制器中,讓我們創建一個生成強大且安全的 JWT 的函數。 

您可以使用Node.js 中的jsonwebtoken庫來生成 JWT。我們將使用登錄用戶的 ID 作為簽名,并為我們的 JWT 設置 TTL。 

const jwt = require('jsonwebtoken');
...

const maxAge = 3 * 24 * 60 * 60;
const createToken = (id) => {
return jwt.sign({ id }, 'secret salt', {
expiresIn: maxAge
});
};

在jwt.sign方法的第二個參數中,我們添加了一個秘密關鍵字。為了演示,我采用了一些簡單的東西。但是,您必須并且應該使用更復雜的東西。 

我們的身份驗證令牌的 TTL 為三天,但您可以根據應用程序的需求進行調整。例如,您可以使用更少的天數。您還可以通過將其設置為取決于用戶登錄的時間、用戶從哪里登錄等來使其動態化。 

所以現在我們的登錄控制器變成:

module.exports.LOGIN = async (req, res) => {
const { email, password } = req.body;

try {
const user = await User.login(email, password);
const token = createToken(user._id);
res.cookie('jwt', token);
res.status(200).json({ user: user._id });
}
catch (err) {
const errors = handleErrors(err);
res.status(400).json({ errors });
}

}

太棒了!您剛剛使身份驗證工作流程更加安全,并降低了遇到身份驗證漏洞的可能性。讓我們繼續前進。 

NodeJS 失效身份驗證指南:示例和預防措施

我們將 JWT 或身份驗證令牌作為 cookie 發送。此 cookie 會自行設置到客戶端的瀏覽器。但是,此 cookie 并沒有什么特別之處。任何客戶端 JavaScript 實際上都可以訪問、修改或刪除該 cookie。此外,通過授予客戶端訪問 cookie 的權限,客戶端將承擔處理和管理用戶會話的部分責任。 

我們知道,客戶端代碼很容易通過瀏覽器訪問。這意味著客戶端驗證可以在前端輕松繞過。最佳實踐是讓服務器端到端處理會話管理。我們可以將此身份驗證令牌設為特殊的服務器端 cookie。這稱為HttpOnly cookie。只有設置此 cookie 的服務器才能訪問它。 

此外,HttpOnly cookie 會隨瀏覽器的每個請求自動發送。因此,服務器仍然完全負責整個身份驗證工作流程。

即使有人攻擊客戶端代碼,客戶端 JavaScript 也無法通過 JavaScript 訪問或修改 cookie。 

res.cookie('jwt', token, { httpOnly: true, maxAge: maxAge * 1000 });

我們還在 cookie 上設置了 TTL。請記住,身份驗證令牌的 TTL 表示會話持續時間,而 cookie 的 TTL 則表示該身份驗證令牌的生命周期。您需要確保同時實現這兩項功能,以實現萬無一失的身份驗證工作流程。

驗證服務器上的憑證強度

NodeJS 失效身份驗證指南:示例和預防措施

我們可以使用名為owasp-password-strength-tester 的庫在服務器端驗證用戶密碼的強度,該庫根據一些常見的準則來驗證密碼的強度。 

您可以通過運行以下命令來安裝它: 

npm install owasp-password-strength-test

然后,如下所示導入它: 

const owasp = require('owasp-password-strength-test');

接下來,我們可以相應地修改我們的注冊控制器:

module.exports.SIGNUP = async (req, res) => {
const { email, password } = req.body;

try {
const result = owasp.test(password);
if(!result.strong){
res.status(401).json({error:result.errors})
}
...
}
catch(err) {
...
}

}

現在,如果用戶的密碼較弱,您的 SignUp API 會發送錯誤。此錯誤中會說明密碼缺少哪些內容以確保其安全??蛻舳丝梢允褂么诵畔⒆層脩暨x擇更強的密碼。 

結論

總而言之,以下是您的服務器為防止身份驗證中斷需要做的: 

文章來源:NodeJS Broken Authentication Guide: Examples and Prevention

上一篇:

SEO關鍵詞擴展、歸類和內容布局方法

下一篇:

.NET HTTP 嚴格傳輸安全指南:是什么及如何啟用
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費