업로드 없음, 100% 로컬, 계정 없음

아티클

데이터를 비공개로 인코딩하고 디코딩하기

개발자는 매일 토큰, 페이로드, 자격 증명을 인코딩과 디코딩 페이지에 붙여 넣습니다. 가장 편리한 페이지는 서버에서 동작하는데, 이는 굳이 필요하지 않았던 작업을 위해 데이터가 기기를 떠난다는 뜻입니다. 이 네 가지 도구는 전적으로 브라우저에서 동작하므로 데이터는 당신 곁에 남습니다.

Base64: 뒤섞여 보여도 비밀은 아니다

Base64는 암호화가 아니라 인코딩입니다. 이진 데이터를, 복사해 붙여 넣거나 단순한 문자만 처리하는 시스템을 통과해도 살아남는 텍스트로 바꿉니다. Base64 문자열을 본 사람은 한 단계로 원본으로 디코딩할 수 있으므로, API 키나 개인 인증서, 이메일 본문을 담은 문자열은 그것을 가진 사람에게 완전히 읽힙니다. 위험한 점은 그 값이 흔히 설정 파일이나 data URL, 인증 헤더 속에 숨어 알아보기 어렵게 보인다는 것이며, 그래서 사람들은 온라인에서 처음 찾은 디코더에 붙여 넣고 싶어집니다. 그 디코더는 가공되지 않은 비밀을 받습니다. Base64를 로컬에서 디코딩하는 도구는 값이 한 번도 서버에 닿지 않은 채로 원래 바이트를 보여 줍니다.

Hello!를 SGVsbG8h로 인코딩한 뒤 다시 디코딩한 예시로, Base64는 키 없이도 누구나 되돌릴 수 있음을 보여줌.

URL 인코딩: 쿼리 문자열은 생각보다 많은 것을 나른다

퍼센트 인코딩은 공백, 강세 부호, 예약 문자를 URL에 안전하게 넣게 해 줍니다. 당신이 인코딩하거나 디코딩하는 텍스트는 흔히 애플리케이션의 실제 쿼리 문자열이며, 이것들은 세션 식별자, 검색어, 이메일 주소, 리디렉션 대상, 때로는 서명된 매개변수를 나릅니다. 완전한 URL을 원격 인코더에 붙여 넣으면 이 모두를 한 번에 제삼자에게 넘기게 되고, 쿼리 문자열은 바로 서버 로그에 남기 쉬운 종류의 값입니다. 브라우저에서 인코딩하고 디코딩한다는 것은 URL이 당신 기기의 메모리에서 처리되며 작업하는 동안 결코 전송되지 않는다는 뜻입니다.

JWT: 페이로드는 서명되었을 뿐 숨겨진 것이 아니다

JSON Web Token은 점으로 이어진 세 개의 Base64url 구간, 곧 헤더와 페이로드, 서명으로 이루어집니다. 서명은 토큰이 변조되지 않았음을 증명하지만 페이로드를 가리는 일은 전혀 하지 않으며, 페이로드는 사용자 식별자, 역할, 만료 시각, 발급자가 추가한 모든 사용자 정의 클레임을 담은 읽을 수 있는 JSON으로 디코딩됩니다. 유효한 토큰은 살아 있는 자격 증명이기도 합니다. 만료되기 전까지는 그것을 가진 누구든 그 사용자처럼 행동할 수 있습니다. 작동하는 토큰을 온라인 디코더에 붙여 넣으면 당신이 통제하지 않는 서버로 활성 자격 증명을 보내게 됩니다. 브라우저에서 토큰을 파싱하는 디코더는 그 토큰이 한 번도 페이지를 떠나지 않은 채로 동일한 헤더와 페이로드를 보여 줍니다.

JWT의 세 부분: 읽을 수 있는 헤더, 읽을 수 있는 페이로드, 그리고 아무것도 숨기지 않으면서 무결성을 증명하는 서명.

해싱: 다이제스트보다 입력이 더 중요하다

