프로의 안전을 개발하면서 외부 NVR 서버에 접근해야 하는 경우가 생겼습니다.
하지만 NVR은 보안상 외부에 직접 노출되면 안 되기 때문에, 중간에 인증 및 프록시 서버를 두는 구조를 설계하게 되었습니다.
이 글은 그 구조를 만들고 운영까지 하면서 얻은 경험을 공유하는 글입니다.
🔐 1. 배경: NVR 서버의 Digest 인증과 외부 접근 제한
NVR(Network Video Recorder)은 대부분 보안상의 이유로 외부 노출이 어렵고, 인증 방식도 일반적인 Basic Auth가 아닌 Digest 인증을 사용합니다.
Digest 인증이란?
HTTP 기본 인증(Basic Auth)은 ID/PW를 Base64로 노출하는 방식이라 보안이 약합니다.
반면 Digest Auth는 서버가 nonce 값을 보내고, 클라이언트가 MD5 해시로 암호화된 응답값을 다시 보내는 방식이라 보안성이 높습니다.
Digest 인증은 서버가 nonce, realm 등의 정보를 포함한 challenge를 클라이언트에게 응답으로 주고,
클라이언트는 이를 바탕으로 해시를 계산한 후 다시 인증 요청을 보내는 방식입니다.
이러한 구조 때문에 브라우저에서 WebSocket을 통해 NVR로 직접 연결을 시도하면 Digest 인증 문제로 실패하게 됩니다.
브라우저는 WebSocket 요청에 커스텀 인증 헤더(Authorization)를 포함시키지 못하고,
401 Unauthorized를 받더라도 자동 재시도가 되지 않기 때문입니다.
전체 흐름 구조는 아래와 같습니다.
🧭 2. 해결 방향: FE에서 Digest 인증 처리 후, 프록시 서버에서 요청 중계
- FE(프론트엔드)에서 사용자가 입력한 ID/PW를 기반으로 Digest 인증 헤더를 생성합니다.
- FE는 이 Authorization 헤더를 WebSocket 요청에 함께 담아 프록시 서버로 전달합니다.
- 프록시 서버(Nginx)는 이 요청을 가로채 Digest 인증 헤더를 유지한 채 내부망 NVR 서버로 중계합니다.
- NVR은 해당 헤더를 검증하고 스트리밍 응답을 보내게 됩니다.
🛠️ 3. 프록시 서버 Nginx 설정
아래는 실제로 구성한 Nginx 설정 중 주요 부분입니다.
포트는 9898, 도메인은 proxy.pro-safe.co.kr을 사용했고, 인증서도 Let’s Encrypt로 설정했습니다.
server {
listen 9898 ssl;
server_name proxy server;
ssl_certificate /etc/letsencrypt/live/proxy.pro-safe.co.kr/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/proxy.pro-safe.co.kr/privkey.pem;
# 루트 접근 시 NVR로 리디렉션
location = / {
proxy_pass NVR 서버 주소;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Authorization $http_authorization;
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 86400;
# StreamingServer
location /StreamingServer {
# CORS preflight (필요 시 OPTIONS)
if ($request_method = OPTIONS ) {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-T>
add_header 'Access-Control-Max-Age' 3600;
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain';
return 204;
}
proxy_pass NVR 스트리밍 서버 주소;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Authorization $http_authorization;
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
위와 같은 구조를 통해 외부 사용자도 안전하게 NVR 영상에 접근할 수 있게 되었습니다.
Digest 인증이 필요한 NVR 서버는 직접 노출되지 않으면서도 인증 처리와 스트리밍 요청을 처리할 수 있게 되었습니다.
WebSocket 스트리밍 연결도 안정적으로 유지되었고, 서버 타임아웃도 충분히 확보하여 영상 끊김 없이 재생이 가능했습니다.
'python' 카테고리의 다른 글
python 네이버 금융 웹 스크래핑 (0) | 2022.05.14 |
---|---|
파이썬 웹 스크래핑 (0) | 2022.05.14 |
set과 frozenset (0) | 2022.04.07 |
dict & defaultdict (0) | 2022.04.06 |
파이썬의 메모리 관리 (0) | 2022.04.06 |