/ / Cách bảo mật API REST của Node.js bằng mã thông báo web JSON

Cách bảo mật API REST của Node.js bằng mã thông báo web JSON

Khi bạn đang xây dựng một ứng dụng, điều quan trọng là bạn phải bảo vệ dữ liệu nhạy cảm khỏi bị truy cập trái phép. Nhiều ứng dụng web, di động và đám mây hiện đại sử dụng API REST làm phương tiện giao tiếp chính. Do đó, điều quan trọng là phải thiết kế và phát triển các API phụ trợ với tính năng bảo mật được đặt lên hàng đầu.


Một cách tiếp cận hiệu quả để bảo mật API REST liên quan đến Mã thông báo Web JSON (JWT). Các mã thông báo này cung cấp một cơ chế mạnh mẽ để xác thực và ủy quyền người dùng, giúp bảo vệ các tài nguyên được bảo vệ khỏi sự truy cập của các tác nhân độc hại.


Mã thông báo web JSON là gì?

JSON Web Token (JWT) là một tiêu chuẩn bảo mật được sử dụng rộng rãi. Nó cung cấp một phương pháp ngắn gọn, khép kín để truyền dữ liệu một cách an toàn giữa ứng dụng khách và hệ thống phụ trợ.

API REST có thể sử dụng JWT để xác định và xác thực người dùng một cách an toàn khi họ thực hiện các yêu cầu HTTP để truy cập các tài nguyên được bảo vệ.

Một ví dụ về mã thông báo JWT được mã hóa ở bên trái và phiên bản đã giải mã của mã thông báo hiển thị các thành phần riêng lẻ ở bên phải.

Mã thông báo web JSON bao gồm ba phần riêng biệt: tiêu đề, tải trọng và chữ ký. Nó mã hóa từng phần và nối chúng bằng dấu chấm (“.”).

Tiêu đề mô tả thuật toán mật mã được sử dụng để ký mã thông báo, trong khi tải trọng chứa dữ liệu về người dùng và bất kỳ siêu dữ liệu bổ sung nào.

Cuối cùng, chữ ký, được tính bằng tiêu đề, tải trọng và khóa bí mật, đảm bảo tính toàn vẹn và tính xác thực của mã thông báo.

Với những điều cơ bản về JWT, hãy xây dựng API REST của Node.js và triển khai JWT.

Thiết lập Ứng dụng Express.js và Cơ sở dữ liệu MongoDB

Tại đây, bạn sẽ tìm hiểu cách xây dựng API REST xác thực đơn giản xử lý cả chức năng đăng ký và đăng nhập. Sau khi quá trình đăng nhập xác thực người dùng, họ sẽ có thể thực hiện các yêu cầu HTTP tới một tuyến API được bảo vệ.

Để bắt đầu, hãy tạo một máy chủ web Express và cài đặt các gói sau:

 npm install cors dotenv bycrpt mongoose cookie-parser crypto jsonwebtoken mongodb 

Tiếp theo, tạo cơ sở dữ liệu MongoDB hoặc định cấu hình cụm MongoDB trên đám mây. Sau đó sao chép chuỗi kết nối cơ sở dữ liệu, tạo một .env tệp trong thư mục gốc và dán vào chuỗi kết nối:

 CONNECTION_STRING="connection string" 

Định cấu hình kết nối cơ sở dữ liệu

Tạo một cái mới tiện ích/db.js tập tin trong thư mục gốc của thư mục dự án của bạn. Trong tệp này, hãy thêm đoạn mã sau để thiết lập kết nối cơ sở dữ liệu bằng Mongoose.

 const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.CONNECTION_STRING);
    console.log("Connected to MongoDB!");
  } catch (error) {
    console.error("Error connecting to MongoDB:", error);
  }
};

module.exports = connectDB;

Xác định mô hình dữ liệu

Xác định lược đồ dữ liệu người dùng đơn giản bằng Mongoose. Trong thư mục gốc, tạo mới mô hình/user.model.js tập tin và thêm mã sau đây.

 const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  username: String,
  password: {
    type: String,
    required: true,
    unique: true,
  },
});

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

Xác định Bộ điều khiển cho các Tuyến API

