## 限速
為了保護您的應用程序免受暴力攻擊,您必須實現某種速率限制。幸運的是,`NPM`上已經有很多各種中間件可用。其中之一是[express-rate-limit](https://github.com/nfriedly/express-rate-limit)。
```bash
$ npm i --save express-rate-limit
```
安裝完成后,將其應用為全局中間件。
```typescript
import * as rateLimit from 'express-rate-limit';
// somewhere in your initialization file
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
}),
);
```
如果在服務器和以太網之間存在負載均衡或者反向代理,Express可能需要配置為信任proxy設置的頭文件,從而保證最終用戶得到正確的IP地址。要如此,首先使用`NestExpressApplication`平臺[接口](https://docs.nestjs.com/first-steps#platform)來創建你的`app`實例,然后配置[trust proxy](https://expressjs.com/en/guide/behind-proxies.html)設置。
```TypeScript
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// see https://expressjs.com/en/guide/behind-proxies.html
app.set('trust proxy', 1);
```
> 如果使用 `FastifyAdapter`,用 [fastify-rate-limit](https://github.com/fastify/fastify-rate-limit)替換。
## 限速(新版)
保護應用程序免受暴力攻擊的常用技術是速率限制。 要開始使用,您需要安裝 `@nestjs/throttler` 包。
~~~bash
$ npm i --save @nestjs/throttler
~~~
安裝完成后,可以使用 `forRoot` 或 `forRootAsync` 方法將 `ThrottlerModule` 配置為任何其他 Nest 包。
~~~typescript
@Module({
imports: [
ThrottlerModule.forRoot({
ttl: 60,
limit: 10,
}),
],
})
export class AppModule {}
~~~
上面將為受保護的應用程序的路由設置 `ttl` 的全局選項、生存時間和限制、`ttl` 內的最大請求數。
導入模塊后,您可以選擇綁定 `ThrottlerGuard `的方式。 守衛部分中提到的任何類型的綁定都可以。 例如,如果您想全局綁定守衛,可以通過將此提供程序添加到任何模塊來實現:
~~~typescript
{
provide: APP_GUARD,
useClass: ThrottlerGuard
}
~~~
### 自定義
有時您可能希望將防護綁定到控制器或全局綁定,但希望禁用一個或多個端點的速率限制。 為此,您可以使用 `@SkipThrottle() `裝飾器來否定整個類或單個路由的節流器。 `@SkipThrottle() `裝飾器也可以接受一個布爾值,如果你想排除大部分控制器,但不是每條路由。
還有一個 `@Throttle() `裝飾器可以用來覆蓋全局模塊中設置的限制和 ttl,以提供更嚴格或更寬松的安全選項。 這個裝飾器也可以用于類或函數。 這個裝飾器的順序很重要,因為參數的順序是限制,ttl。
### 代理
如果您的應用程序在代理服務器后面運行,請檢查信任代理選項的特定 HTTP 適配器選項(`express` 和 `fastify`)并啟用它。 這樣做將允許您從 `X-Forwarded-For` 標頭中獲取原始 IP 地址,并且您可以覆蓋 `getTracker()` 方法以從標頭中而不是從 req.ip 中提取值。 以下示例適用于 `express` 和 `fastify`:
~~~ts
// throttler-behind-proxy.guard.ts
import { ThrottlerGuard } from '@nestjs/throttler';
import { Injectable } from '@nestjs/common';
@Injectable()
export class ThrottlerBehindProxyGuard extends ThrottlerGuard {
protected getTracker(req: Record<string, any>): string {
return req.ips.length ? req.ips[0] : req.ip; // individualize IP extraction to meet your own needs
}
}
// app.controller.ts
import { ThrottlerBehindProxyGuard } from './throttler-behind-proxy.guard';
@UseGuards(ThrottlerBehindProxyGuard)
~~~
>您可以在此處找到 [express](https://expressjs.com/en/api.html#req.ips) 和[fastify](https://www.fastify.io/docs/latest/Reference/Request/) 的 req Request 對象的 API。
### Websockets[#](#websockets)
該模塊可以與 websocket 一起使用,但它需要一些類擴展。 您可以擴展 ThrottlerGuard 并覆蓋 handleRequest 方法,如下所示:
~~~typescript
@Injectable()
export class WsThrottlerGuard extends ThrottlerGuard {
async handleRequest(
context: ExecutionContext,
limit: number,
ttl: number,
): Promise<boolean> {
const client = context.switchToWs().getClient();
const ip = client.conn.remoteAddress;
const key = this.generateKey(context, ip);
const ttls = await this.storageService.getRecord(key);
if (ttls.length >= limit) {
throw new ThrottlerException();
}
await this.storageService.addRecord(key, ttl);
return true;
}
}
~~~
>如果您使用的是 `@nestjs/platform-ws` 包,則可以改用 `client._socket.remoteAddress`。
### GraphQL[#](#graphql)
`ThrottlerGuard` 也可用于處理 GraphQL 請求。 同樣,可以擴展保護,但這次 `getRequestResponse` 方法將被覆蓋。
~~~typescript
@Injectable()
export class GqlThrottlerGuard extends ThrottlerGuard {
getRequestResponse(context: ExecutionContext) {
const gqlCtx = GqlExecutionContext.create(context);
const ctx = gqlCtx.getContext();
return { req: ctx.req, res: ctx.res }
}
}
~~~
### 配置
以下是`ThrottlerModule` 配置選項:
| | |
|--- |--- |
| `ttl` | 每個請求將在存儲中持續的秒數 |
|`limit` | TTL 限制內的最大請求數 |
|`ignoreUserAgents` | 在限制請求時要忽略的用戶代理正則表達式數組 |
|`storage` | 如何跟蹤請求的存儲設置 |
### 異步配置
您可能希望以異步方式而不是同步方式獲取限速配置。 您可以使用 `forRootAsync()` 方法,該方法允許依賴注入和異步方法。
一種方法是使用工廠函數:
~~~typescript
@Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
ttl: config.get('THROTTLE_TTL'),
limit: config.get('THROTTLE_LIMIT'),
}),
}),
],
})
export class AppModule {}
~~~
您還可以使用 useClass 語法:
~~~typescript
@Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
useClass: ThrottlerConfigService,
}),
],
})
export class AppModule {}
~~~
這是可行的,只要 `ThrottlerConfigService` 實現了接口 `ThrottlerOptionsFactory`。
### 存儲
內置存儲是一個內存緩存,它跟蹤發出的請求,直到它們通過全局選項設置的 TTL。 只要類實現 `ThrottlerStorage` 接口,您就可以將自己的存儲選項放入 `ThrottlerModule` 的存儲選項中。
對于分布式服務器,您可以使用 Redis 的社區存儲提供程序來獲得單一的事實來源。
>`ThrottlerStorage` 可以從 `@nestjs/throttler` 導入。
- 介紹
- 概述
- 第一步
- 控制器
- 提供者
- 模塊
- 中間件
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 自定義裝飾器
- 基礎知識
- 自定義提供者
- 異步提供者
- 動態模塊
- 注入作用域
- 循環依賴
- 模塊參考
- 懶加載模塊
- 應用上下文
- 生命周期事件
- 跨平臺
- 測試
- 技術
- 數據庫
- Mongo
- 配置
- 驗證
- 緩存
- 序列化
- 版本控制
- 定時任務
- 隊列
- 日志
- Cookies
- 事件
- 壓縮
- 文件上傳
- 流式處理文件
- HTTP模塊
- Session(會話)
- MVC
- 性能(Fastify)
- 服務器端事件發送
- 安全
- 認證(Authentication)
- 授權(Authorization)
- 加密和散列
- Helmet
- CORS(跨域請求)
- CSRF保護
- 限速
- GraphQL
- 快速開始
- 解析器(resolvers)
- 變更(Mutations)
- 訂閱(Subscriptions)
- 標量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 聯合類型
- 枚舉(Enums)
- 字段中間件
- 映射類型
- 插件
- 復雜性
- 擴展
- CLI插件
- 生成SDL
- 其他功能
- 聯合服務
- 遷移指南
- Websocket
- 網關
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 適配器
- 微服務
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定義傳輸器
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 獨立應用
- Cli
- 概述
- 工作空間
- 庫
- 用法
- 腳本
- Openapi
- 介紹
- 類型和參數
- 操作
- 安全
- 映射類型
- 裝飾器
- CLI插件
- 其他特性
- 遷移指南
- 秘籍
- CRUD 生成器
- 熱重載
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模塊
- Swagger
- 健康檢查
- CQRS
- 文檔
- Prisma
- 靜態服務
- Nest Commander
- 問答
- Serverless
- HTTP 適配器
- 全局路由前綴
- 混合應用
- HTTPS 和多服務器
- 請求生命周期
- 常見錯誤
- 實例
- 遷移指南
- 發現
- 誰在使用Nest?