Merged PR 815: XMLHttpRequestにてリクエストヘッダー「X-Requested-With: XMLHttpRequest」をコメントアウトしていればコメントアウトはずす

## 概要
[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の呼び出しを確認したわけではないが、ログイン等の基本的な操作はできることを確認した

## 補足
- 相談、参考資料などがあれば
This commit is contained in:
saito.k 2024-03-11 07:26:01 +00:00
parent aca9bcf496
commit c059a2eabd
3 changed files with 50 additions and 1 deletions

View File

@ -17,7 +17,16 @@ const App = (): JSX.Element => {
const { instance } = useMsal(); const { instance } = useMsal();
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [t, i18n] = useTranslation(); const [t, i18n] = useTranslation();
useEffect(() => { 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( const id = globalAxios.interceptors.response.use(
(response: AxiosResponse) => response, (response: AxiosResponse) => response,
(e: AxiosError<{ code?: string }>) => { (e: AxiosError<{ code?: string }>) => {

View File

@ -52,6 +52,7 @@ import { WorkflowsRepositoryModule } from './repositories/workflows/workflows.re
import { TermsModule } from './features/terms/terms.module'; import { TermsModule } from './features/terms/terms.module';
import { RedisModule } from './gateways/redis/redis.module'; import { RedisModule } from './gateways/redis/redis.module';
import * as redisStore from 'cache-manager-redis-store'; import * as redisStore from 'cache-manager-redis-store';
import { CheckHeaderMiddleware } from './common/check-header.middleware';
@Module({ @Module({
imports: [ imports: [
ServeStaticModule.forRootAsync({ ServeStaticModule.forRootAsync({
@ -164,6 +165,13 @@ import * as redisStore from 'cache-manager-redis-store';
}) })
export class AppModule { export class AppModule {
configure(consumer: MiddlewareConsumer) { 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('');
}
} }
} }

View File

@ -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);
}
}
}