【最佳实践】如何修改 Express 服务响应头?

📘 欢迎关注博主的掘金:暮星的主页



背景

最近在尝试修复工作项目中 Express 服务的 WebInspect 扫描报告指出的漏洞,其中有涉及到需要修改服务响应头的部分。以前没怎么研究过 Express,正好借此机会实践一下。

📣 版本
node : 14.17.6
express : 4.17.1


关于 WebInspect

Micro Focus Fortify WebInspectMicro Focus 公司旗下的一款企业级 Web 应用程序安全分析产品。

如今,很多代码管理制度完善的公司都把 WebInspect Scan 作为常规化 Security Scan 的其中一环,甚至集成到 CI/CD 流程中。

通常使用它的方式就是把要扫描的 Web url 或者 API url(基于所选择的扫描类型) 提供给 WebInspect 客户端,根据引导进行一些设置后开始扫描。

在这里插入图片描述
扫描过程中 WebInspect 会根据应用程序的行为和环境,多次从多角度进行定制访问攻击,找出可能存在的安全漏洞,并将它们归为 CriticalHighMediumLow 等几个风险等级,最终生成 Scan Report,其中会提供漏洞说明、解决方案、预防未来等内容。


报告分析

从扫描报告来看,目前应用有以下几个 vulnerability:

  • Cached SSL Content
  • Browser Mime Sniffing is not disabled
  • Missing HTTP Strict-Transport-Security Header
  • Inadequate Cross Site Scripting Header Protection

报告指出这些漏洞都与响应头有关,要么是某个字段的值有风险,要么是缺少了某个字段。
于是我在本地把项目 run 起来,随便找了个响应的资源查看响应头。

在这里插入图片描述
结果确实和报告的描述一致,而按照报告的修复建议,我需要对所有请求的响应头做如下更改:

    // 修改字段
    Cache-Control: no-store           // fix --> Cached SSL Content
    
    // 添加字段
    X-Content-Type-Options: nosniff   // fix --> Browser Mime Sniffing is not disabled
    X-XSS-Protection: 1; mode=block   // fix --> Inadequate Cross Site Scripting Header Protection
    Strict-Transport-Security: 3600   // fix --> Missing HTTP Strict-Transport-Security Header

具体为什么添加某个字段,可以修复某个漏洞,本文不做深究。
如感兴趣,可根据列出的漏洞名目,自行搜索。


修复

首先看看现有的服务架构:

    // ... other code ...
    const express = require('express');
    const app = express();
    
    const port = xxx;
    const targetDir = xxx;
    
    app.use(express.static(targetDir));
    app.listen(port, async function() { xxx });
    // ... other code ...

嗯…很经典的静态资源服务器写法,服务所有要访问的静态资源都放到了 targetDir 下,app.listen 开启一个端口来监听所有的 HTTP 请求,然后用 app.use 将所有来自 '/' 及其子路径下的请求先交给 Express 内置的提供静态资源服务的中间件 express.static 处理,让其提供 targetDir 下的对应文件。

于是,我们主要有两种方法在此基础上修改所有请求的响应头:

  • 在路由之前放置一个中间件,统一修改请求的响应头
    // ... other code ...
    const express = require('express');
    const app = express();
    
    const port = xxx;
    const targetDir = xxx;
    
    app.use((req, res, next) => {
        res.set('X-Content-Type-Options', 'nosniff');
        res.set('Cache-Control', 'no-store');
        res.set('X-XSS-Protection', '1; mode=block');
        res.set('Strict-Transport-Security', '3600');
        next();
    });
    
    app.use(express.static(targetDir));
    app.listen(port, async function() { xxx });
    // ... other code ...
  • 偶然看到 express.static 有额外的参数 setHeaders,可以在提供静态资源的时候,为其设置响应头,点此了解详情
    // ... other code ...
    const express = require('express');
    const app = express();
    
    const port = xxx;
    const targetDir = xxx;
    
    let options = {
        setHeaders: (res, path, stat) => {
            res.set('X-Content-Type-Options', 'nosniff');
            res.set('Cache-Control', 'no-store');
            res.set('X-XSS-Protection', '1; mode=block');
            res.set('Strict-Transport-Security', '3600');
        }
    };
    
    app.use(express.static(targetDir, options));
    app.listen(port, async function() { xxx });
    // ... other code ...

OK,生效了,收工下班 ╰(‵□′)╯

在这里插入图片描述


写在最后

One day you’ll leave this world behind. So live a life you will remember ! — Avicii

我是暮星,一枚有志于在前端领域证道的攻城狮。

优质前端内容持续输出中…,欢迎点赞 + 关注 + 收藏

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUSK-STAR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值