1.시스템&인프라/스트리밍

[MistServer] API 인증 방식과 HTTP·WebSocket API 비교

쿼드큐브 2025. 11. 6. 15:10
반응형
반응형

MistServer API 인증 방식과 HTTP·WebSocket API 비교

"본 글은 과거 티스토리에서 발행했던 콘텐츠를 기반으로, 최신 정보를 반영해 새롭게 정리한 업데이트 버전입니다."

 

📚 목차
1. MistServer API 개요
2. MistServer API 인증 방식 이해
3. HTTP API vs WebSocket API
✔ 마무리

 

MistServer API 개념
MistServer API 개념

1. MistServer API 개요

MistServer는 HTTP API와 WebSocket API 두 가지 형태의 원격 제어 인터페이스를 제공합니다.

모든 데이터는 JSON 형식으로 주고받으며, 기본 통신 포트는 4242입니다.

API 엔드포인트는 다음과 같이 두 가지 버전이 있습니다.

🔸 /api

▸ 전체 상태·설정·로그 등 모든 정보를 포함한 응답을 반환합니다.
▸ 한 번의 요청으로 다양한 정보를 받아야 하는 경우에 유용하지만, 응답 크기가 크고 속도가 느릴 수 있습니다.

🔸 /api2

▸ minimal 모드가 기본 적용되어, 요청한 항목만 간결하게 반환합니다.
▸ 불필요한 데이터 전송을 줄여 성능이 향상되며, 실시간 모니터링·자동화 스크립트에 권장됩니다.

 

🔷 호출 형식

▸ HTTP: GET 또는 POST 요청
▸ WebSocket: 지속 연결 후 이벤트 기반 데이터 수신

 

✔️ 호출 예시 (HTTP POST)

# Windows CMD 용
curl -X POST "http://10.1.73.35:4242/api" ^
  -H "Content-Type: application/x-www-form-urlencoded" ^
  --data-urlencode "command={\"username\":\"ceri\",\"password\":\"\"}"

 

🔷 /api vs /api2 간단 비교

구분 /api(기존) /api2(최신)
데이터 전체 정보 반환 요청한 정보만 반환
속도 상대적으로 느림 빠름
활용 초기 설정, 전체 상태 조회 실시간 조회, 자동화 스크립트

 

✔️ 실무 활용 팁

신규 구축이나 자동화 환경에서는 /api2를 기본값으로 사용하고, /api는 전체 백업이나 복잡한 상태 점검 시에만 활용하는 것이 좋습니다.

 

2. MistServer API 인증 방식 이해

MistServer는 API 호출이 서버 내부(로컬)에서 발생하는지, 외부 네트워크를 통해 들어오는지에 따라 인증 절차를 다르게 적용합니다.
이는 보안과 접근 제어를 위해 설계된 기본 정책으로, 운영 환경에서 반드시 숙지해야 하는 부분입니다.

 

🔷 로컬 호출(Local Requests)

▸ MistServer가 실행 중인 동일한 머신(서버)에서 API를 호출하는 경우, 인증 과정이 필요 없습니다.
▸ 이는 개발·테스트 환경이나 단일 서버 운영 시 편리하지만, 잘못 설정된 경우 외부 접근이 로컬로 우회될 위험이 있으므로 방화벽 설정을 반드시 병행해야 합니다.

▸ 이 경우, API와 웹 인터페이스 모두 로그인 없이 자유롭게 접근이 가능합니다.

▸예시

curl http://localhost:4242/api2/capabilities

 

🔷 외부 호출(Remote Requests)

외부 네트워크에서 MistServer API를 호출하는 경우 최소 1회 인증이 필요합니다.

인증이 완료되면 연결이 유지되는 동안 재인증 없이 API 요청이 가능하지만, 세션이 끊기거나 만료되면 다시 인증을 수행해야 합니다.
외부 호출 인증 방식은 크게 두 가지입니다.
▸ Challenge 기반 인증 – MistServer 기본 인증 절차
▸ HTTP 헤더 인증 – WebSocket API 사용 시 필수 방식

 

