잡플래닛 리뷰의 익명성을 이어주는 디링크

리뷰 익명성 보장과 안전한 리뷰 수정을 위한 잡플래닛의 Delink와 Relink기능을 소개합니다.
Jul 31, 2024
잡플래닛 리뷰의 익명성을 이어주는 디링크
잡플래닛에는 200만 개가 넘는 소중한 리뷰가 저장되어 있습니다. 많은 분들이 솔직하게 회사의 리뷰를 작성해주고 계신데요. 이렇게 재직자들의 생생한 경험과 평가가 공유되다 보니 리뷰의 보안을 지키는 것이 저희에겐 아주 중요한 미션입니다.
 
리뷰의 익명성은 철저하게 유지하되 작성자 본인은 리뷰에 접근할 수 있게 하려면 어떤 방식을 사용할 수 있을까요? 잡플래닛의 백엔드 팀은 리뷰의 보안 강화를 위한 특별한 방식을 고안하여 적용했습니다.
리뷰의 익명성과 무결성을 지키기 위해 백엔드 팀이 어떤 노력을 기울였는지 여기서 설명드립니다. 🔐
 
 
notion image
 
Delink는 잡플래닛의 익명성을 보장해 주는 핵심 기능입니다. 단어 그대로 유저와 리뷰의 연결 고리를 끊는 것을 의미합니다. 유저와 리뷰의 연결이 끊어져야 진정한 익명이 보장되기 때문입니다.

Delink가 필요한 이유 ✨

데이터 분리 단순 암호화만 사용한다면 유저와 리뷰 데이터가 여전히 연결되어 있을 수 있습니다. Delink는 이 연결을 완전히 끊어 별도의 데이터로 관리합니다.
내부 유출 방지 단순 암호화의 경우 시스템 관리자나 내부자가 암호를 해독할 수 있습니다. Delink는 이러한 내부 유출까지 고려하여 설계되었습니다.
Minimal Disclosure Delink를 통해 리뷰의 유효성은 검증할 수 있지만, 작성자에 대해서는 아무것도 알 수 없는 최소 공개(Minimal Disclosure) 원칙을 따릅니다.
 
유저가 리뷰를 작성하면 서버에서는 유저에게 무작위의 보안코드를 내려줍니다. 유저는 이 보안코드를 따로 저장하면 되고, 서버에서는 보안 코드를 저장하지 않고 단방향으로 암호화만하여 누구도 알 수 없는 암호 토큰을 생성합니다. 단방향으로 암호화된 암호 토큰은 보안 코드를 알 수 없고 그저 보안 코드가 맞는지만 검사해줍니다.
 
  • 리뷰의 보안코드 발급
  • 보안코드를 유저에게 제공
  • 보안코드와 유저의 해시값을 사용하여 2차로 단방향 암호화
  • 2중으로 암호화된 암호 토큰을 리뷰 데이터에 저장
 
보안코드와 암호 토큰 생성 간단한 예시)
def self.generate_token(len) domain = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' domain_size = domain.bytesize char = '' len.times { char << domain[rand(domain_size)] } char end
user_salt = get_user_salt(user) secret_token = Digest::SHA256.hexdigest "#{token}:#{user_salt}" review.update(secret_token: secret_token)
 
데이터 예시)
id
company_id
rating
secret_token
312321914
910316824
5
1aR0jagrt256vKn12laaD9nl09dlR
312164531
151246832
3
gJLi7JQfap92JlfjHS8gLs9HLXhrH
 
이러한 Delink 과정은 자물쇠와 열쇠로도 비유할 수 있습니다. 보안 코드는 리뷰를 열 수 있는 유일한 열쇠이며 암호 토큰은 이 열쇠가 맞는지 확인할 수 있는 자물쇠입니다. 잡플래닛은 마스터키를 가지고 있지 않습니다.
 
  • 리뷰는 모두 고유한 자물쇠로 잠겨있다.
  • 자물쇠를 열 수 있는 열쇠(=보안코드)는 오직 작성자만 가지고 있다.
  • 작성자의 열쇠(=보안코드) 없이는 자물쇠를 열 수 없다.
  • 작성자가 열쇠(=보안코드)를 잃어버리면 자물쇠는 아무도 열 수 없다.
 
 

해시 알고리즘과 소금값

위에서 적은 대로 보안코드는 유저별 해시 소금값을 활용해 다시 한번 암호화합니다. 해시와 소금값은 무엇이고 보안코드를 이중으로 암호화해야하는 이유는 무엇일까요?
 

해시 알고리즘

해시 알고리즘은 단방향 암호화 방식입니다. 단방향 암호화는 달걀을 깨트리면 원래 모습으로 복구할 수 없듯이 복호화가 불가능한 방식을 의미합니다.
깨진 달걀의 모습은 바닥의 재질, 떨어지는 각도 등 아주 미세한 차이에도 달라지게 될 것입니다. 이것은 해시 알고리즘의 Avalanche Effect(작은 변화에 큰 영향)와 유사합니다.
대신 이 모든 차이가 똑같다면 어떻게 될까요? 깨진 달걀의 모양도 이론적으로 똑같아집니다.
 