해시 함수는 어떤 입력이든 고정 길이의 다이제스트로 바꾸며, 다이제스트를 입력으로 되돌릴 수는 없습니다. 이 성질 덕분에 해싱은 파일의 무결성을 확인하거나 원본을 저장하지 않고 값을 비교하는 데 유용합니다. 함정은 입력 쪽에 있습니다. 비밀번호나 문서, 설정상의 비밀의 해시를 계산하려면 도구에 진짜 값을 넣어야 합니다. 그 도구가 서버에서 동작한다면, 돌아오는 것은 무해한 다이제스트뿐이라도 민감한 입력은 그곳으로 갑니다. 해시를 로컬에서 계산하면 입력이 기기에 남으므로, 해싱한 대상을 드러내지 않고도 필요한 다이제스트를 얻습니다.

Base64 인코딩: 바이트 매핑과 패딩

Base64는 입력 3바이트(24비트)를 4개의 6비트 값으로 묶어 8비트 바이트를 6비트 문자로 변환합니다. 각 6비트 값은 Base64 알파벳(A-Z, a-z, 0-9, +, /)의 문자에 매핑됩니다. 이 과정은 24비트로 나누어지는 입력이 필요하므로 짧은 입력은 패딩됩니다. 남은 바이트가 1개이면 패딩 문자 2개(==)가 추가되고, 2개이면 1개(=)가 추가됩니다. JSON Web Token(JWT)에 사용되는 Base64url 변형은 +를 -로, /를 _로 대체하여 문자열을 URL에 안전하게 만들고 = 패딩을 완전히 제거합니다. 엄격한 URI 파서에서 패딩 문자가 오류를 일으킬 수 있기 때문입니다. 이 차이를 인식하는 것은 토큰 처리 디버깅에 중요합니다. 형식이 잘못된 것처럼 보이는 JWT가 단순히 표준 Base64가 아닌 Base64url로 인코딩된 것일 수 있습니다.

JWT 서명: HS256, RS256, 그리고 알고리즘 혼동 취약점

JSON Web Token의 보안은 전적으로 서명, 즉 점으로 구분된 세 번째 세그먼트에 달려 있습니다. HS256(HMAC-SHA256)에서는 서버가 비밀 키를 사용하여 Base64url로 인코딩된 헤더와 페이로드에 서명합니다. SHA-256 해시 함수는 충돌 저항성을 제공합니다. 비밀 키를 모르는 상태에서 동일한 서명으로 해시되는 수정된 페이로드를 만드는 것은 계산상 불가능합니다. RS256에서는 서버가 RSA 개인 키로 서명하고 공개 키로 검증합니다. 알고리즘 혼동이라는 알려진 취약점은 서버 라이브러리가 예상 알고리즘 유형을 엄격하게 적용하지 않을 때 발생합니다. 공격자는 토큰 헤더의 alg 필드를 RS256에서 HS256으로 변경하고, 공개 키가 종종 접근 가능하다는 점을 이용해 서버의 공개 키를 HMAC 비밀로 사용하여 토큰에 서명할 수 있습니다. 브라우저에서 로컬로 JWT 헤더를 디코딩하면 활성 토큰을 타사 로깅 시스템에 노출하지 않고도 실제로 어떤 알고리즘이 지정되어 있는지 확인할 수 있습니다.

이 아티클의 도구

자주 묻는 질문

Base64나 URL 인코딩은 보안의 한 형태인가요?

아니요. 둘 다 데이터를 보호하기 위한 것이 아니라 안전하게 옮기기 위해 설계된 가역 인코딩입니다. 인코딩된 문자열을 읽을 수 있는 사람은 키나 비밀번호 없이도 즉시 디코딩합니다. 어떤 값을 비밀로 유지해야 한다면 적절한 알고리즘으로 암호화하고 키를 따로 관리하세요. Base64나 퍼센트 인코딩된 값은 모두 평문으로 적힌 것처럼 다루세요.

토큰을 어디서 디코딩하거나 비밀번호를 어디서 해싱하는지가 왜 중요한가요?

민감한 부분이 입력이기 때문입니다. 유효한 JWT는 살아 있는 자격 증명이고, 당신이 해싱하는 비밀번호는 진짜 비밀입니다. 서버 기반 도구는 결과를 돌려주기도 전에 그 가공되지 않은 입력을 받으며, 이는 사본이 로그에 남거나 당신이 보지 못하는 곳에 보관될 수 있다는 뜻입니다. 브라우저에서 동작하는 도구는 같은 작업을 당신 기기의 메모리에서 수행하므로 토큰이나 비밀번호는 어디로도 보내지지 않습니다.