본문 바로가기

프로젝트

우리 프로젝트의 회원가입 정책에 관하여

지스트 청원 프로젝트는 '학교 구성원'을 대상으로 '익명성'을 보장한 채 운영돼야 하는 서비스다. 이런 서비스에 특징을 가져가면서 사용자의 편리성을 가져다주어야 하는데, 그 시작인 회원가입 정책에 대해 고민한 부분을 작성하고자 한다. 우리 프로젝트의 요구사항은 다음과 같다.

 

프로젝트의 요구사항

1. '학교 구성원'은 학교 이메일을 가진 사람 전원이다.

2. '익명'으로 진행되기 때문에 최소한의 개인 정보로 회원 가입을 진행한다.

3. 학교 측의 데이터를 받을 수는 없는 상황이다.

 

이때 최소한의 개인 정보에 대해 우리 팀은 '학교 이메일' '비밀번호' 이 두 가지 만을 사용하도록 결정했다. 별도의 아이디를 가지게 되면 사용자의 불편함을 초래할 것이라 생각했다.

학생, 직원, 교수의 직업을 입력받아 데이터의 자료로 쓰면 좋지 않을까라는 개인적인 생각.

기존 회원 가입 정책

기존 회원 가입의 흐름은 다음과 같다.

기존 회원 가입 정책 흐름

사용자는 회원 가입을 진행을 완료하고, 그 이후에  발송된 이메일의 링크를 클릭해 인증을 진행한다. 서버 측에서는 회원 가입의 요청을 진행했을 때 USER를 저장하고, 인증을 한 유저에 한해서 인증됐다는 의미로 `enabled=true`값으로 수정을 진행한다. 이 방식은 사용자의 편리성을 주는 동시에, 학교 측의 이메일을 가지고 있는 사용자만을 대상으로 회원가입을 진행하는 요구사항을 모두 만족한다. 하지만 이 방식은 다음의 치명적인 문제점들을 가지고 있다.

 

문제점 1. 이메일의 주인이 아닌 사람이 다른 사람의 이메일을 알고 있다면 회원가입이 가능하다.

회원 가입 과정에서 해당 이메일이 주인인지 확인하는 절차가 없기 때문에 위의 문제점을 지닌다. 만약 가입을 진행하게 된다면, 이메일의 주인은 이메일 중복 체크 로직으로 인해 회원가입이 불가능하게 된다.

 

문제점 2. 실제 이메일이 존재하지 않더라도 회원가입이 가능하다.

이메일 자체적인 검증이 진행되지 않기 때문에, 존재하지 않는 이메일로도 계속 회원가입이 가능하다. 악성 유저가 수십만 건의 이메일을 가입하더라도 막을 방법이 존재하지 않게 되고, 사용되지 않는 유저 정보로 우리 DB에 많은 부분을 가득 차는 위험에 놓이게 된다.

 

이를 고려하지 않고 출시하기에는 문제 상황이 크다고 판단했고 회원가입 방식을 전면 수정하기로 결정했다. 이를 위해 다른 서비스들의 회원 가입 방식을 분석했다.

 

글을 적고 난 이후 기존의 방식으로도 구현할 수 있을 것 같다라는 생각이 들었고, 궁금한 분은 아래 더보기 클릭

더보기

기존에 문제는 인증되지 않은 사용자가 데이터베이스에 저장된다는 문제다. 회원 가입 인증을 완료하기 전까지 데이터베이스에는 직접 저장하지 않고, Redis와 같은 저장소에 관리해두고 있다가, 인증이 된 이후에 이를 데이터베이스에 쓰도록 코드를 구성할 수 있을 것 같다.

 

다른 서비스의 회원 가입 정책 분석

학교 이메일 검증이라는 특수성을 가진 서비스이므로 학교 커뮤니티로 대표하는 에브리타임과 우리 학교 커뮤니티 플랫폼인 지스토리를 분석해 보았다.

에브리타임

에브리타임 회원가입 방식

에브리타임은 학교 인증 방식을 다양하게 제공하고 있기 때문에선지, 회원가입을 진행한 이후에 학교 인증을 진행한다. 휴대폰 인증 방식을 통해 1인 1 계정 원칙을 지킬 수 있기 때문에, 우리 서비스의 문제점 2 또한 발생하지 않게 된다.

하지만, 이 방식을 그대로 도입하기에는 회원 가입 과정에서 사용자의 경험을 너무 떨어트릴 수 있다 생각했다. 휴대폰 인증이라는 방식을 도입하는 부분 또한 비용적인 측면에 문제, 개인 정보 문제 등 복잡하게 엮일 수 있다 판단했다.

 

 

지스토리

지스토리 회원가입 방식

