CORS๋ฅผ ํ‰๋‚ด๋‚ธ, ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ„ ํ†ต์‹  ๋ฐฉ๋ฒ•

youngki
  • #Cryptographic coding
  • #Encryption
  • #Hash
  • #HMAC
  • #microservice
  • #fromm

๋“ค์–ด๊ฐ€๋ฉฐ

์•ˆ๋…•ํ•˜์„ธ์š”. ๋…ธ๋จธ์Šค์—์„œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๊ณ  ์žˆ๋Š” ์œ ์˜๊ธฐ์ž…๋‹ˆ๋‹ค.

ํšŒ์‚ฌ๊ฐ€ ์„ฑ์žฅํ•˜๋ฉด์„œ ํŠธ๋ž˜ํ”ฝ์ด ์ฆ๊ฐ€๋˜์–ด, ๋„๋ฉ”์ธ๋ณ„๋กœ ์„œ๋น„์Šค๊ฐ€ ๋ถ„ํ™”๋  ์ˆ˜ ๋ฐ–์— ์—†๊ณ , ๊ทธ์— ๋”ฐ๋ผ ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ๋„ ๋นˆ๋ฒˆํ•ด ์กŒ์Šต๋‹ˆ๋‹ค.
๊ธฐ์กด์—๋Š” ์ž์ฒด ์ƒ์„ฑ ๋ฉ”ํƒ€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ , AES-256 ์•”ํ˜ธํ™”๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์„ ํ–ˆ๋Š”๋ฐ, ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง ๊ณผ์ •์—์„œ ๋†’์€ CPU ์‚ฌ์šฉ๋ฅ ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์„œ๋ฒ„๊ฐ„์˜ ์ธ์ฆ์„ ์œ„ํ•ด, CORS์—์„œ ํžŒํŠธ๋ฅผ ์–ป์–ด ๋‚ด๋ถ€ ์„œ๋ฒ„๊ฐ„์˜ ํ†ต์‹ ์— ์ ์šฉํ•œ ๋ฐฉ๋ฒ•๊ณผ ๊ฐœ์„  ๊ฒฐ๊ณผ๋ฅผ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ

ํ”„๋กœ์ ํŠธ ๋ฐฐ๊ฒฝ

์กฐ์ง์ด ์ปค์ง€๊ณ , infra๊ฐ€ ๋งŽ์•„์ง€๋ฉด์„œ interface ๊ด€์ ์—์„œ ์ €ํฌ๋Š” gRPC๋ฅผ ๊ณ ๋ฏผํ•ด ๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ ๊ณผ์ •์—์„œ ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง์„ ๋ช‡๋ฒˆ ํ•˜๊ฒŒ๋˜์—ˆ๊ณ , ๊ทธ ๊ณผ์ •์—์„œ ๊ธฐ์กด์— ์„œ๋ฒ„ ๋‚ด๋ถ€๊ฐ„ ์ธ์ฆ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋˜ AES-256 ์•”ํ˜ธํ™” ๋ฐฉ์‹์˜ ๋†’์€ CPU ์‚ฌ์šฉ๋ฅ ๊ณผ ์ด๋กœ ์ธํ•œ ๋Š๋ฆฐ response time์„ ํ™•์ธํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„ ํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋˜ ์™€์ค‘์—, ์šฐ๋ฆฌ๊ฐ€ ์‰ฝ๊ฒŒ ์ ‘ํ•˜๊ณ  ์žˆ๋Š” CORS์—์„œ ํžŒํŠธ๋ฅผ ์–ป์–ด, ์ด๋ฅผ ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์— ์ ์šฉํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
์„ฑ๋Šฅ์  ๊ฐœ์„ ๋„ ํ•ด์•ผ๊ฒ ์ง€๋งŒ, ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์ด ๋งŽ์•„์ง€๋ฉด์„œ ์ ์  ๋Š˜์–ด๋‚˜๋Š” ๋‚ด๋ถ€ ์ธ์ฆ์šฉ ๋ฉ”ํƒ€ ์ •๋ณด, AES-256 ์ฝ”๋“œ๋„, ์ƒˆ ๋ฐฉ์‹์—์„œ๋Š” package๋กœ ๋งŒ๋“ค์–ด ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์˜ ์‰ฌ์šด ์‚ฌ์šฉ๋„ ๊ด€์‹ฌ์‚ฌ ์˜€์Šต๋‹ˆ๋‹ค.

