회원 연동 서명 규격

회원 연동 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 키와 다른 값이에요. 토큰이 새면 누구든 관리자로 접속할 수 있으므로 서버 코드에만 두세요.

서명 순서

  1. 값이 있는 필드만 골라요. 빈 값과 넣지 않은 필드는 빠지고, 토큰도 넣지 않아요.
  2. 필드를 이름순(영문 소문자, 바이트 순서)으로 정렬해요.
  3. 필드마다 이름=값 한 줄을 만들어요. 값은 UTF-8 바이트를 소문자 16진수로 쓴 것이에요.
  4. uchat-v2 뒤에 3의 줄을 줄바꿈(\n) 하나씩으로 이어 붙여요.
  5. 4의 문자열을 채팅방 토큰을 키로 HMAC-SHA256 계산해요. 소문자 16진수 64자 앞에 v2.를 붙인 것이 hash예요.
  6. 같은 순서로 이름 + 공백 + 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.js crypto, Python hmac·hashlib, Java javax.crypto.Mac, C# HMACSHA256, Go crypto/hmac, Ruby OpenSSL::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 속성)로 그때그때 받으세요. 오류별 해결은 회원 연동을 보세요.

봐도 잘 이해가 되지 않나요? 문의 게시판에 질문을 남겨 주세요.

상호 UCHAT · 대표 김경욱 · 사업자등록번호 141-05-32832
사업장소재지 경기도 파주시 와석순환로 61 · 통신판매업신고번호 2013-경기파주-4485호
대표번호 010-8677-8633 · 이메일 support@uchat.io

ⓒ 2013–2026 UCHAT. All rights reserved.