【NestJS应用从0到1】9.安全①-防御XSS

708 阅读3分钟

服务端的安全十分重要,所以防止网络攻击是必须进行。一般攻击方式有CSRF,XSS,SQL注入等。服务端原理大致就是增加过滤条件及合法验证

这里不对XSS/CSRF攻击方式及原理描述不做详细介绍。各种技术博客已经讲的很详细了,如果不了解的话,可以自行搜索查看。

默认你对class-validator,class-transformer,guard,interceptor等已经了解

在这之前,先了解XSS一些基本知识

XSS,全称是Cross-Site Scripting(跨站脚本攻击),是一种常见的网络安全漏洞。它允许攻击者将恶意脚本注入到正常用户会看到的页面中。当其他用户浏览这些页面时,嵌入其中的恶意脚本将在他们的浏览器中执行,这可能导致用户数据被盗取、会话被劫持、恶意软件被下载等一系列问题。

防御

对于XSS,常见的防御手段包括

  • 对用户输入进行严格的过滤和转义
  • 使用内容安全策略(CSP)等。

Code it

在NestJS中,有一些配置是开箱即用,引用对应的插件会默认处理,如果你有自定义的需要,你可以在插件处配置一些自定义配置

下面分为两部分处理

  1. 过滤;使用 dompurify
  2. 增加csp头部;使用helmet

1.过滤危险Html内容

这里使用到dompurify,用来将文本中的一些危险html清除或者替换

它暂不支持转义html,我建议转义的操作前端处理,如果前端传递接口中出现了未转义的html标签内容,则表示是非正常提交传递直接清除即可。

代码逻辑

为了保证代码的可复用性和解耦,我们将使用class-transformer自定义一个转换的装饰器,在需要转换的Dto字段使用装饰器即可完成,无需在服务层进行特定的代码处理。

定义装饰器

注意:因为dompurify是在broswer环境上使用的,所以在服务端使用需要使用jsdom

// DOMPurify.transform.decorator.ts
import { TransformFnParams } from 'class-transformer';
import { JSDOM } from 'jsdom';
import * as DOMPurify from 'dompurify';
export const DOMPurifyTransform = ({ value }: TransformFnParams) => {
  if (typeof value === 'string') {
    const window = new JSDOM('').window;
    const purify = DOMPurify(window);
    const result = purify.sanitize(value);
    // 这里可以加入日志记录有XSS攻击出现
    // if(result !== value){
    //   console.log('XSS攻击', value)
    // }
    return result;
  }
  return value;
};

使用装饰器

import { DOMPurifyTransform } from '@/decorators/DOMPurify.transform.decorator';
import { Transform } from 'class-transformer';
import { IsNotEmpty, IsOptional, IsString, Length } from 'class-validator';

export class CreateArticleDto {
  @IsNotEmpty()
  @Length(5, 30)
  title: string;

  @Length(5, 8000)
  @IsNotEmpty()
  @Transform(DOMPurifyTransform)
  content: string;

  @IsNotEmpty()
  categoryId: string;
  creatorId?: string;
}

2.使用helmet增加csp头部

Helmet除了增加CSP头部,其实默认设置了以下头部信息:

  • Content-Security-Policy:一个强大的白名单,规定了页面上可以发生什么,从而减轻了许多攻击。
  • Cross-Origin-Opener-Policy:帮助对你的页面进行进程隔离。
  • Cross-Origin-Resource-Policy:阻止其他来源加载你的资源。
  • Origin-Agent-Cluster:将进程隔离更改为基于来源的。
  • Referrer-Policy:控制Referer头部信息。
  • Strict-Transport-Security:告诉浏览器偏好HTTPS。
  • X-Content-Type-Options:避免MIME类型嗅探。
  • X-DNS-Prefetch-Control:控制DNS预获取。
  • X-Download-Options:强制下载被保存(仅限Internet Explorer)。
  • X-Frame-Options:一个减轻点击劫持攻击的旧头部信息。
  • X-Permitted-Cross-Domain-Policies:控制Adobe产品(如Acrobat)的跨域行为。
  • X-Powered-By:关于Web服务器的信息。由于它可能被用于简单的攻击,因此被移除。
  • X-XSS-Protection:一个旨在减轻XSS攻击的旧头部信息,但实际上可能会使情况变得更糟,因此Helmet将其禁用。

引用及注册

因为我的项目使用的是Fastify,已经有官方插件所以这一步很简单 安装fastify-helmet包:

$ npm i --save fastify-helmet

fastify-helmet需要作为Fastify插件使用

import * as helmet from 'fastify-helmet';
app.register(helmet);

效果

引入Helmet后,你会发现你的Reponse中会出现如下头部,表示helmet正常工作啦

image.png

完结,撒花❀❀❀❀❀❀

下一部分是CSRF