CORS๋ฅผ ํ๋ด๋ธ, ๋ฐฑ์๋ ์๋ฒ๊ฐ ํต์ ๋ฐฉ๋ฒ
- #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
- Lossless
- 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;
}
}
- header์ origin๊ณผ signature๊ฐ ์๋์ง ํ์ธํฉ๋๋ค.
- ์๋ฒ์์๋ ๊ฐ์ง๊ณ ์๋ secretKey๋ก signature๋ฅผ ๋ง๋ค์ด, header์ signature์ ๋น๊ตํฉ๋๋ค.
- ๊ฐ ์๋ฒ์์ ๊ฐ์ง๊ณ ์๋ allowed origin list์ ํฌํจ๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
์ ์ฉ
๋๋ฉ์ธ๋ง๋ค ์ฌ๋ฌ ์๋ฒ๊ฐ ์กด์ฌํ์ง๋ง, ํนํ ์๋ฒ๊ฐ ํต์ ์ด ๋ง์ membership server์ ์ ์ฉํ์์ต๋๋ค.
์ผ๋ง์ membership server๋ฅผ ๋ด๋ถ์ ์ผ๋ก ํธ์ถํ๋ ๋ชจ๋ client(internal interface ๊ด์ ์์ client์ด์ง๋ง ๋ฐฑ์๋ ์๋ฒ์
๋๋ค.)์ ์๋ก์ด ๋ฐฉ์์ ํต์ ๋ฐฉ์์ ์ ์ฉํ๊ณ ๋์จ lambda ์๋ฒ์ ๋ณํ ์
๋๋ค.
๋ง์น๋ฉฐ
๋ฐ์ดํฐ ์๋ฌธ(plaintext)์ด ๋ ธ์ถ๋๋ฉด ์๋๋ ์์ญ๊ณผ, ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ(Integrity)์ ๊ธฐ๋ํ๋ ์์ญ์ ๋ฐ๋ผ ์ ์ ํ ์ํธํ ๋ฐฉ์์ ์ ํํด์ผ ํฉ๋๋ค.
๊ฐ์ ๋ฐ ๊ธฐ๋ ๊ฒฐ๊ณผ๋ก๋
- monorepo package์์ ์ ๊ณตํ๋ InternalAxiosService๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ผ์ฐ์ ์ฒ๋ผ ์๋์ผ๋ก origin์ ๋ถ์ฌ์ฃผ์ด, ๋ฐฑ์๋ ๋ก์ง ๊ตฌํ์ ์ง์คํ ์ ์๊ฒ ๋์๊ณ ,
- ์๋ฒ๊ฐ ํต์ ์์๋ request์ origin์ ์ ์ ์์ด, ๋๋ฒ๊น ์ ์ถ๊ฐ์ ์ธ ๋๊ตฌ๊ฐ ์๊ฒผ์ต๋๋ค.
- lambda์ duration ๊ฐ์ ์ผ๋ก ๋น์ฉ ์ ๊ฐ๋ ๊ธฐ๋๋ฉ๋๋ค.
๊ฐ์ฌํฉ๋๋ค.