지스토리의 경우에는 회원가입의 과정이 두 가지 스텝으로 진행된다. 이메일 인증 과정을 처리하고 난 후 회원가입 폼을 작성하게 된다. 이 방식을 도입하게 되었을 때, 이메일의 주인만이 회원가입을 진행한다는 목표를 이룰 수 있게 된다.

회원 가입 폼에 작성할 부분이 이메일과 비밀번호밖에 없는 우리 서비스의 경우에는 인증과 검증을 둘로 나누어 진행하기보단 하나로 합치는 방법을 도입하고자 한다.

새로운 회원 가입 정책

새로운 회원 가입 정책에선 아래와 같이 이메일 인증을 진행하고, 인증이 된 후에 회원가입을 진행한다. 많은 다른 서비스에서 이메일 인증을 하는 방식과 비슷한 형태를 가지게 구성했다.

새로운 회원 가입 정책 form 및 api

서버단에서의 구현

@Entity
@Getter
public class VerificationInfo {
    public static final int CONFIRM_EXPIRE_MINUTE = 15;
    public static final int SIGN_UP_EXPIRE_MINUTE = 60;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String verificationCode;
    private LocalDateTime createdAt;
    private LocalDateTime confirmedAt;
}

우리 서비스는 이러한 인증 정보를 데이터베이스에 직접 저장한다. 이메일 정보와 인증코드의 매핑을 가지고 있고, 인증이 된 시간을 가지고 이를 인증 여부 판별을 진행한다. 이메일 인증이 가능한 시간을 15분, 인증을 진행 후 회원 가입은 60분 안에 진행하도록 정책을 정했다. 개인적으로 구현의 측면에서 고민하는 부분을 작성해보면 아래와 같다.

  1. 인증이라는 휘발적인 정보를 데이터베이스에 저장하는 것이 좋은 방식일까?
  2. 인증의 유효함은 해당 연결된 세션으로 한정지어야 하지 않나?
  3. VerificationInfo를 생성하는 데 제한을 두지 않았는데, 하나의 username마다 하나의 VerificationInfo만을 유효해야 하지 않을까?
    (지금의 경우 하나의 username에 여러 VerificationInfo를 계속 생성할 수 있다)

위 1,2,3번의 문제를 해결하기 위한 필자의 뇌피셜이 궁금한 분은 아래 더보기 참고

더보기
더보기

들어가기 앞서, 작성자는 아직 Redis에 대한 경험이 거의 없는 감자라는 사실을 인지하고 읽었으면 한다.

Redis를 두고 인증 요청 시 해당 username에 해당하는 verificationCode를 생성해준다. 이때, 연결된 세션 정보 또한 함께 저장해준다. 다음의 세 가지 시나리오에 따라 진행되는 방식을 적어보자면,

1. 회원 가입 진행 -> verificationCode와 세션 정보를 비교하고 일치하면 회원 가입을 진행한다. 그렇지 않으면 에러를 띄우고 이메일 인증을 진행하라고 응답을 보낸다.

2. 인증 재전송(같은 세션) -> 기존의 verificationCode를 새로 발급한 세션 정보로 치환해준다. (하나의 username -> 하나의 VerificationCode)

3. 새로운 인증 요청(다른 세션) -> 기존의 (verificationCode, 세션 정보) 모두를 치환해준다. (세션 별로 별도로 관리해줄 수 있겠지만 굳이 그럴 필요성은 없을 것으로 보임)

 

새로운 회원 가입 정책 고려사항

  • 이 방식은 다른 사람의 이메일을 입력하고 인증 요청을 보냈을 때, 이를 막을 방법이 없다.
    프론트
    측에서는 '인증'하기 버튼을 눌렀을 , 인증 버튼이 비활성화되도록 구현
  • 이메일 오타가 생겼을 부분에 대해서 고려해주기 (인증 재전송하기 기능 추가)
  • 악의적으로 이메일을 보낼 있기 때문에, 해당 내용을 인증 메일에 포함하여 가입을 하고 싶다면 가입을 하도록 유도하고, 아니면 블랙리스트 메일로 작성할 있을듯
  • 회원 가입을 진행했거나, 인증기간이 만료된 인증 정보에 경우에는 삭제를 진행해 최적화를 진행할 수 있을 듯

정리

우리 프로젝트의 회원가입 정책을 변경하는 과정을 글로 정리해보았다. 새로운 방식이 가지고 있는 문제점들도 있어 추후에 보완되어야겠지만, 기존의 구현 방식의 문제점을 해결하기 위해 다양한 방면으로 팀원들과 함께 고민한 부분이 재밌었다. 일련의 과정은 이 이슈에서 확인할 수 있다.