brunch

You can make anything
by writing

C.S.Lewis

by 강진우 Jul 31. 2015

tcp_syncookies는 어떻게 동작하는가?

Linux Network Internal

오늘 다룰 내용은  tcp_syncookies입니다. 조금은 어렵고 복잡한 이야기를 다룰  예정이고요, 아마도 제가 잘못 조사한 내용이 있을 수도 있으니 잘못된 부분이 있으면 댓글로 알려 주시면 좋겠습니다.


syn flooding 공격

먼저 syncookies 에 대해  이야기하기 전에 syn flooding 공격에 대해  이야기해보려고 합니다. 아시다시피 TCP는 세션을 맺기 위해 3-Way handshake 방식을  사용합니다.

정상적인 TCP 3-Way handshake

서버가 처음 listen() 시스템 콜을 이용해서 소켓을 만들면 커널에서는 SYN Backlog, Listen  Backlog라는 두 개의 큐를 만들게 됩니다. 그 후 클라이언트의 커넥션 요청인 SYN 패킷이 들어오면 해당 소켓 정보를 SYN Backlog에 저장하고 곧바로 SYN + ACK를 클라이언트로 보냅니다. 이 때 해당 소켓은 SYN_RECV 상태가 됩니다. 다음으로 클라이언트가 ACK 패킷을 보내게 되면 해당 소켓에 대한 정보는 Listen Backlog로 옮겨집니다. 그리고 서버에서 accept() 시스템 콜이 호출되면 해당 소켓은 최종적으로 Established 상태가 되며 Backlog 큐에서 빠져 나와 TCP 통신을 위한 준비를 합니다.

하지만, 클라이언트가 SYN + ACK에 대한 응답인 ACK를 보내지 않는다면 어떤 일이 벌어질까요?

ACK 를 보내지 않았을 때

그림에서 보이는 것처럼 SYN Backlog에는 처음 SYN을 받았을 때의 소켓 정보가 쌓이게 되고 설정된 크기 이상으로 들어오게 되면 더 이상 SYN 소켓의 정보를 저장할 수 없어 결국 SYN Drop이 발생하게 됩니다.

즉, 악의적으로 SYN 만을 보냄으로써 서버의 SYN  Backlog를 가득 채워 더 이상 신규 커넥션을 받아들이지 못하게 됩니다.

syncookies는 어떤 역할을 하게 될까?

위와 같이 syn flooding 공격을 받게 될 때 syncookies 기능을 켜게 되면 서버는 더 이상 SYN 패킷들을 SYN Backlog에 저장하지 않습니다. 저장하지 않고 SYN 패킷에 있는 정보들 (클라이언트 IP, timestamp, mss 값 등)을 이용해 syncookies라는 것을 만들고, 그 값을 SYN + ACK 의 ISN (Initial Sequence Number)로 만들어서 클라이언트에게 다시 보냅니다. 즉, 특정 알고리즘에 의해 생성된  ISN을 보내게 됩니다. (정상적인 상황이라면 그냥 random 값을 보냅니다.) 그 후 정상적인 클라라면 당연히 ACK를 보내게 될 테고요, 서버는 이 때 받은  ACK에서 Sequence Number를 추출해 내서 자신이 만들었던 숫자가 맞는지 검사를 하게 되고, 정상적인 패킷이라고 판단이 되면 Listen Backlog로 넘겨서 커넥션을 맺을 준비를 합니다.

그래서 syncookies를 켜게 되면 syn flooding 공격을 받는 중에도 정상적인 클라이언트들의 통신은 살릴 수 있습니다.

여기서 한가지 오해할 수 있는 부분이, syncookies 발행은 syn flooding에 의해 SYN Backlog가 가득 찼을 때만 이루어 집니다.

즉, syn flooding이 발생하지 않는 정상적인 상황에서는 안켰을때랑 동일하게 동작하고 TCP Option도 잘 구현 됩니다.


장점만 있을까요?

syn flooding 공격 중에도 정상 커넥션을 맺을 수 있기 때문에 장점만 있어 보이지만, 단점도 있습니다. syncookies를 생성하기 위해 사용하는 값들이 이미 정해져 있기 때문에 (mss 의 사이즈 등..) 결과적으로 TCP Option 헤더를 무시하게 됩니다. TCP Option 헤더에는 Windows scailing 옵션 같은 성능 향상을 위해 사용하는 내용들이 포함되어 있기 때문에 TCP Option 헤더를 무시한다는 것은 성능이 느려질 수 있다는 것을  의미합니다.

그럼에도 불구하고, 서버 입장에서는 syn drop 에 의해 아예 서비스를 못하는 것보다 느리게라도 서비스를 하는 것이 좋고, syncookies가 발행된다는 커널 메시지도 남기 때문에 현재 syn flooding 공격을 받고 있다는 것을 인지할 수 있어서 켜는 것이 좋습니다.

syn flooding 공격에 대한 대처 방안

그렇다면, syn flooding 이 발생했을 때 syncookies 말고 다른 대처 방안은 없는 걸까요?

아닙니다. 위 그림에서도 볼 수 있듯이 syn flooding 이 발생하는 원인은 SYN 패킷이 너무 많이 들어오는 경우도 있지만, 서버의 Backlog 값이 너무 작아서 그럴 수도 있습니다.

그것에 대한 판단 기준은.. netstat 상의 SYN_RECV 소켓들의 소스 IP 가 다양한가 아닌가를 가지고 판단할 수 있습니다. SYN_RECV 상태의 소켓들이 소스 IP가 전부 다 다르고 다양하다면 실제로 SYN 패킷이 많이 들어오는 공격으로 볼 수 있지만, 소스 IP가 어느 정도 한정되어 있는 상태라면 Backlog 값이 작아서 라고 볼 수 있습니다.

Backlog와 관련된 커널 파라미터는 두 가지가 있습니다.

net.ipv4.tcp_max_syn_backlog
net.core.somaxconn

이 값을 수정하면 syn  flooding을 줄이는 데 도움이 됩니다만, 값을 수정하고 커널 파라미터를 리로드 하는 것만으로 적용이 될까요? 아마 안될 겁니다. 이 값을 아무리 수정해도 SYN_RECV 값은 그대로인 것을 보실 수 있습니다. 왜 그럴까요? 이번 글에서 거기까지 다루면 너무 길어지기 때문에 아쉽지만.. 이 내용은 다음 글로 넘기겠습니다. ^^


긴 글 읽어주셔서 감사합니다.




매거진의 이전글 osquery, 어떻게 활용할 것인가
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari