기반 프리미티브
같은 바이트가 항상 같은 문자열이 되게 해 문자열 비교와 바이트 비교가 갈리지 않게 합니다.
규격 재현과 공격 거부를 이 페이지에서 직접 실행해 확인할 수 있습니다.
base64url은 단순한 표현 방식처럼 보이지만 보안 경계에서는 다릅니다. 대부분의 디코더가 관대해서 서로 다른 문자열이 같은 바이트로 디코딩되며, 그러면 문자열로 비교하는 곳과 바이트로 비교하는 곳의 판단이 갈립니다. 디코딩 후 재인코딩이 원본과 일치할 때만 받아들이는 왕복 검사가 이 문제를 한 번에 닫습니다.
디코딩한 값을 다시 인코딩해 원본과 같을 때만 통과시켜 비정규 표현을 걸러냅니다.
마지막 문자에는 사용되지 않는 비트가 남아, 다른 문자가 같은 바이트로 디코딩될 수 있습니다.
중복 제거·캐시 키·사용 완료 목록이 같은 값을 다르게 세지 않도록 표현을 하나로 고정합니다.
"QQ"와 "QR"은 둘 다 0x41 한 바이트로 디코딩됩니다. 마지막 문자가 담는 6비트 중 실제로 쓰이는 것은 2비트뿐이고 남는 4비트는 무시되기 때문입니다. 사용 완료 토큰 목록을 문자열로 관리한다면, 공격자는 마지막 글자만 바꿔 같은 토큰을 다시 쓸 수 있습니다. 패딩(=) 추가, 표준 base64 알파벳(+, /) 혼용, 앞뒤 공백도 같은 부류의 문제입니다.
이 규칙은 원래 secret-encryption과 signed-values 안에 각각 흩어져 있었습니다. 흩어져 있으면 새 envelope 형식을 추가할 때 빠뜨리기 쉽고, 실제로 그런 누락이 형식 검증 우회로 이어집니다. 한곳에 모아 두면 새 형식은 이 함수를 쓰기만 하면 됩니다.
아래 증명은 설명이 아니라 실제 실행입니다. 버튼을 누르면 이 서버에서 지금 계산합니다.
base64url은 base64의 알파벳 두 글자를 바꾸고 패딩을 없앤 형태다 — URL에 그대로 실을 수 있다. 규격 벡터를 재현하고, 모든 바이트열이 인코딩 후 디코딩하면 원래대로 돌아오는지 확인한다.
표준이 고정한 test vector 를 그대로 실행합니다.
"QQ"와 "QR"은 둘 다 0x41로 디코딩된다 — 마지막 문자의 남는 비트가 무시되기 때문이다. 문자열로 사용 완료 토큰을 관리한다면 마지막 글자만 바꿔 재사용할 수 있다. 왕복 검사가 이 부류를 한 번에 닫는다.
막아야 할 입력을 실제로 넣고 거부되는지 확인합니다.
규격 원문을 우선합니다. 사례는 이 주제가 실제로 어떻게 뚫렸는지를 다룬 자료입니다.
인코딩 원문. §10이 시험 벡터, §3.5가 남는 비트 규칙.
같은 문제를 JSON에서 푼 사례. 서명 대상 정규화의 필요성.
Next step
서명 대상이 되는 JSON 구조에 RFC 8785 정규화를 적용할지 검토합니다.