백엔드/NestJs

[암호화] 양방향 암호화 & 해싱(단방향 암호화)

STUFIT 2023. 1. 29. 16:09
반응형

암호화의 종류는 두 가지가 있는데 아래와 같다.

- 양방향 암호화 : 암호화와 복호화 과정을 통해 송,수신 간 주고받는 메세지를 안전하게 암호화한 후 평문으로 복호화를 하는 과정

- 단뱡향 암호화 : hashing 을 이용한 암호화 방식으로서, 평문을 암호문으로 암호화가 가능하지만, 암호문을 평문으로 다시 복호화 하는 것은 불가능하다.

 

양방향 암호화는 암호문을 평문으로 복호화 가능하기 때문에 보통 단방향 암호화를 이용하는 편이다.

<단방향 해시 함수의 종류>

- SHA

- MD

- HAS

- WHIRLPOOL

이렇게 4 종류 중에 대표적으로 SHA-256 알고리즘이 많이 사용된다.

 

<Key Stretching >

단순 해시 함수를 이용하여 변환만 한다면 보안이 완벽하다고 할 수 없다. 왜냐하면 해커들이 레인보우 테이블을 이용하여 엄청난 경우의 수의 복호화를 대입해 볼 수 있기 때문이다. 이 때, 보안을 좀 더 철저히 하기 위해 생겨난 방법이 키-스트레칭 이다.

키-스트레칭은 개발자가 횟수를 정하여 해시함수를 돌리는 방법으로서, 비밀번호를 저장할 때 가장 쉽게 생각할 수 있는 방법이다.

 

<Salt>

키-스트레칭은 만약, 해커들이 돌린 횟수만 알게 된다면 언제든지 보안이 뚫릴 수 있는 단점이 있는데, Salt는 해당 암호화된 문자에 임의의 문자열을 덧붙이기 때문에 좀 더 보안이 뛰어나다. 그리고, 사용자마다 다른 Salt를  사용한다면 Digest 값이 달라지기 때문에, 어떤 임의의 사용자의 비밀번호가 유출되더라도 해당 사용자와 똑같은 비밀번호를 사용하는 다른 사용자의 비밀번호는 비교적 안전할 수 있다.


<NestJS - Bcrypt>

1. Nestjs 에서 암호화를 하기 위해 bcrypt 라는 모듈을 설치해주자.

$ npm install bcrypt
$ npm install @types/bcrypt // 타입스크립트에서 제공하는 모듈

2. gql 을 사용하는 분들은 user.resolver.ts 에 아래의 코드를 대입한다.

// user.resolver.ts

import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { User } from './entities/user.entity';
import { UserService } from './user.service';
import * as bcrypt from 'bcrypt';

@Resolver()
export class UserResolver {
  constructor(
    private readonly userService: UserService, //
  ) {}

  @Mutation(() => User)
  async createUser(
    @Args('email') email: string,
    @Args('password') password: string,
    @Args('name') name: string,
    @Args('age') age: number,
  ) {
    const stufithashpassword = await bcrypt.hash(password, 10);
    console.log(hashedPassword);
    return this.userService.create({ email, stufithashpassword, name, age });
  }
}

// 1. 설치한 bcrypt 모듈을 불러온다.
// 2. 21번째 줄에서 hash 알고리즘을 이용하는데, hash 메서드의 첫번째 인자는 사용자가 입력한 비밀번호이다.
// 3. 두번째 인자는 Salt 이므로, 10 의 의미는 password 를 10 회 Salt 시켜준다는 의미이다.

3. user.service 에서 password 를 repository 로 보내어 저장한다.

// user.service.ts

import { ConflictException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

// 파라미터 stufithashpassword 는 changedpassword 로 name을 변경할 수 있다.
  async create({ email, stufithashpassword: changedpassword, name, age }) {
    const user = await this.userRepository.findOne({ email });
    if (user) throw new ConflictException('이미 등록된 이메일 입니다.');

	// password 는 DB에 password 라는 컬럼으로 되어 있으므로, password는 changedpassword 라는 뜻이다.
    return await this.userRepository.save({ email, password:changedpassword, name, age });
  }
}

4. gql 호출

: createUser 로 계정 생성 시, 다음과 같이 response 를 받는다.

5. DB 확인

: password 부분이 해쉬암호화 된 것이 확인된다.

반응형