Coding Theory

Coding Theory์— ๋‚˜์˜ค๋Š” ์ข…๋ฅ˜๋ฅผ ๊ฐ„๋‹จํžˆ ์ •๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • Source coding (Data compression)
    • Lossless
      • ZIP
    • Lossy
      • MP3, MPEG, JPEG
  • Channel coding (Error control)
    • Viterbi Decoder
    • Turbo Coding
  • Cryptographic coding (Encryption)
    • ์–‘๋ฐฉํ–ฅ
      • ๋Œ€์นญํ‚ค
        • AES-256
      • ๋น„๋Œ€์นญํ‚ค
        • RSA
    • ๋‹จ๋ฐฉํ–ฅ (Hash)
      • SHA-256
  • Line coding

monorepo package

monorepo์™€ nestjs๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด, package์— ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

@Module({
    imports: [ConfigModule],
    providers: [InternalOriginGuard, InternalAxiosService],
    exports: [InternalOriginGuard, InternalAxiosService]
})
export class InternalApiModule {}

์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์ด๋ผ ํ• ์ง€๋ผ๋„, client-server ๊ด€๊ณ„๋Š” ์กด์žฌํ•˜๋Š”๋ฐ,
InternalAxiosService๋Š” client์šฉ์ด๊ณ , InternalOriginGuard๋Š” server์šฉ์ด์ง€๋งŒ,
์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์—์„œ ์˜์›ํžˆ client ์—ญํ• ๋กœ, ํ˜น์€ server ์—ญํ• ๋กœ ๊ทœ์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๋‘˜์„ ๋ฌถ์–ด module๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ์˜ ๊ฐ ์„œ๋ฒ„๋Š” ์ž์‹ ์˜ API domain ๊ฐ’์„ origin ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
์ด origin ๊ฐ’๊ณผ, HMAC์˜ signature๋Š” InternalAxiosService๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋ถ™์–ด ๋‚˜๊ฐ€๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

InternalAxiosService

internal client์šฉ axios instance๋ฅผ ๋งŒ๋“ค์–ด, origin๊ณผ signature๋ฅผ ๋ถ™์—ฌ ๋ณด๋‚ด๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@Injectable()
export class InternalAxiosService {
  readonly #axiosInstance: AxiosInstance;

  constructor(private readonly configService: ConfigService) {
    const secretKey = this.configService.getOrThrow('INTERNAL_API_SECRET_KEY'); 
    const origin = this.configService.getOrThrow('INTERNAL_API_ORIGIN');

    this.#axiosInstance = axios.create();
    this.#axiosInstance.interceptors.request.use(config => {
      config.headers['origin'] = origin;
      config.headers['x-signature'] = crypto.createHmac('sha256', secretKey).update(origin).digest('hex');
      return config;
    });
  }

  get instance(): AxiosInstance {
    return this.#axiosInstance;
  }
}

InternalOriginGuard

internal server์šฉ guard๋ฅผ ๋งŒ๋“ค์–ด, origin๊ณผ signature๋ฅผ ํ™•์ธํ•˜๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@Injectable()
export class InternalOriginGuard implements CanActivate {
  readonly #INTERNAL_API_SECRET_KEY: string;
  readonly #INTERNAL_API_ALLOWS: string[];

  constructor(private readonly configService: ConfigService) {
    this.#INTERNAL_API_SECRET_KEY = this.configService.getOrThrow('INTERNAL_API_SECRET_KEY');
    this.#INTERNAL_API_ALLOWS = this.configService.getOrThrow('INTERNAL_API_ALLOWS');
  }

  canActivate(context: ExecutionContext): boolean {
    const request: Request = context.switchToHttp().getRequest();

    const origin = request.headers['origin'] as string;
    const signature = request.headers['x-signature'] as string;

    if (!origin || !signature) {
      throw new UnauthorizedException('Missing origin or signature');
    }

    const expectedSignature = crypto.createHmac('sha256', this.#INTERNAL_API_SECRET_KEY).update(origin).digest('hex');

    if (signature !== expectedSignature) {
      throw new UnauthorizedException('Invalid signature');
    }

    if (!this.#INTERNAL_API_ALLOWS.include(origin)) {
      throw new UnauthorizedException('Invalid origin');
    }

    return true;
  }
}
  1. header์— origin๊ณผ signature๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  2. ์„œ๋ฒ„์—์„œ๋„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” secretKey๋กœ signature๋ฅผ ๋งŒ๋“ค์–ด, header์˜ signature์™€ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฐ ์„œ๋ฒ„์—์„œ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” allowed origin list์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ ์šฉ

๋„๋ฉ”์ธ๋งˆ๋‹ค ์—ฌ๋Ÿฌ ์„œ๋ฒ„๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ, ํŠนํžˆ ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์ด ๋งŽ์€ membership server์— ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์–ผ๋งˆ์ „ membership server๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๋ชจ๋“  client(internal interface ๊ด€์ ์—์„œ client์ด์ง€๋งŒ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.)์— ์ƒˆ๋กœ์šด ๋ฐฉ์‹์˜ ํ†ต์‹ ๋ฐฉ์‹์„ ์ ์šฉํ•˜๊ณ  ๋‚˜์˜จ lambda ์„œ๋ฒ„์˜ ๋ณ€ํ™” ์ž…๋‹ˆ๋‹ค.

lambda_duration.png

๋งˆ์น˜๋ฉฐ

๋ฐ์ดํ„ฐ ์›๋ฌธ(plaintext)์ด ๋…ธ์ถœ๋˜๋ฉด ์•ˆ๋˜๋Š” ์˜์—ญ๊ณผ, ๋ฐ์ดํ„ฐ์˜ ๋ฌด๊ฒฐ์„ฑ(Integrity)์„ ๊ธฐ๋Œ€ํ•˜๋Š” ์˜์—ญ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์•”ํ˜ธํ™” ๋ฐฉ์‹์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ์„  ๋ฐ ๊ธฐ๋Œ€ ๊ฒฐ๊ณผ๋กœ๋Š”

  • monorepo package์—์„œ ์ œ๊ณตํ•˜๋Š” InternalAxiosService๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์ฒ˜๋Ÿผ ์ž๋™์œผ๋กœ origin์„ ๋ถ™์—ฌ์ฃผ์–ด, ๋ฐฑ์—”๋“œ ๋กœ์ง ๊ตฌํ˜„์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๊ณ ,
  • ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์—์„œ๋„ request์˜ origin์„ ์•Œ ์ˆ˜ ์žˆ์–ด, ๋””๋ฒ„๊น…์‹œ ์ถ”๊ฐ€์ ์ธ ๋„๊ตฌ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.
  • lambda์˜ duration ๊ฐœ์„ ์œผ๋กœ ๋น„์šฉ ์ ˆ๊ฐ๋„ ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

Art Changes Life

๋…ธ๋จธ์Šค์™€ ํ•จ๊ป˜ ์—”ํ„ฐํ…Œํฌ ์‚ฐ์—…์„ ํ˜์‹ ํ•ด๋‚˜๊ฐˆ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ฑ„์šฉ ์ค‘์ธ ๊ณต๊ณ  ๋ณด๊ธฐ