만베거
newminkyung
Hashid

hashid로 난독화하여 id 노출하지 않기

이번에 회사에서 개발하는 기능 중 하나가

인증 절차는 필요하지만 + 빡센 인증은 아니여도 됨

이라는 요구사항이 있었는데 이 때 알게된 hashid에 대해 써보았습니다

난독화

  • 의도적으로 읽기 힘들게 만드는 것
    • 예: 10이라는 사용자 아이디를 -> "D439fhdsE"로 난독화하면 원래 값인 10을 알아내기 어려움
  • 난독화 !== 암호화
    • 암호화는 brute-force attack 등의 공격에도 매우 안전해야하지만
    • 난독화는 그정도는 보안은 아님

hashids

제공하는 기능

  • non-negative integers -> string 으로 인코딩 / 디코딩
// 간단한 예시
// 왠만한 언어로 동일 구현되어있음
 
const sqids = new Sqids()
const id = sqids.encode([1, 2, 3]) // "86Rf07"
const numbers = sqids.decode(id) // [1, 2, 3]

hashids를 사용하는 경우

  • 어떤 정보를 노출하고 싶지는 않지만 + 완전히 숨기기는 힘들 때

    • 반디부디를 예시로 들면, 인생지도 URL이 /home/13이면 13번째 사용자임을 알 수 있음
    • 난독화를 통해 /home/13 -> /home/D439fhdsE으로 사용자의 ID를 난독화할 수 있음
    • 이 경우, 서비스의 규모가 밝혀지고 싶지 않을 때 난독화할 수 있을 듯 (근데 URL이 못생김)
  • 보안 문제 / 웹 스크래핑 등의 가능성을 줄이기 위해

    • /home/13으로 접근 가능하다면 /home/14로도 임의 접근이 가능함
  • UUID가 너무 긴 경우

image

  • 임의 생성 때문에 UUID를 고려했지만, 너무 길어서 어려웠던 경우의 사례
    • hashids를 사용하면 길이를 지정해줄 수 있음

hashids를 사용하지 않는 경우

  • negative interger의 경우 사용할 수 없음
  • 보안
    • 보안을 뚫었을 때 비용 vs 뚫는 비용을 고려해볼 때, 보안이 매우 중요하지 않는 경우만 사용하는게 좋을 듯

비슷한 대안

  • Base64 encode
    • 값을 숨기지 않고 문자로만 바꾸고 싶을 때 괜찮을 듯
    • 회사 개발자분이 라이브러리 설치를 싫어하셔서 이걸 강력 주장하셨다
  • uuid, nanoid
    • 충돌 가능해도 괜찮고 + 디코딩이 안되도 괜찮을 때 적절할듯
  • optimus, feistel cipher
    • 숫자 -> 숫자 매핑을 원할 때