회원 연동 서명 규격
회원 연동 user_data 문자열의 필드, 서명(hash) 만드는 순서, 시간 연동 검사, 검증용 고정 값이에요.
마지막 수정 2026년 10월 19일
회원 연동의 user_data는 내 서버가 회원 정보에 채팅방 토큰으로 서명한 문자열이에요. 이 문서는 필드와 서명 순서, 서버가 검사하는 규칙의 정본이에요. 설치 흐름과 언어별 예제는 회원 연동을 보세요.
필드
아래 필드 중 값이 있는 것만 서명에 들어가요. 서명 순서는 필드 이름순이라 넣는 순서는 상관없어요. 서명 코드는 넣은 필드를 모두 서명하므로 이 표에 없는 필드를 넣으면 오류 202가 나요. 나중에 필드가 늘어나도 새 필드를 넣지 않는 사이트의 서명은 그대로예요.
| 필드 | 형식 | 설명 |
|---|---|---|
auth |
0~3 또는 guest, member, subadmin, admin |
권한. 0 손님, 1 회원, 2 부관리자, 3 관리자. 비우면 id가 있을 때 회원, 없을 때 손님 |
icons |
주소 목록 | 닉네임 옆 아이콘. 쉼표로 여러 개, @ 앞은 닉네임 앞·뒤는 닉네임 뒤. 예: /img/a.png,/img/b.png@/img/c.png |
id |
문자열 | 회원 아이디. 차단·채팅금지·권한 부여의 기준 |
level |
숫자 | 레벨. 채팅방 기능 조건의 레벨 비교에 쓰여요 |
nick |
문자열 | 닉네임. 서버가 15자로 자른 뒤 공백을 지워요 |
nickcon |
주소 | 닉네임 대신 보일 이미지 |
other |
문자열 | 추가 표시. 낱말은 공백 하나로 구분해요. 보통 비워 둬요 |
room |
채팅방 아이디 | 필수. <u-chat room> 값과 같아야 해요 |
time |
Unix 시각(초) | 필수. 서명을 만든 현재 시각. 시간 연동을 끄면 검사하지 않지만 항상 넣어요 |
서명 키는 채팅방 토큰이에요. 토큰은 관리 페이지 채팅방 정보 → 토큰에서 확인하고, 결과 문자열에는 넣지 않아요. 서버 REST API의 API 키와 다른 값이에요. 토큰이 새면 누구든 관리자로 접속할 수 있으므로 서버 코드에만 두세요.
서명 순서
- 값이 있는 필드만 골라요. 빈 값과 넣지 않은 필드는 빠지고, 토큰도 넣지 않아요.
- 필드를 이름순(영문 소문자, 바이트 순서)으로 정렬해요.
- 필드마다
이름=값한 줄을 만들어요. 값은 UTF-8 바이트를 소문자 16진수로 쓴 것이에요. uchat-v2뒤에 3의 줄을 줄바꿈(\n) 하나씩으로 이어 붙여요.- 4의 문자열을 채팅방 토큰을 키로 HMAC-SHA256 계산해요. 소문자 16진수 64자 앞에
v2.를 붙인 것이hash예요. - 같은 순서로
이름 + 공백 + encodeURIComponent(값)을|로 잇고, 끝에hash 값을 붙여요.
결과 모양:
icons ...|id ...|level ...|nick ...|room my-room|time 1700000000|hash v2.0123...(64자)
- 값은 자바스크립트
encodeURIComponent처럼 인코딩해요. 공백은%20이에요. PHP는rawurlencode를 써요.rawurlencode처럼~,*,!등을 더 인코딩해도 풀면 같은 값이므로 hash는 같아요. - 채팅창은 각 값을
decodeURIComponent로 풀어 서버로 보내고, 서버는 같은 순서로 hash를 다시 계산해 비교해요.hash의 16진수는 대소문자를 가리지 않아요. - HMAC-SHA256과 16진수 변환은 대부분 언어의 기본 라이브러리에 있어요(PHP 5.6 이상
hash_hmac·bin2hex, Node.jscrypto, Pythonhmac·hashlib, Javajavax.crypto.Mac, C#HMACSHA256, Gocrypto/hmac, RubyOpenSSL::HMAC).
참고 구현(Node.js):
const crypto = require('node:crypto');
function signUserData(user, token) {
const fields = Object.entries({ ...user, time: Math.floor(Date.now() / 1000) })
.filter(([, v]) => v !== undefined && v !== null && v !== '')
.map(([k, v]) => [k, String(v)])
.sort(([a], [b]) => (a < b ? -1 : 1));
const message = ['uchat-v2', ...fields.map(([k, v]) => k + '=' + Buffer.from(v, 'utf8').toString('hex'))].join('\n');
const hash = crypto.createHmac('sha256', token).update(message, 'utf8').digest('hex');
return fields
.map(([k, v]) => k + ' ' + encodeURIComponent(v))
.concat('hash v2.' + hash)
.join('|');
}
// signUserData({ room: 'my-room', nick: '홍길동', id: 'user1', level: 5 }, process.env.UCHAT_TOKEN)
검증용 고정 값
직접 만든 코드가 맞는지 아래 입력으로 확인하세요. 같은 결과가 나와야 해요.
| 입력 | 값 |
|---|---|
| 토큰 | test-token-1234 |
time |
1700000000 |
room |
my-room |
nick |
홍 길동~*! |
id |
user@example.com |
level |
5 |
auth |
(빈 값) |
icons |
/img/a.png,/img/b.png@/img/c.png |
HMAC에 넣는 문자열(4단계, 빈 값인 auth는 줄이 없어요):
uchat-v2
icons=2f696d672f612e706e672c2f696d672f622e706e67402f696d672f632e706e67
id=75736572406578616d706c652e636f6d
level=35
nick=ed998d20eab8b8eb8f997e2a21
room=6d792d726f6f6d
time=31373030303030303030
결과 user_data:
icons %2Fimg%2Fa.png%2C%2Fimg%2Fb.png%40%2Fimg%2Fc.png|id user%40example.com|level 5|nick %ED%99%8D%20%EA%B8%B8%EB%8F%99~*!|room my-room|time 1700000000|hash v2.80d95cf251e7aeef90b37547dbe95ef5336f6c7f8cb235a6cf6cee91031e2ae6
auth는 비어 있어 user_data와 서명 모두에서 빠졌어요. PHP rawurlencode로 만들면 ~, *, !가 %7E, %2A, %21로 바뀌어 글자는 다르지만 hash는 같고 그대로 동작해요.
서버 검사
회원 연동을 켠 채팅방에서 채팅 서버는 입장할 때 아래 순서로 검사해요.
| 검사 | 실패 시 오류 |
|---|---|
hash가 있는가 |
203 |
| hash가 맞는가(위 순서로 다시 계산) | 202 |
시간 연동을 켰다면 time이 기준보다 오래되지 않았고, 같은 서명을 처음 쓴 지 300초가 안 지났는가 |
205 |
서명에는 일회용 값(nonce)이 없어요. 시간 연동을 끄면 한 번 만든 user_data를 복사해 언제든 다시 쓸 수 있으므로 시간 연동을 켜 두세요.
시간 연동
관리 페이지 회원 연동 화면에서 시간 연동을 켰을 때만 time을 검사해요. 끄면 time은 서명에만 들어가고 값은 검사하지 않아요.
offset = time - 유챗 서버 현재 시각을 계산해요.- 저장된 기준이 없으면 이번
offset을 기준으로 저장해요(첫 접속). - 기준이 있으면
offset이 기준보다 300초 넘게 작을 때(오래된 접속 정보) 오류 205로 거절해요. 미래 시각은 막지 않아요. - 같은
hash는 채팅 서버가 처음 받은 뒤 300초까지만 받아요. 그 뒤에는 오류 205예요. - 처음 받는
hash로 통과할 때만 기준을 이번offset으로 바꿔요. 같은user_data를 다시 써도 기준은 움직이지 않아요. - 표준시간 고정을 켜면 기준을 0으로 둬요.
time이 유챗 서버 시각보다 300초 넘게 과거면 거절해요. 내 서버 시계가 정확할 때 쓰세요. - 내 서버를 옮기거나 시계를 뒤로 300초 넘게 바꿨다면 관리 페이지에서 시간 기준을 초기화해요.
- 시간 연동을 켠 채팅방에서
time이 숫자가 아니면 오류 101이에요.
user_data를 페이지에 캐시해 두면 5분 뒤부터 오류 205가 날 수 있어요. 회원 연동 페이지는 캐시하지 않거나 user_data_url(u-chat 속성)로 그때그때 받으세요. 오류별 해결은 회원 연동을 보세요.
봐도 잘 이해가 되지 않나요? 문의 게시판에 질문을 남겨 주세요.