You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Node.js搭建安全服务器?求基于Node.js+MongoDB的注册登录及支付功能开发的学习文档与课程推荐

Hey there! Let’s walk through building a secure Node.js server with MongoDB for user registration/login, and prep it for future payment functionality. I’ve broken this down into actionable steps, plus resources to level up your knowledge.

1. Base Project Setup

First, let’s lay the groundwork for your server:

  • Initialize your project: npm init -y
  • Install core dependencies: npm install express mongoose dotenv bcryptjs jsonwebtoken
  • Install dev dependencies (for validation and security tools): npm install --save-dev express-validator helmet express-rate-limit express-mongo-sanitize

Connect MongoDB Securely

Never hardcode database credentials—use environment variables with dotenv:

// server.js
const mongoose = require('mongoose');
require('dotenv').config();

async function connectDB() {
  try {
    await mongoose.connect(process.env.MONGODB_URI);
    console.log('MongoDB connected securely');
  } catch (err) {
    console.error('MongoDB connection failed:', err.message);
    process.exit(1); // Exit on connection failure
  }
}

connectDB();

Store your MONGODB_URI, JWT_SECRET, and other sensitive values in a .env file (add this to .gitignore to avoid accidental commits).

2. Secure Auth Implementation (Signup/Login)

The golden rule here: never store plaintext passwords. Use bcrypt for hashing, and JWT for session management.

User Model with Password Hashing

Create a Mongoose schema that automatically hashes passwords before saving:

// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    trim: true
  },
  password: {
    type: String,
    required: true,
    minlength: 8 // Enforce password complexity
  }
});

// Hash password before saving to DB
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 12); // 12 rounds of hashing
  next();
});

// Method to compare login password with stored hash
userSchema.methods.comparePassword = async function(candidatePassword) {
  return await bcrypt.compare(candidatePassword, this.password);
};

module.exports = mongoose.model('User', userSchema);

Signup/Login Routes with Validation

Use express-validator to sanitize and validate user input, and avoid leaking sensitive error details:

// routes/auth.js
const express = require('express');
const jwt = require('jsonwebtoken');
const { body, validationResult } = require('express-validator');
const User = require('../models/User');
const router = express.Router();

// Signup Route
router.post('/signup', [
  body('email').isEmail().withMessage('Enter a valid email'),
  body('password').isLength({ min: 8 }).withMessage('Password must be at least 8 characters')
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }

  const { email, password } = req.body;

  try {
    // Check if user already exists
    let user = await User.findOne({ email });
    if (user) {
      return res.status(400).json({ message: 'User already exists' });
    }

    user = new User({ email, password });
    await user.save();

    // Generate initial access token
    const accessToken = jwt.sign(
      { id: user._id },
      process.env.JWT_SECRET,
      { expiresIn: '15m' } // Short-lived access token for security
    );

    res.status(201).json({ accessToken });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: 'Server error' }); // Don't expose DB details
  }
});

// Login Route
router.post('/login', [
  body('email').isEmail(),
  body('password').notEmpty()
], async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }

  const { email, password } = req.body;

  try {
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    const isMatch = await user.comparePassword(password);
    if (!isMatch) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    const accessToken = jwt.sign(
      { id: user._id },
      process.env.JWT_SECRET,
      { expiresIn: '15m' }
    );

    // Use HttpOnly cookie for refresh tokens (prevents XSS attacks)
    const refreshToken = jwt.sign(
      { id: user._id },
      process.env.JWT_REFRESH_SECRET,
      { expiresIn: '7d' }
    );

    res.cookie('refreshToken', refreshToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production', // Only send over HTTPS in prod
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000
    });

    res.json({ accessToken });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;
3. Critical Security Hardening

These steps are non-negotiable for a production-ready server:

  • Enable HTTPS: Use Let’s Encrypt for free SSL certificates. In production, either use Node.js’s https module or reverse proxy with Nginx to handle SSL.
  • Add Security Middleware:
    • helmet(): Sets essential security HTTP headers (e.g., CSP, X-Frame-Options)
    • express-mongo-sanitize(): Prevents NoSQL injection attacks
    • express-rate-limit(): Blocks brute-force login attempts (limit to 5 requests per 15 minutes)
    • cors(): Restrict cross-origin requests to trusted domains only
  • Input Sanitization: Always sanitize user input to prevent XSS attacks—express-validator can help with this.
  • Error Handling: Never return detailed database errors to clients; use generic messages like "Server error".
  • Dependency Updates: Regularly run npm audit or use tools like Snyk to fix vulnerable dependencies.
4. Prep for Future Payment Features

If you plan to add payments later, keep these security best practices in mind:

  • Never store credit card data: Use payment providers like Stripe or PayPal’s tokenization systems instead.
  • Secure payment APIs: Store provider API keys in environment variables, and validate webhook signatures to prevent fake payment events.
  • Compliance: Follow PCI DSS guidelines if handling card payments (most providers handle this for you, but stay informed).
  • Audit Logs: Log all payment-related actions for debugging and compliance purposes.

Official Documentation

  • Express.js Docs: Covers routing, middleware, and security best practices in depth
  • Mongoose Docs: Learn to use MongoDB safely with Node.js’s most popular ODM
  • JWT Docs: Understand the standard and secure usage of JSON Web Tokens
  • bcrypt Docs: Master password hashing implementation details

Online Courses

  • Node.js Security Masterclass: Focuses exclusively on securing Node.js apps, including auth, authorization, and vulnerability mitigation
  • MongoDB for Node.js Developers: A hands-on course covering secure database design and querying
  • Full Stack Node.js Authentication: Builds a complete auth system with security best practices baked in

Books

  • Node.js Design Patterns: Includes sections on secure architecture design and pattern implementation
  • Web Security for Developers: Covers common web vulnerabilities (XSS, CSRF, injection) and how to defend against them in Node.js

内容的提问来源于stack exchange,提问作者Alena Igorevna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 08:47:39