MST

星途 面试题库

面试题:Node.js HTTP 服务安全防护体系的设计与优化

请设计一套完整的 Node.js HTTP 服务安全防护体系,包括但不限于身份认证与授权机制、数据加密传输、安全漏洞检测与修复流程,并且说明如何根据业务场景和性能需求对这套体系进行优化。
47.8万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

身份认证与授权机制

  1. 基本认证 通过在 HTTP 请求头中发送 Authorization 字段,格式为 Basic base64(username:password)。在 Node.js 中使用 http 模块可以这样验证:
const http = require('http');
const { Buffer } = require('buffer');

const server = http.createServer((req, res) => {
    const authHeader = req.headers.authorization;
    if (authHeader) {
        const parts = authHeader.split(' ');
        if (parts[0] === 'Basic') {
            const credentials = Buffer.from(parts[1], 'base64').toString('utf8');
            const [username, password] = credentials.split(':');
            // 验证用户名和密码
            if (username === 'validUser' && password === 'validPassword') {
                res.statusCode = 200;
                res.end('Authenticated');
            } else {
                res.statusCode = 401;
                res.setHeader('WWW-Authenticate', 'Basic realm="Access to the secure area"');
                res.end('Unauthorized');
            }
        }
    } else {
        res.statusCode = 401;
        res.setHeader('WWW-Authenticate', 'Basic realm="Access to the secure area"');
        res.end('Unauthorized');
    }
});

server.listen(3000, () => {
    console.log('Server running on port 3000');
});
  1. JSON Web Tokens (JWT)
  • 生成 JWT: 使用 jsonwebtoken 库,例如:
const jwt = require('jsonwebtoken');
const payload = { user_id: 1, username: 'exampleUser' };
const secretKey = 'your-secret-key';
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
  • 验证 JWT
const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key';

const verifyToken = (req, res, next) => {
    const token = req.headers['authorization']?.split(' ')[1];
    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: 'Unauthorized' });
        }
        req.user = decoded;
        next();
    });
};
  1. OAuth 2.0 可使用 oauth2-server 库实现。这是一种授权框架,允许第三方应用通过用户授权访问资源服务器上的资源。流程包括用户向授权服务器请求授权,授权服务器向第三方应用颁发授权码,第三方应用用授权码换取访问令牌等步骤。

数据加密传输

  1. HTTPS
  • 生成密钥和证书: 可以使用 OpenSSL 生成私钥和证书,例如:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
  • 在 Node.js 中使用 HTTPS
const https = require('https');
const fs = require('fs');

const options = {
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('cert.pem')
};

const server = https.createServer(options, (req, res) => {
    res.writeHead(200);
    res.end('Hello, HTTPS!\n');
});

server.listen(443, () => {
    console.log('Server running on port 443');
});
  1. 对称加密 使用 crypto 模块,例如 AES - 256 - CBC 加密:
const crypto = require('crypto');
const algorithm = 'aes - 256 - cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);

function encrypt(text) {
    const cipher = crypto.createCipheriv(algorithm, key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return encrypted;
}

function decrypt(text) {
    const decipher = crypto.createDecipheriv(algorithm, key, iv);
    let decrypted = decipher.update(text, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}
  1. 非对称加密 同样使用 crypto 模块,例如 RSA 加密:
const crypto = require('crypto');

const privateKey = crypto.generateKeyPairSync('rsa', {
    modulusLength: 4096,
    publicKeyEncoding: {
        type: 'pkcs1',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs1',
        format: 'pem'
    }
});

function encryptWithPublicKey(text, publicKey) {
    const buffer = Buffer.from(text, 'utf8');
    const encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString('hex');
}

function decryptWithPrivateKey(encryptedText, privateKey) {
    const buffer = Buffer.from(encryptedText, 'hex');
    const decrypted = crypto.privateDecrypt(privateKey, buffer);
    return decrypted.toString('utf8');
}

安全漏洞检测与修复流程

  1. 依赖项安全检测
  • 使用工具npm audit 是 npm 自带的安全审计工具,可检测项目依赖的包是否存在已知漏洞。例如,在项目根目录运行 npm audit 命令,它会扫描 package - lock.json 文件,列出所有存在安全问题的依赖及其漏洞详情。
  • 修复:对于低风险漏洞,可尝试升级相关依赖到最新版本,例如 npm install <package - name>@latest。对于高风险漏洞,若升级依赖不可行,可能需要寻找替代包或手动修复漏洞代码。
  1. 代码安全扫描
  • 使用工具ESLint 可结合安全插件(如 eslint - plugin - security)进行代码安全扫描。在项目中配置 .eslintrc.json 文件启用该插件,例如:
{
    "plugins": [
        "security"
    ],
    "rules": {
        "security/detect - no - direct - eval": "error",
        "security/detect - non - standard - require": "error"
    }
}

然后运行 eslint src(假设代码在 src 目录),它会检测代码中可能存在的安全风险,如使用 eval 函数、非标准的 require 调用等。

  • 修复:根据 ESLint 提示的错误信息修改代码,避免使用不安全的代码模式。
  1. 渗透测试
  • 工具:可以使用工具如 OWASP ZAP(Zed Attack Proxy)对 Node.js HTTP 服务进行渗透测试。配置 ZAP 指向 Node.js 服务的地址和端口,启动扫描。ZAP 会模拟各种攻击场景,如 SQL 注入、XSS 攻击等,检测服务是否存在相应漏洞。
  • 修复:根据 ZAP 报告的漏洞详情,在代码层面进行修复。例如,对于 SQL 注入漏洞,使用参数化查询代替直接拼接 SQL 语句;对于 XSS 漏洞,对用户输入进行严格的过滤和转义。

根据业务场景和性能需求优化

  1. 业务场景优化
  • 低流量、高安全场景:如果业务对安全性要求极高,流量相对较低,可采用更复杂的加密算法和严格的身份认证机制。例如,使用 RSA 4096 位非对称加密和多因素身份认证。虽然这些操作会消耗更多计算资源,但由于流量低,对整体性能影响较小。
  • 高流量、中等安全场景:对于高流量业务,优先考虑性能。可采用对称加密算法(如 AES - 256 - CBC)进行数据加密,因为其加密和解密速度较快。在身份认证方面,可使用 JWT 并设置合理的过期时间,减少频繁认证带来的性能开销。
  1. 性能需求优化
  • 缓存机制:对于不经常变化的数据,可引入缓存。例如使用 node - cache 库,在身份认证与授权环节,缓存已验证通过的用户信息,减少重复验证。在数据传输方面,缓存加密后的结果,避免重复加密相同数据。
  • 异步处理:在加密、身份认证等操作中,尽量使用异步函数。例如,在生成 JWT 或验证 JWT 时,使用 async/await 语法确保这些操作不会阻塞事件循环,提高服务的并发处理能力。
  • 负载均衡:如果性能需求极高,可采用负载均衡技术,如使用 Nginx 作为反向代理服务器,将请求均匀分配到多个 Node.js 实例上,提高整体服务的吞吐量。同时,在每个 Node.js 实例上优化安全防护体系的性能,确保不成为性能瓶颈。