본문 바로가기

Web hacking

소켓 통신 알아보기

웹 소켓이란

 

먼저, 웹 브라우저와 웹 사이트 간의 대부분의 통신은 HTTP를 사용한다. HTTP를 사용하면 클라이언트가 요청을 보내고 서버는 응답을 반환한다. 일반적으로 응답은 즉시 발생하고 트랜잭션이 완료된다. 네트워크 연결이 계속 열려 있어도 요청과 응답의 별도 트랜잭션에 사용된다. 일부 최신 웹 사이트는 WebSocket을 사용한다. WebSocket 연결은 HTTP를 통해 시작되며 일반적으로 오래 지속된다. 메시지는 언제든지 어느 방향으로나 전송될 수 있으며 본질적으로 트랜잭션이 아니다. 연결은 일반적으로 클라이언트나 서버가 메시지를 보낼 준비가 될 때까지 열려 있고 유휴 상태로 유지된다. WebSocket은 금융 데이터의 실시간 피드와 같이 대기 시간이 짧거나 서버에서 시작되는 메시지가 필요한 상황에서 특히 유용하다. 

 

웹 소켓은 일반적으로 아래와 같은 클라이언트 자바스크립트를 통해 생성된다. 

var ws = new WebSocket("wss://normal-website.com/chat");

 

 

웹 소켓 통신 전환 요청 및 확인

GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket

 

Connection: Upgrade를 보고 다른 프로토콜로 전환해달라는 요청인 것을 알 수 있다.  그렇다면 어떤 프로토콜로 전환이 될까? Upgrade: websocket 부분을 보고 websocket 통신으로의 전환을 요청한다는 것을 알 수 있다. 

 

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=

 

프로토콜 전환 요청이 성공적으로 이루어 지면, 서버 측에서는 101 Switching Protocols응답과 함께 위와 같은 응답을 해준다. 

 

 

소켓 통신 흐름

 

출처: https://recipes4dev.tistory.com/153

 

클라이언트 (Client)

1) socket() : 소켓 생성
2) connect() : 통신 할 서버에 설정된 ip와 port 번호에 연결(통신)을 시도
3) 통신을 시도 시, 서버가 accept() 함수를 이용하여 클라이언트의 socket descriptor를 반환
4) 이를 통해 클라이언트와 서버가 서로 read(), write()를 하며 통신 (이 과정이 반복)

 

서버 (Server)

 

1) socket() 함수를 이용해 소캣을 생성
2) bind() 함수로 ip와 port 번호를 설정
3) listen() 함수로 클라이언트의 접근 요청에 수신 대기열을 만들어 몇 개의 클라이언트를 대기시킬지 결정
4) accept() 함수를 사용하여 클라이언트와의 연결을 기다림

5) send() / recv() : 데이터를 전송하거나 받기
6) close() : 소켓 닫기

 

 

파이썬 소켓 통신(간단 구현)

 

클라이언트

import socket

# 서버의 IP 주소와 포트 번호
server_ip = '127.0.0.1'
server_port = 54321

# 클라이언트 소켓 생성
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 서버에 연결
client_socket.connect((server_ip, server_port))

# 사용자로부터 메시지 입력 받기
request_message = input('message: ').encode('utf-8')

# 입력 받은 메시지를 서버로 전송 
client_socket.sendall(request_message)

# 서버로부터 응답 수신
response = client_socket.recv(1024)

# 수신한 응답을 UTF-8 형식으로 디코딩하여 출력
print(response.decode('utf-8'))

# 클라이언트 소켓 닫기
client_socket.close()

 

 

서버

import socket

# 서버의 IP 주소와 포트 번호
server_ip = '127.0.0.1'
server_port = 54321

# 서버 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 서버 소켓을 주소에 바인딩
server_socket.bind((server_ip, server_port))

# 클라이언트의 연결을 기다림
server_socket.listen(1)

print("서버가 시작되었습니다. 클라이언트의 연결을 기다립니다...")

while True:
    # 클라이언트의 연결 요청을 수락
    client_socket, client_address = server_socket.accept()
    print(f"클라이언트 {client_address}가 연결되었습니다.")

    # 클라이언트로부터 메시지 수신
    request_message = client_socket.recv(1024)

    # 받은 메시지를 그대로 에코하여 클라이언트에게 다시 전송
    client_socket.sendall(request_message)

    # 클라이언트 소켓 종료
    client_socket.close()

# 서버 소켓 종료
server_socket.close()

 

 

 

< 참조 >

 

https://recipes4dev.tistory.com/153

https://portswigger.net/web-security/websockets/what-are-websockets