<aside> 파일 경로를 암호화하지 않았을 때 만약 악의적인 사용자가 응답 인터셉터를 통해 m3u8 데이터를 펼쳐보고 url을 확인한 뒤 다음 조각(세그먼트) 호출할 수 있게 됩니다.

그렇게 세그먼트 하나하나를 이어 붙여 하나의 영상을 만들 수가 있게 됩니다.

그래서 클라이언트가 세그먼트를 호출할 때 hls 서버를 바로 호출하는 것이 아니라 암호화된 GET 파라미터를 proxy 서버로 요청하고 proxy 서버에서 복호화 된 값을 통해 내부적인 hls 서버를 호출하도록 하였습니다. 이때 proxy 서버와 hls 서버는 각각 도커 컨테이너로 동작합니다.

</aside>

처음 영상을 가져올 때는 백엔드에서 사용자의 음원 소유권 체크를 하고, 소유 여부에 따라 10초 혹은 전체 m3u8을 가져와야 합니다. 이때 /play method: POST로 API 요청을 합니다.

image.png

proxy 서버의 play API를 통해 hls 서버에 m3u8 파일을 전달받아 경로를 암호화하고 다시 m3u8 형식에 맞게 가공합니다. 이때 timeout만큼만 클라이언트에게 m3u8 파일을 전달을 해야 합니다.

경로 뒤에 index.m3u8를 붙이면 서버에 파일이 실제로는 존재하지 않지만 hls 서버는 이는 감지하고 요청을 처리하여 해당하는 데이터를 생성하여 반환합니다.

전달받은 m3u8 파일 형식은 다음과 같습니다.

image.png

이후 클라이언트는 hls 라이브러리로 m3u8 파일 안에 작성된 url 세그먼트(proxy 서버로 요청)를 통해서 파일을 조각조각 받아와 스트리밍 합니다.

이때는 /play method : GET 방식 즉 https://proxy 서버/play/ZGVReXlYNUtnVHRUdWQrRG9CL3M1cmJacVRzNHBOdmZtVGlOR2VkQm12UFJPVHlLdlljQzF1NG16eC9YbW5JZFpKMkJtd1ExR2ZOSmNhTU83cVIvNVRuMHRFcHNRTVBsM045MEhsRXloaElFSFVsK2NsQWMzc3M9 형식으로 요청을 합니다.

image.png

정리를 하면 사용자는 초기에 정상적으로 암호화된 m3u8을 전달받고 다음 장면을 볼 때마다 m3u8에 정의된 GET url로 요청을 하게 되고 proxy서버는 복호화를 한 뒤 hls 서버에 리소스를 요청하고 hls 서버는 클라이언트에게 직접적으로 영상을 제공합니다. 이렇게 proxy 서버를 통해 hls 접근 제한을 했습니다.

지속적인 요청으로 인해 이벤트 루프 방식인 nodejs에서 AES-256 암복호화의 자원 사용률이 높아지는 점과 IV값이 없다는 점 또 HLS서버와 매번 커넥션을 맺어야 한다는 점 자원 점유율이 높았습니다. 때문에 최소 자원 효율을 위해 spring boot로 전환을 하였습니다.

image.png