Kodokon kodokon.com

प्रमाणीकरण: हैशिंग, सेशन बनाम JWT

पासवर्ड को एक महँगे फ़ंक्शन से हैश करें, पूरी जानकारी के साथ सेशन और JWT के बीच चुनाव करें, और मिडलवेयर से अपने रूट की रक्षा करें।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

पासवर्ड संग्रहीत करने का मतलब है भविष्य की किसी सेंधमारी के लिए तैयार रहना: हैशिंग को इस तरह डिज़ाइन करें कि वह डेटाबेस की चोरी से भी बची रहे। SHA-256 जैसे तेज़ हैश को GPU पर प्रति सेकंड अरबों प्रयासों की दर से ब्रूट-फ़ोर्स किया जा सकता है। आपको एक जानबूझकर महँगे फ़ंक्शन की ज़रूरत है - scrypt, जो node:crypto द्वारा दिया जाता है, या bcrypt/argon2 - और हर उपयोगकर्ता के लिए एक यादृच्छिक सॉल्ट, जो पूर्व-गणना की गई तालिकाओं को बेकार कर देता है। सॉल्ट कोई रहस्य नहीं है: इसे हैश के बगल में सादे टेक्स्ट में संग्रहीत किया जाता है।

JAVASCRIPT
import {
  randomBytes,
  scryptSync,
  timingSafeEqual,
} from 'node:crypto';

export function hashPassword(password) {
  const salt = randomBytes(16).toString('hex');
  const hash = scryptSync(password, salt, 64)
    .toString('hex');
  return `${salt}:${hash}`;
}

export function verifyPassword(password, stored) {
  const [salt, hash] = stored.split(':');
  const candidate = scryptSync(password, salt, 64);
  const expected = Buffer.from(hash, 'hex');
  return timingSafeEqual(candidate, expected);
}
यादृच्छिक सॉल्ट, महँगी व्युत्पत्ति, स्थिर-समय तुलना।

उपयोगकर्ता को लॉग-इन बनाए रखने के दो मॉडल। सेशन: एक httpOnly कुकी में एक अपारदर्शी पहचानकर्ता, जिसकी स्थिति सर्वर की ओर होती है। तत्काल निरसन, JavaScript के लिए अदृश्य कुकी, लेकिन जैसे ही आप दूसरा इंस्टेंस जोड़ते हैं, एक साझा स्टोर (Redis) आवश्यक हो जाता है। JWT: टोकन में अंतर्निहित हस्ताक्षरित स्थिति, बिना किसी स्टोर के सत्यापन योग्य - सर्विसों के बीच आदर्श - लेकिन समाप्ति से पहले अनिरसनीय। ईमानदार समझौता: एक क्लासिक वेब एप्लिकेशन के लिए सेशन, तीसरे पक्षों द्वारा उपयोग की जाने वाली API या वितरित आर्किटेक्चर के लिए अल्पजीवी JWT।

JAVASCRIPT
import jwt from 'jsonwebtoken';

const SECRET = process.env.JWT_SECRET;
if (!SECRET) {
  throw new Error('JWT_SECRET must be set');
}

export function signToken(user) {
  return jwt.sign(
    { sub: user.id, email: user.email },
    SECRET,
    { expiresIn: '15m' },
  );
}
स्टार्टअप पर सीक्रेट आवश्यक, छोटे जीवनकाल वाले टोकन।

सुरक्षा मिडलवेयर एक्सेस नियंत्रण को अलग निकाल देता है: यह Authorization: Bearer हेडर से टोकन निकालता है, उसे सत्यापित करता है, डिकोड की गई पहचान को req.user से जोड़ता है, या पिछले पाठ के एरर मिडलवेयर की ओर भेजे गए एक 401 के साथ बात को वहीं ख़त्म कर देता है। इसे रूट-दर-रूट के बजाय रूट के पूरे समूह की रक्षा के लिए राउटर स्तर पर (router.use(requireAuth)) लागू करें।

JAVASCRIPT
import jwt from 'jsonwebtoken';
import { HttpError } from './http-error.js';

const SECRET = process.env.JWT_SECRET;

export function requireAuth(req, res, next) {
  const header = req.headers.authorization ?? '';
  const [scheme, token] = header.split(' ');
  if (scheme !== 'Bearer' || !token) {
    return next(new HttpError(401, 'Missing token'));
  }
  try {
    req.user = jwt.verify(token, SECRET);
    next();
  } catch {
    next(new HttpError(401, 'Invalid or expired token'));
  }
}
सत्यापित करो, req.user जोड़ो, या 401 - इसके अलावा कुछ नहीं।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. पासवर्ड संग्रहीत करने के लिए अकेला SHA-256 अनुपयुक्त क्यों है?
    • क्योंकि यह एल्गोरिथ्म क्रिप्टोग्राफ़िक रूप से टूट चुका है
    • क्योंकि यह बहुत तेज़ है: एक GPU प्रति सेकंड अरबों उम्मीदवारों की जाँच करता है; आपको एक धीमे, सॉल्टेड फ़ंक्शन की ज़रूरत है
    • क्योंकि यह छोटे पासवर्ड पर टकराव उत्पन्न करता है
    • क्योंकि Node इसे नेटिव रूप से लागू नहीं करता
  2. कौन सी व्यवस्था आपको किसी भी समाप्ति से पहले, तुरंत एक्सेस निरस्त करने देती है?
    • JWT, क्योंकि इसमें इसकी समाप्ति तिथि अंतर्निहित है
    • सर्वर-साइड सेशन, क्योंकि आप बस स्टोर से इसकी प्रविष्टि हटा देते हैं
    • दोनों, समान रूप से
  3. पासवर्ड सत्यापन में timingSafeEqual किस लिए है?
    • दोनों हैश की तुलना को तेज़ करने के लिए
    • स्थिर समय में तुलना करने के लिए ताकि प्रतिक्रिया की अवधि यह उजागर न करे कि कितने बाइट मेल खाते हैं
    • हेक्साडेसिमल हैश को Buffer में बदलने के लिए