Các chức năng của bộ điều khiển sẽ quản lý đăng ký và đăng nhập; chúng là một phần quan trọng của chương trình mẫu này. Trong thư mục gốc, tạo một bộ điều khiển/userControllers.js tập tin và thêm đoạn mã sau:

  1. Xác định bộ điều khiển đăng ký người dùng.
     const User = require('../models/user.model');
    const bcrypt = require('bcrypt');
    const { generateToken } = require('../middleware/auth');

    exports.registerUser = async (req, res) => {
      const { username, password } = req.body;

      try {
        const hash = await bcrypt.hash(password, 10);
        await User.create({ username, password: hash });
        res.status(201).send({ message: 'User registered successfully' });
      } catch (error) {
        console.log(error);
        res.status(500).send({ message: 'An error occurred!! ' });
      }
    };

    Đoạn mã này băm mật khẩu được cung cấp bằng cách sử dụng bcrypt, sau đó tạo một bản ghi người dùng mới trong cơ sở dữ liệu, lưu trữ tên người dùng và mật khẩu đã băm. Nếu đăng ký thành công, nó sẽ gửi phản hồi với thông báo thành công.

  2. Xác định bộ điều khiển đăng nhập để quản lý quá trình đăng nhập của người dùng:
     exports.loginUser = async (req, res) => {
      const { username, password } = req.body;

      try {
        const user = await User.findOne({ username });
      
        if (!user) {
          return res.status(404).send({ message: 'User not found' });
        }

        const passwordMatch = await bcrypt.compare(password, user.password);

        if (!passwordMatch) {
          return res.status(401).send({ message: 'Invalid login credentials' });
        }

        const payload = { userId: user._id };
        const token = generateToken(payload);
        res.cookie('token', token, { httpOnly: true });
        res.status(200).json({ message: 'Login successful'});
      } catch (error) {
        console.log(error);
        res.status(500).send({ message: 'An error occurred while logging in' });
      }
    };

    Khi người dùng gửi yêu cầu đến /đăng nhập route, họ phải chuyển thông tin đăng nhập xác thực của mình trong phần thân yêu cầu. Sau đó, mã sẽ xác minh các thông tin đăng nhập đó và tạo Mã thông báo Web JSON. Mã thông báo được lưu trữ an toàn trong cookie với httpOnly cờ được đặt thành đúng. Điều này ngăn JavaScript phía máy khách truy cập vào mã thông báo, bảo vệ chống lại các cuộc tấn công kịch bản chéo trang (XSS) tiềm ẩn.

  3. Cuối cùng, xác định một tuyến đường được bảo vệ:
     exports.getUsers = async (req, res) => {
      try {
        const users = await User.find({});
        res.json(users);
      } catch (error) {
        console.log(error);
        res.status(500).send({ message: 'An error occurred!!' });
      }
    };

    Bằng cách lưu trữ JWT trong cookie, các yêu cầu API tiếp theo từ người dùng được xác thực sẽ tự động bao gồm mã thông báo, cho phép máy chủ xác thực và ủy quyền cho các yêu cầu.

Tạo một Middleware xác thực

Bây giờ bạn đã xác định bộ điều khiển đăng nhập tạo mã thông báo JWT khi xác thực thành công, hãy xác định các chức năng xác thực phần mềm trung gian sẽ tạo và xác minh mã thông báo JWT.

Trong thư mục gốc, tạo một thư mục mới, phần mềm trung gian. Trong thư mục này, thêm hai tệp: auth.jsconfig.js.

Thêm mã này vào config.js:

 const crypto = require('crypto');

module.exports = {
  secretKey: crypto.randomBytes(32).toString('hex')
};

Mã này tạo một khóa bí mật ngẫu nhiên mới mỗi khi nó chạy. Sau đó, bạn có thể sử dụng khóa bí mật này để ký và xác minh tính xác thực của JWT. Sau khi người dùng được xác thực thành công, hãy tạo và ký JWT bằng khóa bí mật. Sau đó, máy chủ sẽ sử dụng khóa để xác minh rằng JWT hợp lệ.

Thêm đoạn mã sau vào auth.js trong đó xác định các hàm phần mềm trung gian tạo và xác minh JWT.

 const jwt = require('jsonwebtoken');
const { secretKey } = require('./config');

const generateToken = (payload) => {
  const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
  return token ;
};

const verifyToken = (req, res, next) => {
  const token = req.cookies.token;

  if (!token) {
    return res.status(401).json({ message: 'No token provided' });
  }

  jwt.verify(token, secretKey, (err, decoded) => {
    if (err) {
      return res.status(401).json({ message: 'Invalid token' });
    }

    req.userId = decoded.userId;
    next();
  });
};

module.exports = { generateToken, verifyToken };

Các tạoToken chức năng tạo JWT bằng cách ký tải trọng bằng khóa bí mật và đặt thời gian hết hạn trong khi xác minhToken chức năng đóng vai trò là phần mềm trung gian để xác minh tính xác thực và tính hợp lệ của mã thông báo được cung cấp.

Xác định các tuyến API

Tạo một cái mới tuyến/userRoutes.js tập tin trong thư mục gốc và thêm mã sau đây.

 const express = require('express');
const router = express.Router();
const userControllers = require('../controllers/userControllers');
const { verifyToken } = require('../middleware/auth');
router.post('/api/register', userControllers.registerUser);
router.post('/api/login', userControllers.loginUser);
router.get('/api/users', verifyToken, userControllers.getUsers);
module.exports = router;

Cập nhật điểm vào máy chủ của bạn

cập nhật của bạn máy chủ.js tập tin với mã sau đây.

 const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
require('dotenv').config();
const connectDB = require('./utils/db');
const cookieParser = require('cookie-parser');

connectDB();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(cookieParser());
const userRoutes = require('./routes/userRoutes');
app.use("https://www.smartreviewaz.com/", userRoutes);

app.listen(port, () => {
  console.log(`Server is listening at http://localhost:${port}`);
});

Để kiểm tra API REST, hãy khởi động máy chủ phát triển và thực hiện các yêu cầu API tới các điểm cuối đã xác định:

 node server.js 

Bảo mật các API REST của Node.js

Bảo mật API REST của Node.js không chỉ bằng cách sử dụng JWT, mặc dù chúng đóng vai trò quan trọng trong xác thực và ủy quyền, nhưng điều cần thiết là phải áp dụng phương pháp bảo mật toàn diện để bảo mật nhằm bảo vệ hệ thống phụ trợ của bạn. Bên cạnh JWT, bạn cũng nên xem xét triển khai HTTPS để mã hóa giao tiếp, xác thực và vệ sinh đầu vào, v.v.

Bằng cách kết hợp nhiều biện pháp bảo mật, bạn có thể thiết lập một khung bảo mật mạnh mẽ cho API REST của Node.js và giảm thiểu rủi ro truy cập trái phép, vi phạm dữ liệu và các mối đe dọa bảo mật khác.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *