Node.js面试题及详细答案120题(101-110) -- 安全与部署篇
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。
文章目录
- 一、本文面试题目录
- 101. Node.js应用常见的安全问题有哪些?如何防范?
- 常见安全问题及防范
- 102. 如何防止XSS攻击?在Node.js中有哪些措施?
- 防范措施
- 103. 什么是CSRF攻击?如何防范?
- 攻击原理
- 防范措施
- 104. 如何对密码进行加密存储?bcrypt模块的作用是什么?
- 加密存储流程
- bcrypt的作用
- 105. Node.js应用的部署流程是什么?需要注意哪些问题?
- 部署流程
- 注意事项
- 106. 如何在Docker中部署Node.js应用?
- 步骤1:创建Dockerfile
- 步骤2:创建.dockerignore文件
- 步骤3:构建镜像
- 步骤4:运行容器
- 步骤5:使用Docker Compose(多容器部署)
- 107. 什么是CI/CD?如何为Node.js应用配置CI/CD流程?
- 为Node.js应用配置CI/CD(以GitHub Actions为例)
- 流程说明
- 108. 如何监控Node.js应用的运行状态?有哪些工具?
- 监控指标
- 常用监控工具
- 109. 什么是环境变量?在Node.js中如何使用环境变量?
- 环境变量的优势
- 在Node.js中使用环境变量
- 110. 如何区分开发环境、测试环境和生产环境?
- 1. 通过`NODE_ENV`环境变量区分
- 2. 设置环境特定配置文件
- 3. 在启动命令中指定环境
- 环境差异实践
- 二、120道Node.js面试题目录列表
一、本文面试题目录
101. Node.js应用常见的安全问题有哪些?如何防范?
Node.js应用常见的安全问题主要集中在数据传输、输入验证和权限控制等方面,防范措施如下:
常见安全问题及防范
-
注入攻击(SQL注入、NoSQL注入)
- 风险:恶意输入篡改数据库查询(如
' OR '1'='1
)。 - 防范:使用参数化查询、ORM(如Sequelize),避免直接拼接用户输入到查询语句。
// 安全示例(参数化查询) db.query('SELECT * FROM users WHERE name = ?', [userInput]);
- 风险:恶意输入篡改数据库查询(如
-
跨站脚本攻击(XSS)
- 风险:注入恶意脚本,窃取cookie或篡改页面。
- 防范:输入过滤、输出编码,使用
helmet
设置Content-Security-Policy
。
const helmet = require('helmet'); app.use(helmet.contentSecurityPolicy({directives: { defaultSrc: ["'self'"] } }));
-
跨站请求伪造(CSRF)
- 风险:伪造用户请求执行未授权操作(如转账)。
- 防范:使用CSRF令牌(如
csurf
中间件)、验证Referer
/Origin
头。
-
不安全的依赖包
- 风险:第三方包存在漏洞(如
event-stream
事件)。 - 防范:定期用
npm audit
检查漏洞,使用package-lock.json
锁定版本。
- 风险:第三方包存在漏洞(如
-
敏感信息泄露
- 风险:日志或响应中包含密码、API密钥等。
- 防范:使用环境变量存储敏感信息,日志过滤敏感字段。
-
未限制的请求频率
- 风险:遭受DoS攻击或暴力破解。
- 防范:使用
express-rate-limit
限制请求频率。
const rateLimit = require('express-rate-limit'); app.use(rateLimit({ windowMs: 15*60*1000, max: 100 })); // 15分钟内最多100次请求
102. 如何防止XSS攻击?在Node.js中有哪些措施?
XSS(Cross-Site Scripting,跨站脚本攻击) 是攻击者在网页中注入恶意脚本,当用户访问时执行,窃取cookie或敏感信息。
防范措施
-
输入验证与过滤
- 限制输入格式(如只允许字母、数字),过滤
<script>
等危险标签。
const validator = require('validator'); const userInput = '<script>alert("xss")</script>'; const safeInput = validator.escape(userInput); // 转义为<script>...</script>
- 限制输入格式(如只允许字母、数字),过滤
-
输出编码
- 在模板渲染时自动编码特殊字符(如EJS的
<%= %>
、React的JSX)。
<!-- EJS模板安全输出 --> <div><%= userInput %></div> <!-- 自动转义特殊字符 -->
- 在模板渲染时自动编码特殊字符(如EJS的
-
使用安全HTTP头
- 通过
helmet
设置Content-Security-Policy
(CSP),限制脚本来源。
const helmet = require('helmet'); app.use(helmet({contentSecurityPolicy: {directives: {defaultSrc: ["'self'"], // 只允许本域资源scriptSrc: ["'self'", "trusted-cdn.com"] // 限制脚本来源}} }));
- 通过
-
设置cookie安全属性
HttpOnly
:防止JavaScript访问cookie。Secure
:仅通过HTTPS传输。SameSite
:限制跨站请求携带cookie。
res.cookie('sessionId', '123', {httpOnly: true,secure: process.env.NODE_ENV === 'production',sameSite: 'strict' });
-
避免危险API
- 禁用
eval()
、innerHTML
等直接执行HTML/脚本的方法,改用textContent
。
- 禁用
103. 什么是CSRF攻击?如何防范?
CSRF(Cross-Site Request Forgery,跨站请求伪造) 是攻击者诱导用户在已登录的情况下,向目标网站发送非预期请求(如转账、修改密码),利用用户的身份执行操作。
攻击原理
- 用户登录
bank.com
,浏览器保存认证cookie。 - 攻击者诱导用户访问
evil.com
,该网站自动发送POST /transfer
请求到bank.com
。 - 浏览器携带
bank.com
的cookie发送请求,服务器误认为是用户主动操作。
防范措施
-
使用CSRF令牌
- 服务器生成随机令牌并存储,页面表单包含令牌,提交时验证。
const csurf = require('csurf'); const csrfProtection = csurf({ cookie: true });// 生成令牌并传递到表单 app.get('/transfer', csrfProtection, (req, res) => {res.render('transfer', { csrfToken: req.csrfToken() }); });// 验证令牌 app.post('/transfer', csrfProtection, (req, res) => {res.send('转账成功'); });
表单中需包含令牌:
<form action="/transfer" method="POST"><input type="hidden" name="_csrf" value="<%= csrfToken %>"><button type="submit">转账</button> </form>
-
验证Referer/Origin头
- 检查请求的
Referer
或Origin
是否为信任的域名。
app.use((req, res, next) => {const referer = req.headers.referer || '';if (referer.startsWith('https://yourdomain.com')) {next();} else {res.status(403).send('CSRF检测到');} });
- 检查请求的
-
使用SameSite Cookie属性
- 设置
SameSite=Strict
或SameSite=Lax
,限制跨站请求携带cookie。
res.cookie('session', 'token', { sameSite: 'strict' });
- 设置
104. 如何对密码进行加密存储?bcrypt模块的作用是什么?
密码不能明文存储,需通过加密算法处理后再存入数据库。bcrypt
是Node.js中常用的密码加密模块,基于哈希算法并支持加盐(salt)。
加密存储流程
-
安装bcrypt
npm install bcrypt
-
密码加密与验证示例
const bcrypt = require('bcrypt'); const saltRounds = 10; // 加盐强度(值越大越安全,耗时越长)// 1. 注册时加密密码 async function registerUser(password) {// 生成盐并加密(自动处理盐的生成和存储)const hashedPassword = await bcrypt.hash(password, saltRounds);// 存储hashedPassword到数据库return hashedPassword; }// 2. 登录时验证密码 async function verifyPassword(inputPassword, storedHash) {// 比较输入密码与存储的哈希值const isMatch = await bcrypt.compare(inputPassword, storedHash);return isMatch; // true表示匹配,false不匹配 }// 使用示例 (async () => {const hash = await registerUser('user123');console.log('加密后:', hash); // $2b$10$...(包含盐和哈希结果)console.log(await verifyPassword('user123', hash)); // trueconsole.log(await verifyPassword('wrong', hash)); // false })();
bcrypt的作用
- 单向哈希:加密后无法逆向解密,只能通过比较验证。
- 自动加盐:每次加密生成随机盐(salt),相同密码加密结果不同。
- 抗暴力破解:通过调整
saltRounds
控制计算复杂度,减缓破解速度。
注意:避免使用MD5、SHA等弱哈希算法,它们容易被彩虹表破解。
105. Node.js应用的部署流程是什么?需要注意哪些问题?
Node.js应用部署是将开发完成的代码发布到生产环境的过程,流程及注意事项如下:
部署流程
-
代码准备
- 确保
package.json
正确配置(main
入口、scripts
命令)。 - 排除开发依赖(
dependencies
与devDependencies
区分)。 - 使用
.gitignore
忽略node_modules
、日志文件等。
- 确保
-
环境配置
- 生产环境变量(数据库地址、密钥等)通过环境变量或配置文件管理。
- 安装生产依赖:
npm install --production
。
-
服务器准备
- 安装Node.js(推荐LTS版本)和PM2(进程管理工具)。
# 安装PM2 npm install pm2 -g
-
上传代码
- 通过
scp
、git
或CI/CD工具(如Jenkins)上传代码到服务器。
scp -r ./app user@server:/path/to/app
- 通过
-
启动应用
- 用PM2启动应用,确保进程后台运行并自动重启。
pm2 start app.js --name "my-app" pm2 startup # 设置开机自启 pm2 save
-
配置反向代理
- 使用Nginx作为反向代理,处理静态资源、SSL终止和负载均衡。
# Nginx配置示例 server {listen 80;server_name yourdomain.com;location / {proxy_pass http://localhost:3000;proxy_set_header Host $host;} }
注意事项
-
安全问题
- 禁用
NODE_ENV=development
(避免暴露调试信息)。 - 启用HTTPS(通过Let’s Encrypt获取免费证书)。
- 限制服务器端口访问(仅开放80/443)。
- 禁用
-
性能优化
- 启用Node.js集群模式(
cluster
模块或PM2的-i max
)。 - 配置数据库连接池,避免频繁创建连接。
- 启用Node.js集群模式(
-
监控与日志
- 集成日志收集(如ELK Stack)和性能监控(如New Relic)。
- 定期备份数据库和配置文件。
-
版本管理
- 采用蓝绿部署或滚动更新,减少 downtime。
106. 如何在Docker中部署Node.js应用?
Docker通过容器化技术封装应用及其依赖,实现环境一致性和快速部署。部署Node.js应用步骤如下:
步骤1:创建Dockerfile
在项目根目录创建Dockerfile
:
# 基础镜像(Node.js LTS版本)
FROM node:18-alpine# 设置工作目录
WORKDIR /app# 复制package文件并安装依赖
COPY package*.json ./
RUN npm install --production # 只安装生产依赖# 复制应用代码
COPY . .# 暴露端口(与应用监听端口一致)
EXPOSE 3000# 启动命令
CMD ["node", "app.js"]
步骤2:创建.dockerignore文件
排除不必要的文件,减小镜像体积:
node_modules
npm-debug.log
.git
.gitignore
.env
步骤3:构建镜像
docker build -t my-node-app .
步骤4:运行容器
# 基础运行
docker run -d -p 80:3000 --name node-container my-node-app# 带环境变量运行
docker run -d -p 80:3000 \-e NODE_ENV=production \-e DB_HOST=mysql-container \--name node-container my-node-app# 挂载日志目录(持久化数据)
docker run -d -p 80:3000 \-v /host/logs:/app/logs \--name node-container my-node-app
步骤5:使用Docker Compose(多容器部署)
若需同时启动应用和数据库,创建docker-compose.yml
:
version: '3'
services:app:build: .ports:- "80:3000"depends_on:- dbenvironment:- DB_HOST=dbdb:image: mysql:8environment:- MYSQL_ROOT_PASSWORD=secret- MYSQL_DATABASE=appdbvolumes:- mysql-data:/var/lib/mysqlvolumes:mysql-data:
启动命令:docker-compose up -d
107. 什么是CI/CD?如何为Node.js应用配置CI/CD流程?
CI/CD(持续集成/持续部署) 是自动化软件开发流程:
- CI(持续集成):频繁合并代码到主分支,自动运行测试,尽早发现问题。
- CD(持续部署):通过自动化将通过测试的代码部署到生产环境。
为Node.js应用配置CI/CD(以GitHub Actions为例)
-
创建测试脚本
在package.json
中添加测试命令:{"scripts": {"test": "jest","lint": "eslint ."} }
-
创建GitHub Actions配置文件
在项目根目录创建.github/workflows/ci-cd.yml
:name: Node.js CI/CDon:push:branches: [ main ] # 监听main分支推送pull_request:branches: [ main ]jobs:# 持续集成阶段:测试和代码检查test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Use Node.jsuses: actions/setup-node@v4with:node-version: '18'cache: 'npm'- run: npm ci # 安装依赖- run: npm run lint # 代码检查- run: npm test # 运行测试# 持续部署阶段:部署到服务器deploy:needs: test # 依赖test job成功runs-on: ubuntu-latestif: github.ref == 'refs/heads/main' # 仅main分支触发steps:- uses: actions/checkout@v4# 通过SSH部署到服务器(示例)- name: Deploy to serveruses: appleboy/ssh-action@masterwith:host: ${{ secrets.SERVER_HOST }}username: ${{ secrets.SERVER_USER }}key: ${{ secrets.SSH_PRIVATE_KEY }}script: |cd /path/to/appgit pullnpm install --productionpm2 restart my-app
-
配置密钥
在GitHub仓库的Settings > Secrets
中添加:SERVER_HOST
:服务器IP或域名SERVER_USER
:服务器用户名SSH_PRIVATE_KEY
:用于登录服务器的私钥
流程说明
- 开发者推送代码到GitHub。
- 自动触发
test
任务:安装依赖、运行 lint 和测试。 - 测试通过后,
deploy
任务自动运行:通过SSH登录服务器,拉取代码并重启应用。
108. 如何监控Node.js应用的运行状态?有哪些工具?
监控Node.js应用可及时发现性能瓶颈和异常,常用工具和方法如下:
监控指标
- 系统指标:CPU使用率、内存占用、磁盘I/O、网络流量。
- 应用指标:请求响应时间、错误率、事件循环延迟、活跃连接数。
- 业务指标:用户注册量、订单转化率等。
常用监控工具
-
PM2(进程管理与基础监控)
- 功能:进程管理、内存/CPU监控、日志查看、自动重启。
# 安装PM2 npm install pm2 -g # 启动应用并命名 pm2 start app.js --name "my-app" # 查看监控面板 pm2 monit # 查看详细 metrics pm2 show my-app
-
Prometheus + Grafana
- 功能:时序数据收集、自定义仪表盘、告警。
- 实现步骤:
- 安装
prom-client
暴露指标:const promClient = require('prom-client'); const register = new promClient.Registry(); promClient.collectDefaultMetrics({ register });// 自定义指标 const httpRequestDuration = new promClient.Histogram({name: 'http_request_duration_ms',help: '请求耗时',labelNames: ['method', 'path'],buckets: [50, 100, 200] }); register.registerMetric(httpRequestDuration);// 暴露指标接口 app.get('/metrics', async (req, res) => {res.set('Content-Type', register.contentType);res.end(await register.metrics()); });
- 配置Prometheus抓取
/metrics
接口,Grafana可视化数据。
- 安装
-
APM工具(应用性能监控)
- New Relic、Datadog、Elastic APM:提供分布式追踪、错误分析、性能瓶颈定位。
-
日志监控
- ELK Stack(Elasticsearch + Logstash + Kibana):集中收集、分析日志。
- Winston + Papertrail:实时日志聚合与告警。
109. 什么是环境变量?在Node.js中如何使用环境变量?
环境变量是运行环境中设置的动态值,用于配置应用(如数据库地址、API密钥),避免硬编码敏感信息,实现环境隔离。
环境变量的优势
- 敏感信息(如密码)不暴露在代码中。
- 不同环境(开发、测试、生产)使用不同配置,无需修改代码。
- 便于CI/CD流程中动态注入配置。
在Node.js中使用环境变量
-
直接访问环境变量
Node.js通过process.env
对象访问环境变量:// 读取环境变量 const port = process.env.PORT || 3000; // 默认为3000 const dbHost = process.env.DB_HOST;console.log(`服务器启动在端口 ${port}`);
-
设置环境变量
- 命令行临时设置:
# Linux/macOS PORT=4000 DB_HOST=localhost node app.js# Windows(cmd) set PORT=4000 && node app.js# Windows(PowerShell) $env:PORT=4000; node app.js
- 命令行临时设置:
-
使用
.env
文件管理
用dotenv
库加载.env
文件中的环境变量:npm install dotenv
创建
.env
文件:PORT=3000 DB_HOST=localhost DB_USER=root DB_PASS=secret
在应用入口加载:
require('dotenv').config(); // 加载.env文件console.log(process.env.PORT); // 3000 console.log(process.env.DB_USER); // root
注意:
.env
文件包含敏感信息,需加入.gitignore
。
110. 如何区分开发环境、测试环境和生产环境?
区分环境是为了在不同阶段使用不同配置(如开发环境连接测试数据库,生产环境连接正式数据库),常用方法如下:
1. 通过NODE_ENV
环境变量区分
Node.js约定用NODE_ENV
标识环境,常见值:development
(开发)、test
(测试)、production
(生产)。
// 检测当前环境
const env = process.env.NODE_ENV || 'development';// 根据环境加载不同配置
const config = {development: {db: 'mongodb://localhost/dev_db',logLevel: 'debug'},test: {db: 'mongodb://localhost/test_db',logLevel: 'warn'},production: {db: process.env.DB_URL, // 生产环境从环境变量获取logLevel: 'info'}
}[env];console.log(`当前环境:${env}`);
console.log(`数据库地址:${config.db}`);
2. 设置环境特定配置文件
按环境拆分配置文件,通过环境变量加载对应文件:
config/default.js # 公共配置development.js # 开发环境配置test.js # 测试环境配置production.js # 生产环境配置
// config/index.js
const env = process.env.NODE_ENV || 'development';
const defaultConfig = require('./default');
const envConfig = require(`./${env}`);// 合并配置(环境配置覆盖公共配置)
module.exports = { ...defaultConfig, ...envConfig };
3. 在启动命令中指定环境
// package.json
{"scripts": {"start": "NODE_ENV=production node app.js","dev": "NODE_ENV=development nodemon app.js","test": "NODE_ENV=test jest"}
}
- 开发环境:
npm run dev
(使用开发配置,启用热重载) - 测试环境:
npm test
(使用测试数据库,运行测试用例) - 生产环境:
npm start
(使用生产配置,禁用调试输出)
环境差异实践
- 开发环境:启用详细日志、接口文档、热重载。
- 测试环境:使用独立测试数据库,自动运行测试。
- 生产环境:禁用调试信息、启用缓存、配置HTTPS、限制日志级别。
二、120道Node.js面试题目录列表
文章序号 | Node.js面试题120道 |
---|---|
1 | Node.js面试题及详细答案120道(01-15) |
2 | Node.js面试题及详细答案120道(16-30) |
3 | Node.js面试题及详细答案120道(31-42) |
4 | Node.js面试题及详细答案120道(43-55) |
5 | Node.js面试题及详细答案120道(56-68) |
6 | Node.js面试题及详细答案120道(69-80) |
7 | Node.js面试题及详细答案120道(81-92) |
8 | Node.js面试题及详细答案120道(93-100) |
9 | Node.js面试题及详细答案120道(101-110) |
10 | Node.js面试题及详细答案120道(111-120) |