SO_REUSEADDR 및 SO_EXCLUSIVEADDRUSE 사용

대부분의 네트워크 애플리케이션 개발자는 보안 높은 수준의 네트워크 인프라를 개발하는 것이 최우선 과제입니다. 그러나 완전히 안전한 솔루션을 고려할 때 매우 중요했음에도 불구하고 소켓 보안은 종종 간과됩니다. 특히 소켓 보안은 이전에 다른 애플리케이션 프로세스에 의해 바인딩된 동일한 포트에 바인딩되는 프로세스를 처리합니다. 과거에는 네트워크 애플리케이션이 다른 애플리케이션의 포트를 "하이재킹"하여 "서비스 거부" 공격 또는 데이터 도난으로 쉽게 이어질 수 있었습니다.

일반적으로 소켓 보안은 서버 쪽 프로세스에 적용됩니다. 특히 소켓 보안은 연결을 허용하고 IP 데이터그램 트래픽을 수신하는 모든 네트워크 애플리케이션에 적용됩니다. 이러한 애플리케이션은 일반적으로 잘 알려진 포트에 바인딩되며 악성 네트워크 코드의 일반적인 대상입니다.

클라이언트 애플리케이션은 덜 취약하기 때문이 아니라 대부분의 클라이언트가 정적 "서비스" 포트가 아닌 "임시" 로컬 포트에 바인딩되기 때문에 이러한 공격의 대상이 될 가능성이 적습니다. 강력한 아키텍처 이유가 없는 한 클라이언트 네트워크 애플리케이션은 바인딩 함수를 호출할 때 name 매개 변수가 가리키는 SOCKADDR 구조에서 포트 0을 지정하여 항상 임시 포트에 바인딩해야 합니다. 임시 로컬 포트는 포트 49151보다 큰 포트로 구성됩니다. 전용 서비스에 대한 대부분의 서버 애플리케이션은 포트 49151보다 작거나 같은 잘 알려진 예약된 포트에 바인딩됩니다. 따라서 대부분의 애플리케이션에서는 일반적으로 클라이언트와 서버 애플리케이션 간의 바인딩 요청에 대한 충돌이 없습니다.

이 섹션에서는 다양한 Microsoft Windows 플랫폼의 기본 보안 수준과 특정 소켓 옵션이 네트워크 애플리케이션 보안에 미치는 영향영향을 SO_EXCLUSIVEADDRUSE SO_REUSEADDR 방법을 설명합니다. 향상된 소켓 보안이라는 추가 기능은 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 소켓 옵션을 사용하면 소켓이 다른 소켓에서 사용 중인 포트에 강제로 바인딩할 수 있습니다. 두 번째 소켓은 원래 소켓과 동일한 포트에서 바인딩을 호출하기 전에 optname 매개 변수가 SO_REUSEADDR 설정되고 optval 매개 변수가 TRUE의 부울 값으로 설정된 setsockopt를 호출합니다. 두 번째 소켓이 성공적으로 바인딩되면 해당 포트에 바인딩된 모든 소켓의 동작이 확정되지 않습니다. 예를 들어 동일한 포트의 모든 소켓이 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 옵션은 optname 매개 변수가 SO_EXCLUSIVEADDRUSE 설정되고 optval 매개 변수가 소켓이 바인딩되기 전에 true의 부울 값으로 설정된 setsockopt 함수를 호출하여 설정됩니다. 옵션을 설정한 후 후속 바인딩 호출의 동작은 각바인딩 호출에 지정된 네트워크 주소에 따라 다릅니다.

아래 표에서는 Windows XP 및 이전 버전에서 두 번째 소켓이 특정 소켓 옵션을 사용하여 이전에 첫 번째 소켓에 바인딩된 주소에 바인딩하려고 할 때 발생하는 동작에 대해 설명합니다.

참고

아래 표에서 "와일드카드"는 지정된 프로토콜의 와일드카드 주소(예: IPv4의 경우 "0.0.0.0", IPv6의 경우 "::")를 나타냅니다. "특정"은 인터페이스가 할당된 특정 IP 주소를 표시합니다. 표 셀은 바인딩이 성공했는지("성공") 또는 오류가 반환되었는지( WSAEADDRINUSE 오류의 경우 "INUSE")를 나타냅니다. WSAEACCES 오류에 대한 "ACCESS"입니다.

