SO_REUSEADDR 및 SO_EXCLUSIVEADDRUSE 사용
보안 높은 수준의 네트워크 인프라를 개발하는 것은 대부분의 네트워크 애플리케이션 개발자에게 우선 순위입니다. 그러나 완전히 안전한 솔루션을 고려할 때 매우 중요했음에도 불구하고 소켓 보안은 종종 간과됩니다. 특히 소켓 보안은 이전에 다른 애플리케이션 프로세스에 의해 바인딩된 동일한 포트에 바인딩되는 프로세스를 처리합니다. 과거에는 네트워크 애플리케이션이 다른 애플리케이션의 포트를 "하이재킹"할 수 있었기 때문에 "서비스 거부" 공격 또는 데이터 도난으로 쉽게 이어질 수 있었습니다.
일반적으로 소켓 보안은 서버 쪽 프로세스에 적용됩니다. 더 구체적으로, 소켓 보안은 연결을 허용하고 IP 데이터그램 트래픽을 수신하는 모든 네트워크 애플리케이션에 적용됩니다. 이러한 애플리케이션은 일반적으로 잘 알려진 포트에 바인딩되며 악성 네트워크 코드의 일반적인 대상입니다.
클라이언트 애플리케이션은 이러한 공격의 대상이 될 가능성이 적습니다. 이러한 공격은 덜 취약하기 때문이 아니라 대부분의 클라이언트가 정적 "서비스" 포트가 아닌 "임시" 로컬 포트에 바인딩하기 때문입니다. 클라이언트 네트워크 애플리케이션은 강력한 아키텍처 이유가 없는 한 항상 임시 포트에 바인딩해야 합니다(바인딩 함수를 호출할 때 이름 매개 변수가 가리키는 SOCKADDR 구조에서 포트 0을 지정하여). 임시 로컬 포트는 포트 49151보다 큰 포트로 구성됩니다. 전용 서비스에 대한 대부분의 서버 애플리케이션은 포트 49151보다 작거나 같은 잘 알려진 예약된 포트에 바인딩됩니다. 따라서 대부분의 애플리케이션에서는 일반적으로 클라이언트와 서버 애플리케이션 간의 바인딩 요청에 대한 충돌이 없습니다.
이 섹션에서는 다양한 Microsoft Windows 플랫폼의 기본 보안 수준과 특정 소켓 옵션이 네트워크 애플리케이션 보안에 미치는 영향과 영향을 SO_REUSEADDRSO_EXCLUSIVEADDRUSE 방법을 설명합니다. 향상된 소켓 보안이라는 추가 기능은 Windows Server 2003 이상에서 사용할 수 있습니다. 이러한 소켓 옵션 및 향상된 소켓 보안의 가용성은 아래 표와 같이 Microsoft 운영 체제 버전에 따라 다릅니다.
플랫폼 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | 향상된 소켓 보안 |
---|---|---|---|
Windows 95 | 이용 가능 | 사용할 수 없음 | 사용할 수 없음 |
Windows 98 | 가능 | 사용할 수 없음 | 사용할 수 없음 |
Windows Me | 이용할 수 있는 | 사용할 수 없음 | 사용할 수 없음 |
Windows NT 4.0 | 이용할 수 있는 | 서비스 팩 4 이상에서 사용 가능 | 사용할 수 없음 |
Windows 2000 | 이용할 수 있는 | 이용할 수 있는 | 사용할 수 없음 |
Windows XP | 사용 가능 | 이용할 수 있는 | 사용할 수 없음 |
Windows Server 2003 | 이용할 수 있는 | 이용할 수 있는 | 이용할 수 있는 |
Windows Vista | 이용할 수 있는 | 이용할 수 있는 | 이용할 수 있는 |
Windows Server 2008 | 이용할 수 있는 | 이용할 수 있는 | 이용할 수 있는 |
Windows 7 이상 | 이용 가능 | 이용 가능 | 이용할 수 있는 |
SO_REUSEADDR 사용
SO_REUSEADDR 소켓 옵션을 사용하면 소켓이 다른 소켓에서 사용 중인 포트에 강제로 바인딩할 수 있습니다. 두 번째 소켓은 SO_REUSEADDR로 optname 매개 변수를 설정하여 setsockopt를 호출한 후, TRUE 부울 값으로 optval 매개 변수를 설정하고, 원래 소켓과 동일한 포트에서 bind를 호출합니다. 두 번째 소켓이 성공적으로 바인딩되면 해당 포트에 바인딩된 모든 소켓의 동작이 확정되지 않습니다. 예를 들어 동일한 포트의 모든 소켓이 TCP 서비스를 제공하는 경우 포트를 통해 들어오는 모든 TCP 연결 요청이 올바른 소켓에서 처리되도록 보장할 수 없습니다. 동작은 비결정적입니다. 악의적인 프로그램은 SO_REUSEADDR 사용하여 표준 네트워크 프로토콜 서비스에 이미 사용 중인 소켓을 강제로 바인딩하여 해당 서비스에 대한 액세스를 거부할 수 있습니다. 이 옵션을 사용하려면 특별한 권한이 필요하지 않습니다.
서버 애플리케이션이 동일한 포트에 바인딩하기 전에 클라이언트 애플리케이션이 포트에 바인딩하는 경우 문제가 발생할 수 있습니다. 서버 애플리케이션이 SO_REUSEADDR 소켓 옵션을 사용하여 강제로 동일한 포트에 바인딩하는 경우 해당 포트에 바인딩된 모든 소켓의 동작은 확정되지 않습니다.
이 비결정적 동작의 예외는 멀티캐스트 소켓입니다. 두 소켓이 동일한 인터페이스와 포트에 바인딩되고 동일한 멀티캐스트 그룹의 멤버인 경우 데이터는 임의로 선택된 소켓이 아닌 두 소켓에 모두 전달됩니다.
SO_EXCLUSIVEADDRUSE의 사용
SO_EXCLUSIVEADDRUSE 소켓 옵션이 도입되기 전에는 네트워크 애플리케이션 개발자가 악의적인 프로그램이 네트워크 애플리케이션에 자체 소켓이 바인딩된 포트에 바인딩되지 않도록 방지하기 위해 수행할 수 있는 작업은 거의 없었습니다. 이 보안 문제를 해결하기 위해 Windows 소켓은 sp4(서비스 팩 4) 이상에서 Windows NT 4.0에서 사용할 수 있는 SO_EXCLUSIVEADDRUSE 소켓 옵션을 도입했습니다.
SO_EXCLUSIVEADDRUSE 소켓 옵션은 Windows XP 및 이전 버전의 Administrators 보안 그룹 구성원만 사용할 수 있습니다. 이 요구 사항이 Windows Server 2003 이상에서 변경된 이유는 이 문서의 뒷부분에서 설명합니다.
SO_EXCLUSIVEADDRUSE 옵션은 소켓이 바인딩되기 전에 setsockopt 함수를 호출하여 설정하며, 이때 optname 매개 변수를 SO_EXCLUSIVEADDRUSE로 설정하고, optval 매개 변수를 부울 값인 TRUE로 설정합니다. 옵션을 설정한 후 후속 바인딩 호출의 동작은 각 바인딩 호출에 지정된 네트워크 주소에 따라 다릅니다.
아래 표에서는 Windows XP 및 이전 버전에서 두 번째 소켓이 특정 소켓 옵션을 사용하여 이전에 첫 번째 소켓에 바인딩된 주소에 바인딩하려고 할 때 발생하는 동작에 대해 설명합니다.
메모
아래 표에서 "와일드카드"는 지정된 프로토콜의 와일드카드 주소(예: IPv4의 경우 "0.0.0.0", IPv6의 경우 "::")를 나타냅니다. "특정"은 인터페이스가 할당된 특정 IP 주소를 표시합니다. 표 셀은 바인딩이 성공했는지("성공"), 아니면 오류가 반환되는지("INUSE"는 WSAEADDRINUSE 오류, "ACCESS"는 WSAEACCES 오류)를 나타냅니다.
첫 번째 바인딩 호출 | 두 번째 바인딩 호출 | ||||||
기본값 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
와일드 카드 | 특정 | 와일드 카드 | 특정 | 와일드 카드 | 특정 | ||
기본값 | 와일드 카드 | 사용중 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 |
특정 | 사용 중 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 | |
SO_REUSEADDR | 와일드 카드 | 사용 중 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 |
특정 | 사용 중 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 | |
SO_EXCLUSIVEADDRUSE | 와일드 카드 | 사용 중 | 사용 중 | 접근 | 접근 | 사용 중 | 사용 중 |
특정 | 사용 중 | 사용 중 | 접근 | 접근 | 사용 중 | 사용 중 |
두 소켓이 동일한 포트 번호에 바인딩되어 있지만 다른 명시적 인터페이스에서는 충돌이 없습니다. 예를 들어, 컴퓨터에 10.0.0.1 및 10.99.99.99라는 두 개의 IP 인터페이스가 있는 경우, 포트가 5150으로 설정되고 SO_EXCLUSIVEADDRUSE가 지정된 상태로 10.0.0.1에서 바인드에 대한 첫 번째 호출을 수행한 후, 아무 옵션 없이 포트가 동일하게 5150으로 설정된 상태에서 10.99.99.99에서 바인드에 대한 두 번째 호출을 실행하면 성공합니다. 그러나 첫 번째 소켓이 와일드카드 주소 및 포트 5150에 바인딩된 경우 SO_EXCLUSIVEADDRUSE 집합이 있는 포트 5150에 대한 후속 바인딩 호출은 WSAEADDRINUSE 또는 바인딩 작업에서 반환된 WSAEACCES 실패합니다.
바인딩 첫 번째 호출이 SO_REUSEADDR 또는 소켓 옵션을 전혀 설정하지 않는 경우 두 번째 바인딩 호출은 포트를 "하이재킹"하고 애플리케이션은 "공유" 포트로 전송된 특정 패킷을 받은 두 소켓 중 어느 것을 확인할 수 없습니다.
바인딩 함수를 호출하는 일반적인 애플리케이션은 바인딩 함수를 호출하기 전에 소켓에서 SO_EXCLUSIVEADDRUSE 소켓 옵션을 호출하지 않는 한 배타적 사용을 위해 바인딩된 소켓을 할당하지 않습니다. 서버 애플리케이션이 동일한 포트에 바인딩되기 전에 클라이언트 애플리케이션이 임시 포트 또는 특정 포트에 바인딩하는 경우 문제가 발생할 수 있습니다. 서버 애플리케이션은 바인딩 함수를 호출하기 전에 소켓의 SO_REUSEADDR 소켓 옵션을 사용하여 동일한 포트에 강제로 바인딩할 수 있지만 해당 포트에 바인딩된 모든 소켓의 동작은 확정되지 않습니다. 서버 애플리케이션이 포트를 단독으로 사용하기 위해 SO_EXCLUSIVEADDRUSE 소켓 옵션을 사용하려고 하면 요청이 실패합니다.
반대로 SO_EXCLUSIVEADDRUSE 집합이 있는 소켓은 소켓 닫기 직후에 다시 사용할 수 없습니다. 예를 들어 SO_EXCLUSIVEADDRUSE 집합이 있는 수신 대기 소켓이 연결을 수락한 다음 이후에 닫히면 원래 연결이 비활성 상태가 될 때까지 다른 소켓(SO_EXCLUSIVEADDRUSE포함)이 첫 번째 소켓과 동일한 포트에 바인딩할 수 없습니다.
소켓이 닫혀 있어도 기본 전송 프로토콜이 연결을 종료하지 못할 수 있으므로 이 문제는 복잡해질 수 있습니다. 애플리케이션에서 소켓을 닫은 후에도 시스템은 버퍼링된 데이터를 전송하고, 피어에 정상적인 연결 끊기 메시지를 보내고, 피어에서 해당 정상 연결 끊기 메시지를 기다려야 합니다. 기본 전송 프로토콜이 연결을 해제하지 않을 수 있습니다. 예를 들어 원래 연결에 참여하는 피어는 크기가 0인 창이나 다른 형태의 "공격" 구성을 보급할 수 있습니다. 이러한 경우 클라이언트 연결은 승인되지 않은 데이터가 버퍼에 남아 있으므로 클라이언트 연결을 닫는 요청에도 불구하고 활성 상태로 유지됩니다.
이러한 상황을 방지하려면 네트워크 애플리케이션은 SD_SEND 플래그가 설정된 종료 호출하여 우아한 종료를 보장한 후, 연결을 통해 0 바이트가 반환될 때까지 recv 루프에서 기다려야 합니다. 이렇게 하면 모든 데이터가 피어에서 수신되고, 앞서 언급한 포트 재사용 문제를 방지할 뿐만 아니라 전송된 모든 데이터를 수신했음을 피어와 마찬가지로 확인합니다.
포트가 "활성" 대기 상태로 전환되지 않도록 소켓에 SO_LINGER 소켓 옵션을 설정할 수 있습니다. 그러나 연결 재설정과 같은 원치 않는 효과로 이어질 수 있으므로 권장되지 않습니다. 예를 들어, 피어에서 데이터를 받았지만 승인되지 않은 상태이고, 로컬 컴퓨터가 SO_LINGER가 설정된 소켓을 닫으면, 두 컴퓨터 간의 연결이 초기화되고 피어에서 승인되지 않은 데이터가 삭제됩니다. 시간 제한 값이 작을수록 연결이 갑자기 중단되는 경우가 많지만, 시간 제한 값이 클수록 시스템이 서비스 거부 공격에 취약해지게 됩니다(많은 연결을 설정하고 애플리케이션 스레드를 지연/차단할 수 있기 때문에). 0이 아닌 느린 시간 제한 값이 있는 소켓을 닫으면 closesocket 호출이 차단될 수도 있습니다.
향상된 소켓 보안
Windows Server 2003 릴리스와 함께 향상된 소켓 보안이 추가되었습니다. 이전 Microsoft 서버 운영 체제 릴리스에서 기본 소켓 보안을 통해 프로세스는 의심하지 않는 애플리케이션에서 포트를 쉽게 하이재킹할 수 있습니다. Windows Server 2003에서 소켓은 기본적으로 공유 가능한 상태가 아닙니다. 따라서 애플리케이션이 소켓이 이미 바인딩된 포트를 다른 프로세스에서 다시 사용하도록 허용하려는 경우 특별히 사용하도록 설정해야 합니다. 이 경우 포트에서 바인딩 호출하는 첫 번째 소켓은 소켓에 SO_REUSEADDR 설정해야 합니다. 이 경우의 유일한 예외는 두 번째 바인딩 호출이 원래 바인딩호출한 동일한 사용자 계정에서 수행될 때 발생합니다. 이 예외는 이전 버전과의 호환성을 제공하기 위해서만 존재합니다.
아래 표에서는 두 번째 소켓이 특정 소켓 옵션을 사용하여 이전에 첫 번째 소켓에 바인딩된 주소에 바인딩하려고 할 때 Windows Server 2003 이상 운영 체제에서 발생하는 동작에 대해 설명합니다.
메모
아래 표에서 "와일드카드"는 지정된 프로토콜의 와일드카드 주소(예: IPv4의 경우 "0.0.0.0", IPv6의 경우 "::")를 나타냅니다. "특정"은 인터페이스가 할당된 특정 IP 주소를 표시합니다. 표 셀은 바인딩이 성공했는지 여부("성공") 또는 반환된 오류를 나타냅니다. 반환된 오류는 WSAEADDRINUSE 오류에 대한 "INUSE" 또는 WSAEACCES 오류에 대한 "ACCESS"입니다.
또한 이 특정 테이블에서는 두 바인딩 호출이 동일한 사용자 계정으로 수행됩니다.
첫 번째 바인딩 호출 | 두 번째 바인딩 호출 | ||||||
기본값 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
와일드 카드 | 특정 | 와일드 카드 | 특정 | 와일드 카드 | 특정 | ||
기본값 | 와일드 카드 | 사용 중 | 성공 | 접근 | 성공 | 사용 중 | 성공 |
특정 | 성공 | 사용 중 | 성공 | 접근 권한 | 사용 중 | 사용 중 | |
SO_REUSEADDR | 와일드 카드 | 사용 중 | 성공 | 성공 | 성공 | 사용 중 | 성공 |
특정 | 성공 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 | |
SO_EXCLUSIVEADDRUSE | 와일드 카드 | 사용 중 | 접근 | 접속 | 접근 | 사용 중 | 접근 |
특정 | 성공 | 사용 중 | 성공 | 접근 | 사용 중 | 사용 중 |
위의 표에 있는 몇 가지 항목은 설명이 필요합니다.
예를 들어 첫 번째 호출자가 특정 주소에 SO_EXCLUSIVEADDRUSE 설정하고 두 번째 호출자가 동일한 포트에 와일드카드 주소를 사용하여 바인딩 호출하려고 하면 두 번째 바인딩 호출이 성공합니다. 이 특정 경우 두 번째 호출자는 첫 번째 호출자가 바인딩된 특정 주소를 제외한 모든 인터페이스에 바인딩됩니다. 이 경우의 반대는 사실이 아닙니다. 첫 번째 호출자가 SO_EXCLUSIVEADDRUSE 설정하고 와일드카드 플래그를 사용하여 바인딩할 호출하는 경우 두 번째 호출자는 동일한 포트를 사용하여 바인딩 호출할 수 없습니다.
소켓 바인딩 동작은 소켓 바인딩 호출이 다른 사용자 계정에서 이루어지면 변경됩니다. 아래 표에서는 두 번째 소켓이 특정 소켓 옵션 및 다른 사용자 계정을 사용하여 이전에 첫 번째 소켓에 바인딩된 주소에 바인딩하려고 할 때 Windows Server 2003 이상 운영 체제에서 발생하는 동작을 지정합니다.
첫 번째 바인딩 호출 | 두 번째 바인딩 호출 | ||||||
기본값 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
와일드 카드 | 특정 | 와일드 카드 | 특정 | 와일드 카드 | 특정 | ||
기본값 | 와일드 카드 | 사용 중 | 접근 | 접근 | 접근 | 사용 중 | 접근 |
특정 | 성공 | 사용 중 | 성공 | 접근 | 사용 중 | 사용 중 | |
SO_REUSEADDR | 와일드 카드 | 사용 중 | 접근 | 성공 | 성공 | 사용 중 | 접근 |
특정 | 성공 | 사용 중 | 성공 | 성공 | 사용 중 | 사용 중 | |
SO_EXCLUSIVEADDRUSE | 와일드 카드 | 사용 중 | 접근 | 접근 | 접근 | 사용 중 | 접근 |
특정 | 성공 | 사용 중 | 성공 | 접근 | 사용 중 | 사용 중 |
기본 동작은 바인딩 호출이 다른 사용자 계정에서 이루어지는 경우 다릅니다. 첫 번째 호출자가 소켓에서 옵션을 설정하지 않고 와일드카드 주소에 바인딩하는 경우 두 번째 호출자는 SO_REUSEADDR 옵션을 설정하고 동일한 포트에 성공적으로 바인딩할 수 없습니다. 옵션 집합이 없는 기본 동작도 오류를 반환합니다.
Windows Vista 이상에서는 IPv6 및 IPv4 둘 다에서 작동하는 이중 스택 소켓을 만들 수 있습니다. 이중 스택 소켓이 와일드카드 주소에 바인딩되면 지정된 포트는 IPv4 및 IPv6 네트워킹 스택 모두에서 예약되며 SO_REUSEADDR 및 SO_EXCLUSIVEADDRUSE(설정된 경우)와 관련된 검사가 수행됩니다. 이러한 검사는 두 네트워킹 스택에서 모두 성공해야 합니다. 예를 들어 이중 스택 TCP 소켓이 SO_EXCLUSIVEADDRUSE 설정한 다음 포트 5000에 바인딩하려고 하면 다른 TCP 소켓을 이전에 포트 5000(와일드카드 또는 특정)에 바인딩할 수 없습니다. 이 경우, IPv4 TCP 소켓이 이전에 포트 5000의 루프백 주소에 바인딩되어 있었다면, 이중 스택 소켓에 대한 바인드 호출은 WSAEACCES오류로 인해 실패했을 것입니다.
애플리케이션 전략
소켓 계층에서 작동하는 네트워크 애플리케이션을 개발할 때 필요한 소켓 보안 유형을 고려하는 것이 중요합니다. 클라이언트 애플리케이션(서비스에 데이터를 연결하거나 전송하는 애플리케이션)은 임의 로컬(임시) 포트에 바인딩하기 때문에 추가 단계가 거의 필요하지 않습니다. 클라이언트가 제대로 작동하기 위해 특정 로컬 포트 바인딩이 필요한 경우 소켓 보안을 고려해야 합니다.
SO_REUSEADDR 옵션은 동일한 포트에 바인딩된 모든 소켓에 데이터가 전달되는 멀티캐스트 소켓을 제외하고 일반 애플리케이션에서 거의 사용하지 않습니다. 그렇지 않으면 "소켓 하이재킹"에 매우 취약하므로 이 소켓 옵션을 설정하는 모든 애플리케이션을 다시 디자인하여 종속성을 제거해야 합니다. SO_REUSEADDR 소켓 옵션을 사용하여 서버 애플리케이션에서 포트를 하이재킹할 수 있는 한 애플리케이션은 안전하지 않은 것으로 간주되어야 합니다.
모든 서버 애플리케이션은 강력한 수준의 소켓 보안을 위해 SO_EXCLUSIVEADDRUSE 설정해야 합니다. 악성 소프트웨어가 포트를 하이재킹하는 것을 방지할 뿐만 아니라 다른 애플리케이션이 요청된 포트에 바인딩되어 있는지 여부도 나타냅니다. 예를 들어 다른 프로세스가 특정 인터페이스의 동일한 포트에 현재 바인딩되어 있는 경우, SO_EXCLUSIVEADDRUSE 소켓 옵션이 설정된 프로세스가 와일드카드 주소에바인딩하려는 호출은 실패합니다.
마지막으로, Windows Server 2003에서 소켓 보안이 향상되었지만 애플리케이션은 항상 SO_EXCLUSIVEADDRUSE 소켓 옵션을 설정하여 프로세스가 요청한 모든 특정 인터페이스에 바인딩되도록 해야 합니다. Windows Server 2003의 소켓 보안은 레거시 애플리케이션에 대한 보안 수준을 향상하지만 애플리케이션 개발자는 보안의 모든 측면을 염두에 두고 제품을 디자인해야 합니다.