🔷 Challenge 기반 인증 흐름

MistServer의 기본 인증 절차는 Challenge-Response 방식입니다.
비밀번호를 평문으로 전송하지 않고, 서버가 제공하는 challenge 값을 사용해 해시를 생성합니다.

MistServer 인증 절차 개념
MistServer 인증 절차 개념

(1) 최초로 사용자 ID 값 (암호: 공백)을 이용한 json 문자열을 서버로 전송하여 인증을 요청합니다.
(2) 서버는 challenge 문자열을 포함한 응답 메시지를 전송합니다.
(3) 클라이언트는 아래 규칙으로 생성한 패스워드 문자열을 서버로 재 전송하여 인증을 요청합니다.
- 인증용 passowrd 문자열 생성 규칙 : password = MD5( MD5(비밀번호) + challenge)
- challenge 값은 (2) 과정에서 응답받은 challedge 메세지를 사용합니다.
(4) 인증이 완료되면 서버는 "status":"OK" 응답메세지를 전송합니다.

 

✔️ 상태 코드 설명

상태 값 의미
OK 인증 성공, API 호출 가능
CHALL 로그인되지 않음, challenge 제공
NOACC 계정 없음 → 최초 계정 생성 가능
ACC_MADE 계정 생성 완료, 로그인 가능

 

✔️Python 예제 코드

import hashlib
import requests

# 설정
SERVER_URL = "http://101.1.xx.xx:4242/api2"
USERNAME = "ceri"
PASSWORD = "cericube"

headers = {"content-type": "application/json"}

# 1. Challenge 요청
# 초기 요청으로 challenge 값을 받습니다.
initial_payload = {"authorize": {"username": USERNAME, "password": PASSWORD}}
res = requests.post(SERVER_URL, json=initial_payload, headers=headers)
challenge = res.json().get("authorize", {}).get("challenge", "")
print(f"1. Challenge 값 수신: {challenge}")


# 2. 해시 생성
# 비밀번호와 challenge를 조합하여 최종 해시를 만듭니다.
hash1 = hashlib.md5(PASSWORD.encode()).hexdigest()
hash2 = hashlib.md5((hash1 + challenge).encode()).hexdigest()
print(f"2. 최종 인증 해시 생성: {hash2}")

# 3. 최종 인증 요청
# 생성한 해시로 인증을 완료합니다.
final_payload = {"authorize": {"username": USERNAME, "password": hash2}}
res = requests.post(SERVER_URL, json=final_payload, headers=headers)

# 결과 출력
result = res.json()
print("3. 최종 인증 결과:")
print(result)
1. Challenge 값 수신: ad617c87a27382f149812dbf30c15762
2. 최종 인증 해시 생성: 9f10114fc82ea96bbd21c065fc72807f
3. 최종 인증 결과:
{'LTS': 1, 'authorize': {'status': 'OK'}}

 

🔷HTTP 헤더 인증 방식

Challenge 절차 대신, HTTP 헤더로 인증 정보를 전송할 수도 있습니다.
이 방식은 WebSocket API에서 필수입니다.

# CMD 예시    
curl -v -H 'Authorization: json {"username":"ceri","password":""}' http://101.1.xx.xx:4242/api2

▸ challenge 값은 WWW-Authenticate 응답 헤더에서 확인 가능
▸ 인증 성공 후에는 Body에 인증 정보를 포함하지 않아도 됩니다