첫 번째 바인딩 호출 두 번째 바인딩 호출
기본값 SO_REUSEADDR SO_EXCLUSIVEADDRUSE
와일드카드 특정 와일드카드 특정 와일드카드 특정
기본값 와일드카드 INUSE INUSE Success 성공 INUSE INUSE
특정 INUSE INUSE Success 성공 INUSE INUSE
SO_REUSEADDR 와일드카드 INUSE INUSE Success 성공 INUSE INUSE
특정 INUSE INUSE Success 성공 INUSE INUSE
SO_EXCLUSIVEADDRUSE 와일드카드 INUSE INUSE ACCESS ACCESS INUSE INUSE
특정 INUSE INUSE ACCESS ACCESS INUSE INUSE

두 개의 소켓이 동일한 포트 번호에 바인딩되지만 다른 명시적 인터페이스에서는 충돌이 없습니다. 예를 들어 컴퓨터에 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 또는 소켓 옵션을 전혀 설정하지 않는 경우 두 번째 바인딩 호출은 포트를 "하이재킹"하고 애플리케이션은 "공유" 포트로 전송된 특정 패킷을 받은 두 소켓 중 어느 것을 확인할 수 없습니다.

bind 함수를 호출하는 일반적인 애플리케이션은 바인딩 함수를 호출하기 전에 소켓에서 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
와일드카드 특정 와일드카드 특정 와일드카드 특정
기본값 와일드카드 INUSE Success ACCESS Success INUSE Success
특정 Success INUSE Success ACCESS INUSE INUSE
SO_REUSEADDR 와일드카드 INUSE Success 성공 성공 INUSE Success
특정 Success INUSE Success 성공 INUSE INUSE
SO_EXCLUSIVEADDRUSE 와일드카드 INUSE ACCESS ACCESS ACCESS INUSE ACCESS
특정 Success INUSE Success ACCESS INUSE INUSE

위의 표에 있는 몇 가지 항목은 장점 설명입니다.

예를 들어 첫 번째 호출자가 특정 주소에서 SO_EXCLUSIVEADDRUSE 설정하고 두 번째 호출자가 동일한 포트에서 와일드카드 주소로 바인딩 을 호출하려고 하면 두 번째 바인딩 호출이 성공합니다. 이 특정 경우 두 번째 호출자는 첫 번째 호출자가 바인딩된 특정 주소를 제외한 모든 인터페이스에 바인딩됩니다. 이 경우의 반대는 true가 아닙니다. 첫 번째 호출자가 SO_EXCLUSIVEADDRUSE 설정하고 호출이 와일드카드 플래그와 바인딩 되는 경우 두 번째 호출자는 동일한 포트로 바인딩 을 호출할 수 없습니다.

소켓 바인딩 호출이 다른 사용자 계정에서 이루어지면 소켓 바인딩 동작이 변경됩니다. 아래 표에서는 두 번째 소켓이 특정 소켓 옵션 및 다른 사용자 계정을 사용하여 이전에 첫 번째 소켓에 바인딩된 주소에 바인딩하려고 할 때 Windows Server 2003 이상 운영 체제에서 발생하는 동작을 지정합니다.

첫 번째 바인딩 호출 두 번째 바인딩 호출
기본값 SO_REUSEADDR SO_EXCLUSIVEADDRUSE
와일드카드 특정 와일드카드 특정 와일드카드 특정
기본값 와일드카드 INUSE ACCESS ACCESS ACCESS INUSE ACCESS
특정 Success INUSE Success ACCESS INUSE INUSE
SO_REUSEADDR 와일드카드 INUSE ACCESS Success 성공 INUSE ACCESS
특정 Success INUSE Success 성공 INUSE INUSE
SO_EXCLUSIVEADDRUSE 와일드카드 INUSE ACCESS ACCESS ACCESS INUSE ACCESS
특정 Success INUSE Success ACCESS INUSE INUSE

바인딩 호출이 다른 사용자 계정에서 이루어지는 경우 기본 동작은 다릅니다. 첫 번째 호출자가 소켓에서 옵션을 설정하지 않고 와일드카드 주소에 바인딩하는 경우 두 번째 호출자는 SO_REUSEADDR 옵션을 설정하고 동일한 포트에 성공적으로 바인딩할 수 없습니다. 옵션이 설정되지 않은 기본 동작도 오류를 반환합니다.

Windows Vista 이상에서는 IPv6 및 IPv4 둘 다에서 작동하는 이중 스택 소켓을 만들 수 있습니다. 이중 스택 소켓이 와일드카드 주소에 바인딩된 경우 지정된 포트는 IPv4 및 IPv6 네트워킹 스택 모두에서 예약되며 SO_REUSEADDRSO_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의 소켓 보안은 레거시 애플리케이션에 대한 보안 수준을 향상하지만 애플리케이션 개발자는 보안의 모든 측면을 염두에 두고 제품을 디자인해야 합니다.