티스토리 뷰
반응형
얼마전 동료에게 CS(Customer Service) 문의가 들어왔다.
A 유저가 투표한 내용이 B 유저에게 노출이 됐다는 것이다.
내가 보기엔 꽤나 흥미롭고 귀찮은 이슈였는데(😭), 동료가 분석한 원인은 다음과 같았다.
- A가 '홍길동'에게 투표했음
- A의 고유 ID는 ABCDE
- B의 고유 ID는 ABcdE (대소문자만 다름)
- Django 서버는 DB 설정에 따라서 대소문자를 구별함 (utf8_general_ci)
- Django ORM filter()를 통해 case-sensitive한 쿼리(__exact__ field lookup)를 보내도, DB에서 case-insensitive하게 처리
- DB에서 case-insensitive하게 처리하므로 A와 B는 동일한 사용자로 판단
이는 MySQL의 collation이 utf8_general_ci로 설정돼있어서 생긴 문제였다.
Non-UCA collations have a one-to-one mapping from character code to weight. In MySQL, such collations are case-insensitive and accent-insensitive. utf8_general_ci is an example: 'a', 'A', 'À', and 'á' each have different character codes but all have a weight of 0x0041 and compare as equal.
utf8_general_ci는 case-insenstive하며 accent-insensitive하다.
이름에서 알 수 있듯이, _ci는 case-insensitive를 의미한다.
collation에 대한 네이밍 컨벤션은 여기에 나와있으며, 아래와 같다.
제일 근본적인 해결법은 DB 설정을 utf8mb4_bin과 같은 case-sensitive한 collation으로 바꾸는 것이겠지만, DB 설정을 바꾸는 일은 DBA에게 승인을 받아야 하기 때문에 대응까지 시간이 걸린다.
만약 개발자 입장에서 빠른 대응이 필요하다면 코드 배포로 쿼리에 COLLATE를 추가하는 것도 방법일 듯 하다.
반응형
댓글
링크
공지사항
최근에 달린 댓글
- Total
- Today
- Yesterday