스프린트때 직접 개발해두었던 암복호화 모듈을 활용해 utils에 넣었다. (학습메모 1)
// aes.util.ts
import crypto from 'crypto';
import { aesConfig } from '../config/aes.config';
const encryptAes = (plainText) => {
const algorithm = 'aes-256-cbc'; // 암호 알고리즘
const key = crypto.scryptSync(aesConfig.password, aesConfig.salt, 32); // 암호화 키
const iv = aesConfig.iv; // 초기화 벡터
const cipher = crypto.createCipheriv(algorithm, key, iv);
let cipherText = cipher.update(plainText, 'utf8', 'base64');
cipherText += cipher.final('base64');
return cipherText;
};
const decryptAes = (cipherText) => {
const algorithm = 'aes-256-cbc'; // 암호 알고리즘
const key = crypto.scryptSync(aesConfig.password, aesConfig.salt, 32); // 암호화 키
const iv = aesConfig.iv; // 초기화 벡터
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let plainText = decipher.update(cipherText, 'base64', 'utf8');
plainText += decipher.final('utf8');
return plainText;
};
export { encryptAes, decryptAes };
import { configDotenv } from 'dotenv';
configDotenv();
export const aesConfig = {
password: process.env.AES_PASSWORD,
salt: process.env.AES_SALT,
iv: Buffer.alloc(16, 0),
};
config 파일로 .env에 있는 AES_PASSWORD, AES_SALT를 활용하도록 보안처리
이제 POST /board
, PATCH /board/:id
및 GET /board
에 암복호화 처리를 넣어준다.
// board.service.ts
...
import { encryptAes, decryptAes } from 'src/utils/aes.util';
@Injectable()
export class BoardService {
...
async createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
const { title, content, author } = createBoardDto;
const board = this.boardRepository.create({
title,
content: encryptAes(content), // AES 암호화하여 저장
author,
});
const created: Board = await this.boardRepository.save(board);
return created;
}
async findBoardById(id: number): Promise<Board> {
const found: Board = await this.boardRepository.findOneBy({ id });
if (!found) {
throw new NotFoundException(`Not found board with id: ${id}`);
}
if (found.content) {
found.content = decryptAes(found.content); // AES 복호화하여 반환
}
return found;
}
async updateBoard(id: number, updateBoardDto: UpdateBoardDto) {
const board: Board = await this.findBoardById(id);
// updateBoardDto.content가 존재하면 AES 암호화하여 저장
if (updateBoardDto.content) {
updateBoardDto.content = encryptAes(updateBoardDto.content);
}
const updatedBoard: Board = await this.boardRepository.save({
...board,
...updateBoardDto,
});
return updatedBoard;
}
}
암호화돼서 잘 저장됨
GET으로 요청할 땐 복호화되어 반환됨
DB에 저장될때는 암호문으로! IV나 salt를 컬럼에 있는 값을 조합해서 쓰면 같은 input이라도 다른 암호문이 나오게 할 수 있다. 필요하면 개선하자
프론트 분들의 API 테스트를 위해 배포중인 테스트 서버에서 CORS 허용이 필요했다.
localhost에서 띄운 프론트 서버에서 테스트 API서버에 접근할 수 있게 다음과 같이 설정해주면 된다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as cookieParser from 'cookie-parser';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cookieParser());
// cors 허용
app.enableCors({
origin: true,
credentials: true,
});
const config = new DocumentBuilder()
.setTitle('B1G1 API')
.setDescription('B1G1 API description')
.setVersion('1.0')
.addTag('b1g1')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();