*   Trying 101.1.xx.xx:4242...
* Connected to 101.1.xx.xx (101.1.xx.xx) port 4242
* using HTTP/1.x
> GET /api2 HTTP/1.1
> Host: 101.1.xx.xx:4242
> User-Agent: curl/8.13.0
> Accept: */*
> Authorization: json {"username":"ceri","password":""}
>
* Request completely sent off
< HTTP/1.1 403 Not authorized
< Server: MistServer/3.8
< WWW-Authenticate: json {"challenge":"ad617c87a27382f149812dbf30c15762","password":"","status":"CHALL","username":"ceri"}
* no chunk, no close, no size. Assume close to signal end
반응형

 

3. HTTP API vs WebSocket API

HTTP API와 WebSocket API는 데이터를 주고받는 구조와 동작 목적이 다릅니다.

HTTP API는 요청(Request)과 응답(Response)이 단발성으로 이뤄지며, WebSocket API는 한 번 연결 후 지속적으로 데이터를 푸시 받습니다.

 

🔷구조와 동작 원리

구분 HTTP API WebSocket API
연결 방식 요청(Request) 시 서버가 응답(Response)하는 단발성 통신 한 번 연결 후 지속 연결 상태 유지
데이터 수신 요청할 때만 최신 데이터 반환 이벤트가 발생하면 즉시 푸시(Push)
지연 시간 요청-응답 왕복 지연 존재 거의 실시간 반응
리소스 사용 요청 시마다 연결 생성/종료 연결 유지에 따른 메모리·세션 사용
적합한 작업 설정 변경, 상태 조회, 단발성 요청 실시간 모니터링, 이벤트 알림, 로그 스트리밍
대표 활용 예 설정 백업, 특정 시점의 스트림 정보 조회 실시간 뷰어 수 감시, 장애 이벤트 알림

▸ HTTP API → 단발성 요청(설정 변경·조회)에 적합
▸ WebSocket API → 서버 상태·로그·스트림 상태 등 실시간/이벤트 기반에 적합

 

🔷HTTP API 활용 예시

HTTP API는 요청할 때마다 연결을 열고 닫는 구조로 동작하며, 설정 변경·데이터 조회와 같은 단발성 작업에 적합합니다.

🔸 HTTP API 장점

▸ REST 스타일 구조로 직관적
▸ Bash, Python 등 다양한 환경에서 쉽게 호출 가능
▸ 방화벽 및 인증 설정이 단순

 

🔸 HTTP API 단점
▸ 실시간 이벤트 감지 불가
▸ 짧은 간격으로 반복 호출 시 서버 부하 증가 가능

 

🔸현재 활성화된 Stream 목록 조회 예시(인증 포함)

# 필요한 라이브러리를 가져옵니다.
import hashlib  # MD5 해시 함수를 사용하기 위한 라이브러리
import requests # HTTP 요청을 보내기 위한 라이브러리

# MD5 해시를 사용하여 비밀번호를 생성하는 함수입니다.
# 이 함수는 MistServer의 챌린지-응답 인증 방식에 맞춰 비밀번호 해시를 만듭니다.
def generate_password(password, challenge):
    # 1. 원본 비밀번호를 MD5 해시합니다.
    md5_pwd = hashlib.md5(password.encode()).hexdigest()
    # 2. 이 해시값과 서버로부터 받은 챌린지 값을 결합한 후, 다시 MD5 해시하여 최종 인증 해시를 만듭니다.
    return hashlib.md5((md5_pwd + challenge).encode()).hexdigest()

# 설정 변수
# MistServer의 API 엔드포인트 URL
SERVER_URL = "http://101.1.xxx.xxx:4242/api2"
# 인증에 사용할 사용자 이름
USERNAME = "ceri"
# 인증에 사용할 비밀번호
PASSWORD = "cericube"

# HTTP 요청 헤더 설정: JSON 형식의 데이터를 보낼 것임을 지정합니다.
headers = {"content-type": "application/json"}

# 1. 챌린지(Challenge) 값 요청
# 첫 번째 요청으로 서버에 사용자 정보를 보내고, 인증에 필요한 챌린지 값을 받습니다.
initial_payload = {
    "authorize": {
        "username": USERNAME,
        "password": PASSWORD
    }
}

try:
    # POST 요청을 보내고 서버 응답을 받습니다.
    res = requests.post(SERVER_URL, json=initial_payload, headers=headers)
    # 응답 JSON에서 'authorize' > 'challenge' 값을 추출합니다.
    challenge = res.json().get("authorize", {}).get("challenge", "")
    print(f"1. Challenge 값 수신: {challenge}")

    # 2. 인증 해시 생성
    # 수신한 챌린지 값과 비밀번호를 이용해 서버로 보낼 최종 인증 해시를 생성합니다.
    auth_hash = generate_password(PASSWORD, challenge)
    print(f"2. 생성된 해시: {auth_hash}")

    # 3. 최종 인증 및 스트림 정보 요청
    # 사용자 이름과 생성된 해시를 포함하여 최종 인증 요청을 보냅니다.
    # "active_streams": True 는 MistServer에게 현재 활성화된 스트림 목록을 요청하는 명령입니다.
    cap_payload = {
        "authorize": {
            "username": USERNAME,
            "password": auth_hash
        },
        "active_streams": True
    }

    # 최종 인증 요청을 보냅니다.
    res = requests.post(SERVER_URL, json=cap_payload, headers=headers)
    # 서버의 최종 응답(인증 성공 여부 및 활성 스트림 목록)을 출력합니다.
    print(res.json())

except requests.exceptions.RequestException as e:
    # HTTP 요청 중 발생할 수 있는 오류를 처리합니다.
    print(f"오류 발생: {e}")
except (KeyError, IndexError) as e:
    # JSON 데이터 파싱 중 발생할 수 있는 오류를 처리합니다.
    print(f"JSON 데이터 처리 중 오류 발생: {e}")
except Exception as e:
    # 기타 모든 예외를 처리합니다.
    print(f"알 수 없는 오류 발생: {e}")

이 코드는 MistServer API에 접속하기 위해 챌린지-응답(challenge-response) 인증 방식을 사용하며, 인증에 성공한 후 현재 활성화된 스트림 목록을 조회하는 파이썬 스크립트입니다.

 

🔷WebSocket API 활용 예시

WebSocket API는 실시간 데이터 수신이 필요할 때 사용합니다.
서버 상태, 스트림 이벤트, 로그 등을 이벤트 기반으로 즉시 받을 수 있어 대시보드·알림 시스템에 적합합니다.

🔸 WebSocket API 장점
▸ 실시간 이벤트 수신 가능
▸ 대시보드·알림·자동 제어 로직 구현에 최적
▸ 데이터 중복 전송 없음

🔸 WebSocket API 단점
▸ 지속 연결 유지로 세션 관리 필요
▸ 방화벽·네트워크 정책에 따라 연결 제한 가능
▸ 연결 끊김 시 재연결 로직 구현 필수

 

🔸기본 연결 구조 및 주요 파라미터

▸ 인증 방식: HTTP Authorization 헤더(JSON) 필수

Authorization: json {"username":"admin","password":"<해시값>"}

▸구독 파라미터 예시

요청 파라미터 설명
?logs=AMOUNT 최근 로그 + 실시간 로그 푸시
?logs=since:UNIXTIME 특정 시간 이후의 로그 수신
?accs=AMOUNT 접근 로그 실시간 수신
?streams=1 스트림 상태 실시간 수신
?logs=100&accs=100&streams=1 로그·접근 로그·스트림 상태 모든 데이터 실시간 수신

 

🔸 스트림 상태 실시간 수신 예시(인증 포함)

# 필요한 라이브러리를 가져옵니다.
import hashlib
import json 
import requests 
import websockets 
import asyncio 

# MD5 해시를 사용하여 비밀번호를 생성하는 함수입니다.
def generate_password(password, challenge):
    md5_pwd = hashlib.md5(password.encode()).hexdigest()
    return hashlib.md5((md5_pwd + challenge).encode()).hexdigest()

# 설정 변수
SERVER_URL = "http://101.1.xx.xx:4242/api2"
WS_URL = "ws://10.1.xx.xx:4242/ws?streams=1"

USERNAME = "ceri"
PASSWORD = "cericube"

# HTTP 요청 헤더 설정
headers = {"content-type": "application/json"}

# 메인 비동기 함수
async def main():
    try:
        # 1. 챌린지(Challenge) 값 요청
        initial_payload = {
            "authorize": {
                "username": USERNAME,
                "password": PASSWORD
            }
        }
        res = requests.post(SERVER_URL, json=initial_payload, headers=headers)
        res.raise_for_status()
        
        challenge = res.json().get("authorize", {}).get("challenge")
        if not challenge:
            print("오류: 서버로부터 챌린지 값을 받지 못했습니다. 인증 실패!")
            return

        print(f"1. Challenge 값 수신: {challenge}")

        # 2. 인증 해시 생성
        auth_hash = generate_password(PASSWORD, challenge)
        print(f"2. 생성된 해시: {auth_hash}")

        # 3. WebSocket 연결 (async with 사용)
        async with websockets.connect(
            WS_URL,
            additional_headers={
                "Authorization": f'json {{"username":"{USERNAME}","password":"{auth_hash}"}}'
            },
        ) as ws:
            print("WebSocket 연결 성공")
            while True:
                msg = await ws.recv()
                data = json.loads(msg)
                print("실시간 상태:", data)
    
    except requests.exceptions.RequestException as e:
        print(f"HTTP 요청 중 오류 발생: {e}")
    except websockets.exceptions.WebSocketException as e:
        print(f"WebSocket 연결 중 오류 발생: {e}")
    except (KeyError, IndexError, json.JSONDecodeError) as e:
        print(f"JSON 데이터 처리 중 오류 발생: {e}")
    except Exception as e:
        print(f"알 수 없는 오류 발생: {e}")

# 메인 함수 실행
if __name__ == "__main__":
    asyncio.run(main())
1. Challenge 값 수신: ad617c87a27382f149812dbf30c15762
2. 생성된 해시: 9f10114fc82ea96bbd21c065fc72807f
WebSocket 연결 성공
실시간 상태: ['auth', True]
실시간 상태: ['stream', ['rose', 4, 1, 1, 0, '']]
실시간 상태: ['stream', ['rose', 4, 0, 1, 0, '']]
실시간 상태: ['stream', ['rose', 0, 0, 1, 0, '']]
실시간 상태: ['stream', ['rose', 4, 0, 1, 0, '']]
실시간 상태: ['stream', ['rose', 4, 0, 2, 0, '']]

 

✔ 마무리

MistServer API는 HTTP API와 WebSocket API라는 두 가지 접근 방식을 제공하며, 각각의 특성과 활용 목적이 뚜렷하게 구분됩니다.


🔸HTTP API는 단발성 요청과 설정 변경, 특정 시점의 데이터 조회에 최적화되어 있습니다.
🔸WebSocket API는 실시간 상태 추적, 이벤트 감지, 대시보드·알림 시스템 구축에 강점을 갖습니다.

외부 호출 환경에서는 반드시 Challenge-Response 또는 Authorization 헤더(JSON) 방식으로 인증해야 하며, WebSocket API는 반드시 헤더 인증을 사용합니다.

 

운영 환경별 추천 조합:
▸ 정기 점검·설정 변경 자동화 → HTTP API
▸ 실시간 방송 상태·이벤트 모니터링 → WebSocket API
▸ 두 방식을 병행하면 안정성과 대응 속도를 모두 확보 가능


결국, API 구조와 인증 방식의 이해는 MistServer 운영 효율성과 보안을 동시에 지키는 핵심입니다.

 

 

👉 관련 글 링크

1. [MistServer] 설치 실습 - Ubuntu에 직접 설치 vs Docker 컨테이너 실행

2. [MistServer] 설치 후 필수 기본 설정 가이드 (v3.8 기준)

3. [MistServer] Input 실습: 다양한 입력 방식 설정과 스트림 결과 확인

4. [MistServer] Push 기능을 이용한 스트림 녹화 설정

5. [MistServer] DVR(Time-Shift) 설정과 재생 실습

6. [MistServer] OBS Studio와 MistServer 3.8을 이용한 라이브 방송 실습(RTMP,WHIP)

7. [MistServer] API 인증 방식과 HTTP·WebSocket API 비교

8. [MistServer] 스트림 관리 API 실습 (Python)

 

 

 

반응형

※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.

 

반응형