이 문자열이 무엇인지 알아내는 법
로그에 찍힌 낯선 값의 정체를 접두사·길이·앞 네 글자로 좁힙니다. 실제로 돌려 만든 판별표입니다.
로그나 API 응답에 정체 모를 문자열이 있습니다. 무엇으로 디코딩해야 하는지부터 정해야 합니다.
대부분은 앞 몇 글자로 갈립니다.
접두사가 형식을 말한다
$2y$10$4ynIhrlKty… bcrypt 해시
$apr1$45y19kAp$… Apache APR1 (htpasswd)
$1$… md5crypt
{SHA}L55TUjtiq8F… htpasswd 의 SHA-1, 솔트 없음
eyJhbGciOiJIUzI1… JWT
-----BEGIN … PEM (키·인증서)
data:image/png;base64, data URI
xn--bj0bj06e punycode 도메인
=E2=80=94 quoted-printable
%ED%95%9C URL 인코딩된 UTF-8
$로 시작하고 $로 둘러싸인 필드가 있으면 대체로 비밀번호 해시입니다. 첫 필드가 방식을 가리킵니다.
eyJ는 {"의 base64입니다. JSON을 base64로 감싼 것이면 무엇이든 eyJ로 시작하고, JWT가 그중 가장 흔합니다.
base64로 감싸도 파일 종류가 드러난다
base64는 3바이트를 4자로 바꿉니다. 그래서 파일의 앞 3바이트가 base64 앞 4자를 정합니다. 매직 바이트가 고정된 형식이면 그 4자도 항상 같습니다.
형식 앞 3바이트 base64 앞 4자
PNG 89 50 4e iVBO
JPEG ff d8 ff /9j/
GIF 47 49 46 R0lG
PDF 25 50 44 JVBE
ELF 7f 45 4c f0VM
SQLite 53 51 4c U1FM
gzip 1f 8b 08 H4sI
zip 50 4b 03 UEsD
Java class ca fe ba yv66
iVBORw0K로 시작하는 문자열을 보면 PNG를 base64로 감싼 것입니다. H4sI면 gzip입니다.
어디까지 안정적인가
4자까지입니다. 그 뒤는 형식에 따라 달라집니다.
gzip 명령이 만든 것 1f8b 0808 77e6946a → H4sICHfmlGoA
Node zlib 이 만든 것 1f8b 0800 00000000 → H4sIAAAAAAAA
gzip 헤더의 4~8바이트는 수정 시각입니다. gzip 명령은 시각을 넣고 Node는 0을 넣습니다. 그래서 5번째 글자부터 갈립니다.
zip도 50 4b 03 04 다음이 버전과 플래그라 UEsD 이후가 흔들립니다. 앞 3바이트가 완전히 고정인 PNG·JPEG·PDF·ELF만 4자가 항상 같습니다.
길이로 좁힌다
해시라면 길이가 알고리즘을 거의 특정합니다.
알고리즘 바이트 hex base64 base64url
MD5 16 32 24 22
SHA-1 20 40 28 27
RIPEMD-160 20 40 28 27
SHA-256 32 64 44 43
SHA-512 64 128 88 86
BLAKE2b-512 64 128 88 86
hex 32자면 MD5, 40자면 SHA-1이나 RIPEMD-160, 64자면 SHA-256입니다.
같은 길이가 겹치는 자리가 있습니다 — SHA-1과 RIPEMD-160은 둘 다 160비트라 구분되지 않습니다. 문맥으로 갈라야 합니다. 비트코인 주소 유도 과정이면 RIPEMD-160, 그 밖에는 대체로 SHA-1입니다.
base64로 적힌 해시는 끝의 =가 단서입니다. SHA-256을 base64로 하면 44자에 = 하나가 붙고, base64url이면 패딩을 빼서 43자입니다.
식별자
1fa8580d-7265-400b-967f-918c11703522 UUID 36자, 하이픈 4개
01M1AT7NKYZM7C354H747FC0ZJ ULID 26자, 하이픈 없음
V1StGXR8_Z5jdHi6B-myT nanoid 21자 기본
UUID는 세 번째 조각의 첫 글자가 버전입니다.
…-400b-… v4 무작위
…-11ee-… v1 시간 기반, 정렬 안 됨
…-7abc-… v7 시간 기반, 정렬됨
…-5984-… v5 이름 기반 (SHA-1)
ULID는 Crockford base32라 I·L·O·U가 없습니다. 이 네 글자가 보이면 ULID가 아닙니다. 그리고 앞 10자가 타임스탬프라 같은 시각에 만든 값끼리는 앞부분이 같습니다.
문자셋으로 좁힌다
0-9a-f 만 hex
A-Z2-7 과 = base32
A-Za-z0-9+/ 와 = base64 (표준)
A-Za-z0-9-_ base64url
1-9A-HJ-NP-Za-km-z base58 (0·O·I·l 없음)
+나 /가 보이면 표준 base64입니다. -나 _가 섞여 있으면 base64url이고, URL이나 JWT에서 옵니다.
base58은 헷갈리는 글자 넷(0·O·I·l)을 뺀 것이라, 비트코인 주소나 IPFS 해시에서 봅니다.
확인 순서
- 앞 5자를 봅니다.
$·{·-----·eyJ·data:가 있으면 거기서 끝납니다 - 전부 hex이고 길이가 32·40·64·128이면 해시입니다
- base64로 보이면 디코딩해서 앞 바이트를 봅니다. 매직 바이트가 나오면 파일입니다
- 디코딩 결과가 다시 텍스트면 한 겹 더 감싼 것입니다. JSON이 나오는 경우가 많습니다
- 하이픈 4개에 36자면 UUID이고, 세 번째 조각 첫 글자로 버전을 봅니다
- 어느 쪽도 아니면 애플리케이션 고유 형식일 수 있습니다. 길이가 일정한지부터 봅니다
tools.onuel.dev에서 이 순서를 그대로 밟을 수 있습니다. Hex 덤프에 디코딩 결과를 넣으면 매직 바이트가 바로 보이고, Base64 디코딩은 텍스트로, 파일 Base64 변환은 파일로 되돌립니다. JWT로 보이면 JWT 디코더가 세 조각을 나눠 주고, 해시 길이를 대조할 때는 SHA-256과 MD5에 아무 값이나 넣어 자릿수를 비교하면 됩니다.
- #디버깅
- #인코딩
- #해시