From c059a2eabd469ef69770defce2e5623aa13174f0 Mon Sep 17 00:00:00 2001 From: "saito.k" Date: Mon, 11 Mar 2024 07:26:01 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20815:=20XMLHttpRequest=E3=81=AB?= =?UTF-8?q?=E3=81=A6=E3=83=AA=E3=82=AF=E3=82=A8=E3=82=B9=E3=83=88=E3=83=98?= =?UTF-8?q?=E3=83=83=E3=83=80=E3=83=BC=E3=80=8CX-Requested-With:=20XMLHttp?= =?UTF-8?q?Request=E3=80=8D=E3=82=92=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=A2=E3=82=A6=E3=83=88=E3=81=97=E3=81=A6=E3=81=84=E3=82=8C?= =?UTF-8?q?=E3=81=B0=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=E3=81=AF=E3=81=9A=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task1806: XMLHttpRequestにてリクエストヘッダー「X-Requested-With: XMLHttpRequest」をコメントアウトしていればコメントアウトはずす](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1806) - 以下の開発規約に準拠するように修正 - 可能な限り、JSONの場合(JSONPではない場合)は、XMLHttpRequestにてリクエストヘッダー「X-Requested-With: XMLHttpRequest」を設定し、サーバー側でチェックすること。 - Client - APIリクエスト時に、ヘッダーに「X-Requested-With: XMLHttpRequest」を付ける - server - ヘッダーをチェックするミドルウェアを実装 - /healthは画面からのリクエストではないので除外している - ミドルウェアをローカル環境以外で使用するように実装 - ローカル環境ではサーバーから静的ファイルを配信しているから - APIリクエスト以外のリクエストにもmiddlewareが適用されてしまうのでローカル環境は除外している ## レビューポイント - この修正で開発規約に準拠しているといえるか - ローカル環境は除外したが、問題ないか - ローカルとdev,stg,prodで差異があることで、ローカルだけ発生しない問題が生じる可能性がある(その逆も) - 基本的に特定のヘッダーがあるかというチェックを追加しただけなので、大きな問題が発生するとは考えづらい ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## クエリの変更 - Repositoryを変更し、クエリが変更された場合は変更内容を確認する - Before/Afterのクエリ - クエリ置き場 ## 動作確認状況 - ローカルで確認、develop環境で確認 - 行った修正がデグレを発生させていないことを確認できるか - 事前にdev環境でAPI呼び出しができることを確認 - すべてのAPIの呼び出しを確認したわけではないが、ログイン等の基本的な操作はできることを確認した ## 補足 - 相談、参考資料などがあれば --- dictation_client/src/App.tsx | 9 ++++++ dictation_server/src/app.module.ts | 10 +++++- .../src/common/check-header.middleware.ts | 32 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 dictation_server/src/common/check-header.middleware.ts diff --git a/dictation_client/src/App.tsx b/dictation_client/src/App.tsx index f08dfd1..f730016 100644 --- a/dictation_client/src/App.tsx +++ b/dictation_client/src/App.tsx @@ -17,7 +17,16 @@ const App = (): JSX.Element => { const { instance } = useMsal(); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [t, i18n] = useTranslation(); + useEffect(() => { + // すべてのリクエストのヘッダーにX-Requested-Withを追加 + globalAxios.interceptors.request.use((config) => { + // headersがあれば追加、なければ新規作成 + config.headers = config.headers || {}; + // X-Requested-Withを追加 + config.headers["X-Requested-With"] = "XMLHttpRequest"; + return config; + }); const id = globalAxios.interceptors.response.use( (response: AxiosResponse) => response, (e: AxiosError<{ code?: string }>) => { diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index 667cde8..4022501 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -52,6 +52,7 @@ import { WorkflowsRepositoryModule } from './repositories/workflows/workflows.re import { TermsModule } from './features/terms/terms.module'; import { RedisModule } from './gateways/redis/redis.module'; import * as redisStore from 'cache-manager-redis-store'; +import { CheckHeaderMiddleware } from './common/check-header.middleware'; @Module({ imports: [ ServeStaticModule.forRootAsync({ @@ -164,6 +165,13 @@ import * as redisStore from 'cache-manager-redis-store'; }) export class AppModule { configure(consumer: MiddlewareConsumer) { - consumer.apply(LoggerMiddleware).forRoutes(''); + consumer + .apply(LoggerMiddleware) + .forRoutes(''); + // stage=localの場合はmiddlewareを適用しない + // ローカル環境ではサーバーから静的ファイルも返すため、APIリクエスト以外のリクエストにもmiddlewareが適用されてしまう + if (process.env.STAGE !== 'local') { + consumer.apply(CheckHeaderMiddleware).forRoutes(''); + } } } diff --git a/dictation_server/src/common/check-header.middleware.ts b/dictation_server/src/common/check-header.middleware.ts new file mode 100644 index 0000000..359b2e0 --- /dev/null +++ b/dictation_server/src/common/check-header.middleware.ts @@ -0,0 +1,32 @@ +import { + HttpException, + Injectable, + Logger, + NestMiddleware, +} from '@nestjs/common'; +import { Request, Response, NextFunction } from 'express'; + +/** + * CheckHeaderMiddleware + * リクエストヘッダのチェックを行うミドルウェア + * + * ローカル環境ではヘッダチェックを行わない + */ +@Injectable() +export class CheckHeaderMiddleware implements NestMiddleware { + private readonly logger = new Logger(CheckHeaderMiddleware.name); + use(req: Request, res: Response, next: NextFunction): void { + // /healthcheckはheaderチェックを行わない + if (req.url === '/health') { + next(); + return; + } + + if (req.headers['x-requested-with'] === 'XMLHttpRequest') { + next(); + } else { + this.logger.error('header check failed'); + throw new HttpException('header check failed', 400); + } + } +}