모든 네트워크 인터페이스 바인딩

서비스의 의도된 접근 범위를 넘는 네트워크 인터페이스 바인딩

설명

서버가 0.0.0.0 또는 빈 호스트 주소로 바인딩되면 여러 네트워크 인터페이스에서 요청을 받을 수 있습니다. 실제 외부 접근 가능 여부는 라우팅과 방화벽 등에도 달려 있습니다. 모든 인터페이스에서 수신하는 것 자체가 인증 우회는 아니지만, 내부 전용 서비스의 인증·TLS·네트워크 통제가 노출 범위에 맞지 않으면 민감 정보나 관리 기능이 의도치 않게 공개될 수 있습니다.

잠재적 영향

  • 민감 정보 노출: 외부에서 접근할 수 있고 적절히 보호되지 않은 관리·디버그·메트릭 엔드포인트에서 설정, 토큰이나 세션 정보가 유출될 수 있습니다.
  • 접근 범위 확대: 내부망에서만 사용하려던 기능에 외부 클라이언트가 직접 요청할 수 있습니다. 실제 작업 권한은 서비스의 인증·인가에 따라 달라집니다.
  • 공격 표면 확대: 불필요하게 공개된 서비스가 취약한 버전이나 계정을 이용한 공격의 진입점이 될 수 있습니다.

해결 방법

  • 수신 주소를 명시하세요. 내부 전용 서비스에는 net.Listen, tls.Listen의 주소로 루프백이나 필요한 내부망 IP를 사용하세요.
  • 환경별로 주소와 포트를 관리하고, 운영 환경의 모든 인터페이스 수신은 의도된 노출인지 검토하세요.
  • 외부에 필요하지 않은 포트는 방화벽이나 클라우드 보안 그룹으로 승인된 네트워크·IP에만 허용하세요.
  • 리버스 프록시를 사용한다면 같은 호스트·네트워크 네임스페이스에서는 루프백, 별도 호스트나 컨테이너에서는 필요한 사설 연결 경로로 백엔드 접근을 제한하세요. 인증과 전송 보호도 적용하세요.
  • 실제 수신 소켓과 외부에서 접근 가능한 포트를 정기적으로 확인하세요.

예시

변경 전

go
package main

import (
    "log"
    "net"
)

// 내부 관리용 TCP 서버 예시
func startAdminServer() {
    // 비준수: 모든 인터페이스(0.0.0.0)로 bind -> 내부 관리 포트가 외부에도 노출될 수 있음
    listener, err := net.Listen("tcp", "0.0.0.0:9000")
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()

    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Println("accept error:", err)
            continue
        }
        go func(c net.Conn) {
            defer c.Close()
            c.Write([]byte("admin status: OK\n"))
        }(conn)
    }
}

func main() {
    startAdminServer()
}

변경 후

go
package main

import (
    "log"
    "net"
    "os"
)

// 내부 관리용 TCP 서버 - 로컬 또는 내부망에만 bind
func startAdminServer() {
    // 예: 환경 변수로 주소를 설정하되, 기본값은 로컬호스트로 제한
    addr := os.Getenv("ADMIN_BIND_ADDR")
    if addr == "" {
        // 준수: 127.0.0.1 로만 bind -> 같은 서버 내에서만 접속 가능
        addr = "127.0.0.1:9000"
    }

    listener, err := net.Listen("tcp", addr)
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()

    log.Printf("admin server listening on %s", addr)

    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Println("accept error:", err)
            continue
        }
        go func(c net.Conn) {
            defer c.Close()
            c.Write([]byte("admin status: OK\n"))
        }(conn)
    }
}

func main() {
    startAdminServer()
}

설명:

  • 변경 전: 0.0.0.0:9000에서 수신합니다. 외부 연결 경로가 허용되면 인증 없는 상태 응답에 접근할 수 있습니다.
  • 변경 후: 기본 주소는 127.0.0.1:9000입니다. ADMIN_BIND_ADDR를 설정하면 그 값을 그대로 사용하므로, 배포 설정을 신뢰할 수 있는 관리자가 통제하고 실제 접근 범위를 확인해야 합니다.

참조