User
Password
13
ea927ce1dcf51c5bf5b107bb38c6862a9e5fefab164159bcf305c37cb7c7ed63
14
3b5965dd5bb9efdca92546418ead9c1e85c38c3887e99818c2d2b7f7dc3c6e6e
15
34f6ef8b1ebdae9250d495a355135ed7d0d536614c06bf5bc62bde945f8d0c75
16
ea927ce1dcf51c5bf5b107bb38c6862a9e5fefab164159bcf305c37cb7c7ed63
위의 표에서 알 수 있는 정보는 유저들의 비밀번호가 무엇인지는 알 수 없으나 13번 유저와 16번 유저가 같은 비밀번호를 사용한다는 사실입니다. 해시값을 미리 여러개 만들어두면 겹치는 비밀번호가 있을 때 알아낼 수도 있습니다. 이러한 룩업 테이블을 레인보우 테이블이라고 합니다.
 
💡
실제로 레인보우 테이블을 만들기는 매우 어렵습니다. 문자, 숫자, 특수문자의 모든 조합은 엄청난 저장 공간과 성능을 필요로 합니다.
 

소금값 (Salt)

같은 입력값일때 결과가 같아지는 해시 알고리즘의 약점을 보완하기 위해 덧붙이는 문자를 소금값이라고 합니다. 앞에서 해시 알고리즘은 Avalanche Effect 성격을 가지고 있다고 말씀드렸는데요, 조그마한 차이라도 생기면 해시값이 완전히 바뀌게 됩니다. 소금값을 덧붙여 결과를 바꿔버릴 수 있습니다.
 
암호(비밀번호:소금값) = 실제로 저장하는 Password 해시값
 
유저
소금값
Password
13
cf94bb2dc47d3a49ano3l…
d31dfff4ef9dc6f5dafbde221600…
16
72144781cf5e8cb1db8f67…
f8966c72dae9038545df1e13b9…
위에서 같은 비밀번호를 가졌던 13번 16번 유저에게 각각 다른 소금값을 부여하자 비밀번호의 해시값이 전혀 다르게 달라진 것을 볼 수 있습니다.
이렇게 소금값을 이용해서 레인보우 테이블 공격을 방지하고 더욱 더 강력한 암호화를 제공할 수 있습니다.
 
잡플래닛 리뷰는 위와 같은 방식으로 생성한 암호 토큰만 저장하고 유저와의 연결을 끊습니다. 그렇다면 유저가 나중에 자기가 쓴 리뷰를 수정하고 확인하려면 어떻게 해야 할까요? 이때 Relink 과정이 필요합니다.
Relink란 Delink 되어 있는 리뷰를 작성자와 다시 연결하는 과정입니다. 유저가 저장해 둔 보안 코드(=열쇠)를 제출하면, 시스템에서 유저가 제출한 보안 코드와 유저의 소금값이 암호 토큰으로 유효한지 검사합니다. 유효하다고 판단되면 리뷰와 유저를 일정 시간 동안 연결해 줍니다.
수정이 완료된 후에는 보안 코드를 다시 발급하여 Delink의 과정을 다시 거칩니다. 마찬가지로 이 보안 코드는 잡플래닛에 저장되지 않습니다.
 
  • 유저가 제출한 보안 코드와 해시 소금값으로 암호 토큰을 다시 생성
  • 실제 리뷰의 암호 토큰과 일치하는지 검사
  • 일치하는 경우 유저와 리뷰를 Relink
  • 새로운 보안 코드 발급 및 Delink 처리
 
Relink 과정도 열쇠와 자물쇠로 비유해 볼 수 있습니다.
  • 작성자는 열쇠(=보안코드)를 가지고 다시 자물쇠를 연다.
  • 한 번 열린 열쇠와 자물쇠는 자동으로 파괴된다.
  • 리뷰는 새로운 자물쇠로 잠기고 작성자는 새로운 열쇠를 얻는다.
 
이러한 과정을 통해 리뷰의 익명성을 지키면서도 유저가 작성한 리뷰를 수정하고 확인할 수 있는 편의성 또한 갖출 수 있습니다.
 
잡플래닛은 플랫폼의 태초부터 익명 서비스라는 특성을 통해 보복에 대한 두려움 때문에 정당한 목소리를 내는 데에 소극적이었던 과거 문화를 변화시키고 채용 시장의 투명성을 강화할 수 있었어요. 가장 중요하게 여기는 가치가 유저 보호인 만큼 잡플래닛에서는 이렇게 Delink와 Relink를 사용하여 작성된 리뷰를 지키고 있습니다. 안심하고 여러분의 경험을 공유해주세요! 🙌
 
Share article

#잡플래닛 테크블로그 #잡플래닛 기술블로그