SSO와 '~' 문자 관련 문제

여러분 안녕하세요,

최근에 사용자의 바이오(bio)에 '~'를 포함하면 Discourse에서 base64decode 오류가 발생한다는 사실을 알게 되었습니다. 공백, =, %, & 같은 다른 문제적인 문자들은 모두 잘 처리되는데, '~'만 어째서인지 처리되지 않습니다.

이 문제를 겪고 계신 분이 계신가요?

처음에는 인코딩 방식이 잘못된 것 같다는 생각이 들었지만, 아직 원인을 파악하지 못했습니다.

제 Python 인코딩 구현은 다음과 같습니다:

return_payload = base64.urlsafe_b64encode(parse.urlencode(params).encode())

이 결과는 요청(requests)의 ‘sso’ 필드에 (다른 필요한 정보들과 함께) 직접 삽입됩니다:

resp = requests.post(
       ".../admin/users/sync_sso",
        data={'sso': return_payload, ...}
        headers={...}
)

Discourse를 최신 버전(3.5.0.beta1-dev)으로 업데이트했지만, 여전히 문제가 지속됩니다.

도움 주시면 감사하겠습니다!

아마도 수정되어야 할 것 같지만, 그 문제는 내 역량과 직급을 벗어난 문제입니다. 하지만 순수한 실용적 호기심으로: 왜 누군가가 자기소개에 틸드(~)를 쓰게 될까요?

허, 꽤 합리적인 질문이네.

나는 다국어 포럼을 운영하는데, 다른 문화권에서는 '~'가 자주 사용돼. 예를 들어 한국어에서는 말 끝에 '~'를 붙여 말투를 부드럽게 만들지. ‘궁금한 거 있으면 알려줘~’ 같은 식으로 말이야.

그러니까 이건 버그 보고서이지, 지원 요청이 아니라는 뜻인가요?

정말인가요? 버그란 이미 구현은 되어 있지만 작동하지 않는 것을 말합니다. 이 상황은 더 "완료되었는가, 안 되었는가"에 대한 질문이므로, 만약 완성되지 않았다면 Contribute > Feature 태그가 더 적합하며, 지원 문의라고 보기 어렵습니다.

네, 저는 버그라고 부르는 것이 적절하다고 생각합니다. 저는 base64 인코딩을 올바르게 수행하고 있다고 생각하므로, discourse도 올바르게 디코딩할 것입니다.

이것은 버그인 것 같습니다(재현할 수 있다면).

urlsafe_b64encode가 base64 인코딩에서 일부 문자를 대체하는 것 같습니다. 문서에서 확인해 보면:

URL 및 파일 시스템에서 안전한 알파벳을 사용하여 bytes 유사 객체 s를 인코딩합니다. 이 알파벳은 표준 Base64 알파벳에서 + 대신 -를, / 대신 _를 사용하며, 인코딩된 bytes를 반환합니다. 결과에는 여전히 =가 포함될 수 있습니다.

즉, 그 결과는 표준 base64가 아니므로 Discourse의 디코딩과 호환되지 않습니다.

대신 일반 b64encode 함수를 사용하는 것을 권장합니다. 필요할 경우 URL 이스케이핑은 HTTP 라이브러리가 처리할 것입니다.

더 자세히 조사해 보니, 실제로 인코딩을 잘못하고 있었습니다.

참고를 위해 최종적으로 작성한 코드를 공유합니다:

return_payload = base64.b64encode(parse.urlencode(kwargs).encode("utf-8"))
h = hmac.new(secret.encode("utf-8"), return_payload, digestmod=hashlib.sha256)
resp = requests.post(
       ".../admin/users/sync_sso",
        data={"sso": return_payload, "sig": h.hexdigest()}
        headers={...}
)

리다이렉트를 수행하는 경우, {“sso”…}에 대해 parse.urlencode를 반드시 적용하세요.

도움 주셔서 감사합니다, @sam님, @david님!