웹 소켓 통신

(Web Socket)

 

 

 

웹 소켓(Web Socket)은 두 프로그램간의 메시지를 교환하기 위한 통신방법 중 하나입니다. 웹 소켓은 W3C와 IETF에 의해 자리잡은 표준 프로토콜 중 하나이기 때문에, 현재 인터넷을 사용하는 환경에서 특히 많이 사용되고 있습니다. 예를 들면, 크롬(Chrome)이나 엣지(Edge) 등의 웹 브라우저 같은 경우에 웹 소켓 프로토콜을 지원하고 있기 때문에, 웹 브라우저를 통해서 웹 소켓을 사용하려고 한다면, javascript를 사용해서 어렵지 않게 개발할 수 있습니다.

 

 

웹 소켓 특징 2가지

1. 양방향 통신(Full-Duplex)

양방향 통신이란 데이터 송수신을 동시에 처리할 수 있는 통신방법을 말하는 것입니다. 웹 소켓은 클라이언트(client)와 서버(server)가 서로에게 원할 때 데이터를 주고 받을 수 있으니 양방향이라고 말할 수 있는 것이죠.

※ 참고로, 양방향 통신이 아닌 단방향 통신은 한쪽으로만 송신이 가능한 방법을 말하는 것입니다.

 

2. 실시간 네트워킹(Real Time-Networking)

웹 환경(ex, 웹 브라우저)에서 채팅(chatting), 주식(stock), 비디오(video) 데이터 등의 데이터들은 연속된 데이터를 화면에 빠르게 보여주어야 하거나, 여러 단말기(ex, PC, 스마트폰)에 빠르게 데이터를 교환하는 실시간처리가 필요한 부분들이 있습니다. 예를 들어, 요즘 가상화폐들의 변하는 가격들을 웹 사이트에서 실시간으로 볼 수 있는데 이런 서비스를 구현할 때 사용될 수 있는 것이죠.

※ 웹 소켓 특징 중 하나가 실시간 네트워킹인 이유는 웹 소켓이 아닌 다른 비슷한 기술들로는 웹 브라우저 위에서 실시간으로 통신하기가 웹 소켓에 비해 상대적으로 어렵기 때문입니다.

 

 

웹 소켓 이전의 비슷한 기술

 

  1. Polling
  2. Long Polling
  3. Streaming
  4. XML Http Request
  5. Ajax (Asynchronous Javascript + XML)

 

사실, 웹 소켓이 등장하기 이전에, 웹 소켓의 기능과 동일하게 만들 수 있는 기술들이 있었습니다. 만약에, 웹 소켓의 이해가 부족하거나 웹 소켓을 이용해서 개발하기가 부담스러운 환경이라면, 기존의 기술들인 위 목록에 나와있는 것들 중에서 하나를 골라서 개발을 해도 웹 소켓의 기능을 비슷하게 구현가능 할 것입니다. 본 포스팅에서는 웹 소켓이 가지는 "양방향 통신"과 "실시간 통신"이라는 두가지 특징을 가지고 이전의 다른 기술들보다 조금 더 쉽게 구현할 수 있다는 것만 알아두겠습니다.

※ XML Http Request이나 Ajax의 경우,클라이언트가 서버에게 원할 때 데이터를 보내서 요청하는 것이 목적이기 때문에, 그 반대가 어렵습니다. 서버가 클라이언트에게 원할 때 데이터를 보내는 것은 어렵다는 것이죠.

 

 

웹 소켓 동작방법

 

 

웹 소켓 Handshaking 메시지 교환

 

  1. Web Clienthandshake 요청 메시지를 Web Server에게 보낸다.
  2. Web Server는 handshake 응답 메시지를 Web Client에게 보낸다.
  3. Web Client data payload framesWeb Server에게 보낸다.
  4. Web Server data payload framesWeb Client에게 보낸다.
  5. Web Clientclose frameWeb Server에게 보낸다.
  6. Web Server close frameWeb Client에게 보낸다.

 

웹 소켓 프로토콜 특징

  • 최초 접속에서만 http 프로토콜 위에서 handshaking을 하기 때문에 http header를 사용한다.
  • websocket을 위한 별도의 포트는 없으며, 기존 포트(http-80, https-443)를 사용한다.
  • websocket 프로토콜의 wshttp기반으로 운영되고, wsshttps기반으로 운영된다.
  • 메시지 (Upgrade:Websocket, Connection:Upgrade)
  • 메시지에 포함될 수있는 교환 가능한 메시지는 텍스트(text)와 바이너리(binary)이다.

 

웹 소켓 개발

웹 소켓 동작에 대한 이해를 돕기 위해, 실제로 웹 소켓을 사용해서 개발해야하는 경우, 개발환경에 따라 어떻게 사용될 수 있는지를 코드 일부를 추가해봤습니다. 우선 위 그림을 보면, 3개의 클라이언트와 한 개의 서버가 그려져 있습니다. 클라이언트 중 둘(=A와 B)은 javascript 코드를 사용해서 구현된 웹 애플리케이션(Web Application) 형태로 웹브라우저 위에서 동작되고, 다른 하나(=C)는 java 코드를 사용해서 구현된 안드로이드 애플리케이션(Android Appliacation) 형태로 동작되고 있다고 생각해보겠습니다. 이 3개의 클라이언트 애플리케이션는 웹 서버인 D와 웹 소켓을 사용해서 통신이 가능합니다.

 

웹 클라이언트인 A, B, C는 모두 서버 D와 통신하기 위해 "ws://joker.com/say"로 접속요청을 하고 있는 것을 볼 수 있습니다. 클라이언트는 서버에서 웹소켓을 위해 열어둔 해당 주소로 메시지를 보낼 수 있습니다. 반대로,서버가 접속된 클라이언트의 웹 소켓을 통해 메시지를 보낼 수 있죠. 이렇게 서로 웹 소켓이 연결되어 있다면 이를 통해 서로에게 원할 때 메시지를 보낼 수 있는 양방향 통신을 할 수 있게 되는 것입니다.

 

1. 클라이언트 코드

클라이언트로 사용할 수 있는 코드 몇 가지를 소개하겠습니다. 웹 소켓은 웹 기반의 기술이다보니 크롬(chrome), 엣지(edge) 등의 유명한 브라우저들은 개발자들이 쉽게 사용할 수 있도록 이미 javascript로 제공해주고 있습니다. 먼저, WebSocket API는 거의 대부분 브라우저들이 제공해주고 있습니다.  하지만,가끔 WebSocket API를 제공하지 않는 브라우저들이 있습니다. 그렇다고 사용자들한테 WebSocket이 있는 브라우저로 가서 사용하라고 할 수는 없겠죠. 그래서 웹 브라우저가 WebSocket을 제공해주지 않는다고 하더라도 앞에서 말한 HTTP Streaming이나 HTTP Long Polling 등의 기술들을 통해 WebSocket과 동일하게 동작하도록 시켜주는 SockJS라는 라이브러리가 있습니다. WebSocket API나 SockJS 모두 인터페이스는 거의 동일하기 때문에 큰 차이없이 사용할 수 있을 것입니다.

 

웹 브라우저가 아닌 다른 플랫폼인 안드로이드에서도 웹 소켓을 사용할 수 있습니다. WebSocketClient라는 라이브러리를 사용하면 웹 소켓 기능을 어렵지 않게 구현할 수 있습니다. 현재(2019년 10월), java나 android에서 웹 소켓을 위해 기본으로 제공해준는 API가 없기 때문에 직접 구현하거나 어느정도 안정되어 사용할 수 있는 WebSocketClient 라이브러리를 사용하면 됩니다.

 

코드 : javascript 

// 거의 모든 브라우저에서 지원
{
	var uri = "ws://joker.com/say";
	var ws = new WebSocket(uri);
	ws.onopen = function() {
		..
	}
}

 

코드 : javascript (SockJS)

// SockJS Client 사용
{
	var uri = " ws://joker.com/say";
	var sock = new SockJS(uri);
	sock.onopen = function() {
		..
	};
}

 

코드 : Java (in Android)

import org.java_websocket.client.WebSocketClient;
{
	Uri uri = new URI("ws://joker.com/say”);
	WebSocketClient ws = new WebSocketClient(uri) {
		public void onOpen(..) {
			..
		}
	}
} 

 

2. 서버 코드

서버는 스프링(springframework)을 사용하는 경우를 예로 들었습니다. 스프링에서는 웹 소켓에 대한 API를 제공해주고 있기 때문에, 스프링 개발 가이드 등의 많은 곳들에서 관련된 예제들을 살펴볼 수 있을 것입니다. 참고로,아래 registerWebSocketHandlers() 내용 중 “(2)”번 라인의 경우 웹 브라우저에서 WebSocket API를 제공하지 않을 경우, SockJS 라이브러리에 정의된 대로 동작하도록 추가시킨 것입니다. 따라서, "(2)"번 라인의 경우 현재 사용되고 있지만 만약에 모든 브라우저가 기본으로 제공된다면 제거를 해도 상관없을 것입니다.

 

코드 : Java (using Spring Framework)

// import org.springframework.web.socket.WebSocketHandler;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	private final WebSocketHandlerwsHandler;
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(new wsHandler(), "/say").setAllowedOrigins("*"); // (1)
		registry.addHandler(new wsHandler(), "/say").setAllowedOrigins("*").withSockJS(); // (2)
	}
}

 

 

웹 소켓 보안 고려사항

1. Non browser clients

웹 소켓은 클라이언트를 웹 브라우저를 사용해서 운영될 경우, header의 origin정보를 확인함으로써, 악성 javascript를 걸러낼 수 있습니다. 이 말은 웹 브라우저에서 기존에 사용하고 있던 동일 근원 정책(Same-Origin Policy)을 통해 악성 리소스(resource)로부터 보호할 수 있다는 것입니다.

※ Same-Origin Policy는 웹 브라우저의 페이지에 보여지기 위해 필요한 이미지(ex, jpg, png)나 javascript나 css등을 포함하는 모든 리소스(resource)들은 동일한 사이트로부터 가지고 와야한다는 정책으로 웹 브라우저에서 보안을 위해 만들어둔 기술을 말하는 것입니다.

 

웹 소켓은 클라이언트를 웹 브라우저가 아닌 다른 곳에서(ex, android, ios, windows) 운영될 경우, 악성 resource(ex, 악성 javascript)로부터 보호를 할 수 없으므로, 클라이언트와 서버는 이를 고려해서 사용해야 합니다. 웹 소켓은 웹 브라우저 위의 웹 페이지를 통해 사용되는 환경에서 운영되는 프로토콜로 만들어진 것이기 때문에, 웹 브라우저가 아닌 다른 클라이언트에서는 Same-Origin Policy와 같은 정책들을 전혀 사용할 수 없는 것이죠.

 

2. Origin considerations

앞에 1번 고려사항에서 언급했듯이, 웹 소켓은 origin 모델을 사용해서 악성 javascript로부터 보호하고 있습니다. 웹 브라우저에서 Same-Origin Policy을 통해 보호을 하고 있듯이, 웹 서버에서도 origin을 확인해야 하는 로직이 추가되어야 합니다.따라서, 서버에서 모르는 origin으로부터 요청이 들어온다면 "HTTP 403 Forbidden" 에러 상태 코드로 응답을 해서 통신을 못하도록 막아야 합니다.

 

3. WebSocket Client Authentication

웹 소켓 프로토콜은 핸드셰이킹(handshaking) 단계에서 서버가 클라이언트를 인증하는 특별한 방법을 제시하지 않고 있습니다. 따라서, 클라이언트 인증이 필요한 경우 HTTP 인증이나 TLS 인증 등을 사용해야 합니다.

※ 참고로, TLS 인증의 경우 핸드셰이킹 과정에서 클라이언트와 서버는 서로에게 자신의 인증서(Ceritificate)를 전달하고 이를 검증함으로써, 인증을 할 수 있습니다.

 

 

참고

Javascript WebSocket API 설명

https://developer.mozilla.org/ko/docs/Web/API/WebSocket

SockJS API 라이브러리

https://mvnrepository.com/artifact/org.webjars/sockjs-client/0.3.4

WebSocket 프로토콜 RFC 6455

https://tools.ietf.org/html/rfc6455