다음을 통해 공유


안정적이고 안전한 C++ 프로그램 빌드

미국 정부 간행물 NISTIR 8397: 소프트웨어 개발자 검증을 위한 최소 표준에 대한 지침에는 모든 프로그래밍 언어로 안정적이고 안전한 소프트웨어를 빌드하는 방법에 대한 훌륭한 지침이 포함되어 있습니다.

이 문서는 NISTIR 8397과 동일한 구조를 따릅니다. 각 섹션에서는 다음과 같은 내용을 다룹니다.

  • C++ 및 기타 언어에 Microsoft 개발자 제품을 사용하여 해당 섹션의 보안 요구 사항을 충족하는 방법을 요약합니다.
  • 각 영역에서 최대한의 가치를 얻기 위한 지침을 제공합니다.

2.1 위협 모델링

요약

위협 모델링은 특히 개발 요구 사항에 맞게 크기가 조정되고 노이즈를 줄이는 방식으로 적용되는 경우 중요한 프로세스입니다.

권장 사항

위협 모델링은 동적 SDL(보안 개발 수명 주기)의 한 부분이어야 합니다. 제품 전체, 특정 기능 또는 주요 설계 또는 구현 변경에 대해 위협 모델링을 다음과 같이 사용하는 것이 좋습니다.

  • 개발자 팀과의 조기 참여와 접근 방식에 대한 적절한 조정이 가능한 견고하고 동적인 SDL을 구축합니다.
  • 대상이 지정된 방식으로 위협 모델링을 적용합니다. 모든 기능에 위협 모델링을 적용하되, 노출되거나 복잡하거나 중요한 기능부터 전술적으로 시작합니다. 대신 하향식 제품 검토의 일환으로 정기적으로 적용합니다.
  • 디자인을 변경할 기회가 있는 경우 모든 보안 요구 사항과 마찬가지로 위협 모델링을 조기에 적용합니다. 또한 위협 모델은 공격 표면 감소 또는 보안을 위한 설계와 같은 다른 프로세스에 대한 입력 역할을 합니다. 나중에 만들어지는 위협 모델은 기껏해야 퍼지 테스트 같은 보안 테스트가 필요한 영역 또는 침투 테스트를 위한 '설문 조사'에 불과합니다. 기준이 되는 위협 모델을 만든 후에는 공격 표면의 변화에 따라 계속 반복할 계획을 세웁니다.
  • 자산 인벤토리 및 규정 준수를 사용하여 제품을 구성하는 요소를 적절히 추적하고, 보안 아티팩트(위협 모델 포함)와 해당 아티팩트가 적용되는 자산을 추적합니다. 이러한 접근 방식을 사용하면 위험 평가의 자동화 수준을 높이고 변경되는 특정 구성 요소나 기능에 보안 노력을 집중할 수 있습니다.
  • Azure의 Microsoft Threat Modeling Tool은 Azure 개발을 위해 2022년에 업데이트되었습니다. 자세한 내용은 Microsoft Threat Modeling Tool 개요 - Azure를 참조하세요.

지원 요인 및 사례

위협 모델링을 올바르게 적용하고 오용/남용을 방지하려면 다음과 같은 핵심 개념을 먼저 해결해야 합니다.

개발 방식

먼저 팀의 개발 방식을 이해합니다. 매일 수십 개의 변경 내용을 프로덕션에 푸시하는 애자일 개발 워크플로를 사용하는 팀의 경우 모든 기능 변경에 대해 위협 모델 업데이트를 요구하는 것은 실용적이거나 합리적이지 않습니다. 대신 기능의 기능 요구 사항을 작성할 때부터 보안 요구 사항 설문지를 포함하는 것이 좋습니다. 설문지는 기능에 대한 구체적인 질문에 초점을 맞추어 향후 SDL의 어떤 측면을 적용할지 결정해야 합니다. 예시:

  • 이 기능으로 인해 다중 테넌트 환경에서 고객 격리를 제공하는 방식이 크게 변경되나요? 그렇다면 전체 위협 모델을 수행하는 것이 좋습니다.
  • 새 기능이 파일 업로드를 허용하나요? 그렇다면 웹 애플리케이션 보안 평가가 더 적절할 수 있습니다.
  • 이 변경 내용은 주로 기능적인 UI 변경에 불과한가요? 그렇다면 기존의 자동화된 도구 외에는 아무것도 필요하지 않을 수도 있습니다.

보안 설문 조사 결과는 어떤 SDL 기술을 어떤 개발 단위와 연결할지 알려 줍니다. 또한 개발 파트너에게 기능의 SDL 타임라인을 알리므로 적절한 시기에 공동으로 작업할 수 있습니다.

제품 재고

둘째, 평가해야 할 제품의 자산 인벤토리를 잘 관리합니다. 제품의 복잡성이 증가하고 있습니다. 다음과 같은 항목을 사용하는 연결된 디바이스에 대한 소프트웨어를 작성하는 것이 일반적입니다.

  • 센서(예: 여객 철도 및 차량),
  • 차량의 다른 구성 요소(예: CANBUS 또는 PROFIBUS)와 통신하는 버스 기반 네트워크,
  • 고객 디바이스 및 클라우드 백 엔드와의 통신을 위한 무선/셀룰러/Bluetooth,
  • 디바이스 또는 차량 관리 애플리케이션으로 다시 공급되는 클라우드의 기계 학습,
  • 기타

이러한 복잡한 제품에서는 위협 모델링이 매우 중요한 역할을 합니다. 강력한 자산 인벤토리를 보유하면 전체 제품 스택을 보며 전반적인 상황을 파악하고 새 기능이나 변경된 기능이 제품 보안에 미치는 영향을 평가해야 할 주요 위치를 파악할 수 있습니다.

세분성 및 통합

명확한 메트릭을 사용하여 규정 준수를 측정하는 시스템을 구축합니다.

  • 기능 수준 개발에 대한 규정 준수를 정기적으로 측정합니다. 일반적으로 기능 규정 준수는 더 자주, 더 세밀하게 측정해야 하며, 때로는 개발자 시스템에서 또는 코드 커밋/병합 시점에 측정해야 합니다.
  • 기능 또는 구성 요소가 사용되는 광범위한 제품에 대한 보안을 주기적으로 평가합니다. 더 광범위한 평가는 일반적으로 모듈 또는 시스템 테스트 시와 같이 더 낮은 빈도와 더 넓은 세부 단위로 수행됩니다.

스케일

보안 아티팩트와 위협 모델 검토의 출력을 캡처하고 보존하는 적절한 자산 인벤토리 시스템을 유지합니다. 명확한 인벤토리가 있으면 검토 결과의 패턴을 평가하고 제품 보안 프로그램을 정기적으로 개선하는 방법에 대해 현명한 결정을 내릴 수 있습니다.

요구 사항 단계 보안 설문지, 위협 모델링 결과, 보안 평가 결과 및 자동화된 도구의 결과를 결합해 보세요. 이를 결합하면 특정 제품의 상대적 위험에 대한 관점을 “대시보드”라는 형태로 자동화하여 보안 팀에 위협 모델링에서 최고의 가치를 얻기 위해 집중해야 할 사항을 알려 줄 수 있습니다.

2.2 자동화된 테스트

요약

자동화된 테스트는 코드의 품질과 안전을 보장하는 중요한 방법이며, 이 문서에서 언급한 다른 영역(예: 위협 모델링)을 지원하는 데 있어 중요한 요소이기도 합니다. 다른 보안 코딩 방법과 함께 사용하면 코드베이스에 도입되는 버그 및 취약성으로부터 보호하는 데 도움이 됩니다.

키 특성

테스트는 안정적이고 일관되며 격리되어야 합니다. 이러한 테스트는 가능한 한 많은 코드를 다루어야 합니다. 모든 새로운 기능과 버그 수정은 가능한 경우 코드의 장기적인 보안과 안정성을 보장하기 위해 해당 테스트를 수행해야 합니다. 자동화된 테스트를 정기적으로, 가능한 한 많은 환경에서 실행하여 모든 영역이 테스트에 포함되도록 합니다.

  • 먼저 실행해야 하는 곳은 변경을 수행하는 컴퓨터입니다. 테스트 실행은 편집에 사용 중인 IDE 내에서 또는 개발자가 변경할 때 명령줄의 스크립트로 실행하는 것이 가장 쉽습니다.
  • 다음으로 실행해야 하는 곳은 끌어오기 요청 커밋/병합 프로세스의 일부입니다.
  • 마지막으로 테스트를 실행할 곳은 CI/CD(연속 통합 및 지속적인 배포) 파이프라인의 일부 또는 릴리스 후보 빌드입니다.

테스트의 범위는 각 단계마다 증가해야 하며, 마지막 단계에서는 다른 단계에서 놓칠 수 있는 모든 것을 완벽하게 다뤄야 합니다.

지속적인 사용 및 유지 관리

테스트 안정성은 테스트 도구 모음의 효율성을 유지하는 데 있어 중요한 부분입니다. 테스트 실패를 할당하고 조사해야 하며, 잠재적인 보안 문제를 우선 순위로 지정하고 미리 정해진 기간 내에 신속하게 업데이트해야 합니다. 테스트 실패를 무시하는 것은 일반적인 관행이 되어서는 안 되며, 강력한 근거와 승인을 받아야 합니다. 테스트 도구 모음 자체의 문제로 인한 테스트 실패는 다른 실패와 동일하게 처리하여 제품 문제를 놓칠 수 있는 적용 범위의 누락을 방지해야 합니다.

테스트 종류(특히, 유닛 테스트)

자동화된 테스트에는 여러 가지 유형이 있으며, 모든 애플리케이션에 적용 가능한 것은 아니지만 좋은 테스트 도구 모음에는 여러 가지 유형이 포함되어 있습니다. 유닛 테스트와 같은 코드 기반 테스트 케이스는 가장 일반적이면서 가장 필수적인 것으로, 모든 애플리케이션에 적용 가능하며 정확성을 확보하기 위해 가능한 한 많은 코드 경로를 의도적으로 다룹니다. 이러한 테스트는 작고 빠르며 컴퓨터의 상태에 영향을 주지 않아야 전체 테스트 도구 모음을 빠르게 자주 실행할 수 있습니다. 가능하면 하드웨어 설정이 다른 여러 컴퓨터에서 테스트를 실행하여 단일 유형의 컴퓨터에서 재현할 수 없는 문제를 파악합니다.

Visual Studio

Visual Studio 테스트 탐색기는 기본적으로 가장 많이 사용되는 많은 C++ 테스트 프레임워크를 지원하며, 더 많은 프레임워크를 위한 확장 기능을 설치할 수 있는 옵션이 있습니다. 이러한 유연성은 작업 중인 코드를 다루는 테스트의 하위 집합을 실행하는 데 유용하며, 테스트 실패가 발생하면 쉽게 디버그할 수 있습니다. 또한 Visual Studio는 기존 프로젝트에 대한 새 테스트 도구 모음을 쉽게 설정할 수 있게 해 줄 뿐 아니라, 이러한 테스트를 더 쉽게 관리할 수 있도록 CodeLens와 같은 유용한 도구를 제공합니다. Visual Studio를 사용하여 C/C++ 테스트를 작성, 실행 및 관리하는 방법에 대한 자세한 내용은 C/C++용 유닛 테스트 작성 - Visual Studio(Windows)를 참조하세요.

Azure 및 GitHub CI/CD에서

정적 분석, 구성 요소 감지 등과 같이 더 심층적인 검증을 수행하고 실행하는 데 시간이 오래 걸리는 테스트는 끌어오기 요청 테스트 또는 연속 통합 테스트에 적합한 후보입니다. Azure DevOps 및 GitHub Actions를 활용하면 유효성 검사를 자동으로 실행하고 유효성 검사에 실패할 경우 코드 검사를 차단하기가 용이해집니다. 자동화된 적용은 이러한 좀 더 엄격한 검사를 실행하여 검사되는 모든 코드가 안전한지 확인하는 데 도움이 됩니다. Azure Pipelines 및 Azure DevOps 빌드 유효성 검사에 대한 설명은 다음과 같습니다.

2.3 코드 기반 또는 정적 분석

요약 정적 코드/이진 분석은 기본적으로 보안을 위해 사용하도록 설정해야 합니다. 정적 분석은 고객의 컴퓨터에서 익스플로잇이 발생할 수 있는 실행 시점이 아니라 프로그램이 빌드되는 시점에 필요한 안전 및 보안 정책에 대해 프로그램을 분석합니다. 정적 분석에서는 소스 코드 형식 또는 컴파일된 실행 파일 형식으로 프로그램을 분석할 수 있습니다.

권장 사항 Microsoft는 다음을 권장합니다.

  • 모든 C++ 프로그램을 대상으로 입력 소스 코드(컴파일 전)와 실행 가능 이진 파일(컴파일 후) 모두에 대해 정적 분석을 사용하도록 설정합니다. "사용하도록 설정"한다는 것은 개발자의 컴퓨터에서 각 빌드 중에 분석을 실행하거나 나중에 또는 체크 인 요구 사항으로 코드를 검사하는 별도의 빌드로 실행하는 것을 의미할 수 있습니다.
  • 정적 분석을 테스트의 한 형태로 CI 파이프라인에 통합합니다.
  • 정의별 정적 분석은 가양성과 함께 제공되며, 품질 피드백 루프에 해당 사실을 통합할 준비를 해야 합니다. 모든 낮은 가양성 경고를 미리 사용하도록 빠르게 설정합니다. 그런 다음 점차적으로 가양성이 높아지는 대신 중요한 버그에 플래그를 지정하는 규칙을 정기적으로 추가하면서 코드 베이스가 경고 정리를 컴파일하는 규칙 수를 점진적으로 늘리도록 사전에 주의해야 합니다(처음에는 해당 규칙에 대해 코드 베이스가 정리되기 전에).
  • 항상 지원되는 최신 버전의 Visual Studio를 사용하고, 다음 개발 단계/주기까지 지연되는 일 없이 최신 패치 릴리스를 사용 가능한 즉시 신속하게 사용하도록 엔지니어링 환경을 설정합니다.

주요 도구 다음을 인식하고 사용합니다.

참고:

  • /analyze를 활용하면컴파일 시 C++ 코드를 정적으로 분석하여 중요한 보안 및 안정성 코드 취약성을 식별할 수 있습니다. C++ 프로그램의 전체 개발 타임라인 전반에 걸쳐 사용하도록 설정해야 합니다. 기본적으로 "Microsoft 네이티브 권장" 이상을 최소 기준으로 사용하도록 설정하여 시작합니다. 그런 다음 엔지니어링 정책에서 요구하는 대로 더 많은 규칙, 특히 C++ Core Guidelines 규칙을 지정하는 방법에 대한 설명서를 참조합니다. 소스 코드 정적 분석 기능은 Visual C++ IDE와 명령줄 빌드 도구 모두에서 사용할 수 있습니다.
  • 가능한 한 /W4/WX를 사용하도록 설정하여 높은 경고 수준(W4)에서 코드를 깔끔하게 컴파일하고 경고를 수정해야 하는 오류(WX)로 처리해야 합니다. 이러한 옵션을 사용하면 컴파일러 백 엔드가 프로시저 간 분석 및 인라인을 수행한 후에만 오류가 표시되기 때문에 다른 정적 분석 도구에서 확인할 수 없는 초기화되지 않은 데이터 오류를 찾을 수 있습니다.
  • BinSkim 이진 분석을 활용하면 프로젝트에서 광범위한 보안 기능을 사용할 수 있습니다. BinSkim은 PDB 및 기타 출력을 생성하여 관리 체인을 더 쉽게 확인하고 보안 문제에 효율적으로 대응할 수 있도록 합니다. 프로그램용으로 생성되거나 프로그램에서 사용하는 모든 실행 가능 이진 파일(.sys, .dll 또는 .exe)을 분석하려면 BinSkim 도구를 실행하는 것이 좋습니다. BinSkim 사용자 가이드에는 지원되는 보안 표준 목록이 포함되어 있습니다. BinSkim 도구에서 "오류"로 보고된 모든 문제를 해결하는 것이 좋습니다. "경고"로 보고된 문제는 해결이 성능에 영향을 주거나 필요하지 않을 수 있으므로 선택적으로 평가해야 합니다.

Azure 및 GitHub CI/CD의 릴리스 CI/CD 시나리오에서 소스 코드 및 이진 정적 분석을 항상 사용하도록 설정하는 것이 좋습니다. 로컬 개발자의 컴퓨터에서 또는 적어도 모든 커밋 또는 끌어오기 요청에 대해 소스 분석을 즉시 실행하여 가능한 한 빨리 소스 버그를 파악하고 전체 비용을 최소화합니다. 이진 수준 버그는 더 느리게 도입되는 경향이 있으므로 야간 또는 주간 빌드와 같이 덜 빈번한 사전 릴리스 CI/CD 시나리오에서 이진 분석을 실행하는 것으로 충분할 수 있습니다.

2.4 하드 코드된 비밀 검토

요약

소프트웨어 내에서 비밀을 하드 코드하지 마세요. 전체 소스 코드 베이스를 검사할 수 있는 신뢰할 수 있는 도구를 사용하여 소스 코드에서 비밀을 효율적으로 찾고 제거할 수 있습니다. 비밀을 찾으면 보안 스토리지 및 비밀 사용에 대한 지침에 따라 안전한 장소로 이동합니다.

문제

"비밀"은 ID를 설정하고 리소스에 대한 액세스를 제공하는 엔터티 또는 중요한 데이터에 서명하거나 암호화하는 데 사용되는 엔터티를 의미합니다. 예를 들어 암호, 스토리지 키, 연결 문자열 및 프라이빗 키가 있습니다. 소프트웨어에서 필요할 때 쉽게 가져올 수 있도록 소프트웨어 제품에 비밀을 보관하는 것이 좋습니다. 그러나 이러한 하드 코드된 비밀은 쉽게 검색되고 서비스 및 데이터를 손상시키는 데 사용될 수 있으므로 심각하거나 치명적인 보안 인시던트를 유발할 수 있습니다.

방지

소스 코드에서 하드 코드된 비밀(일반 텍스트 또는 암호화된 Blob)은 보안 취약성에 해당합니다. 소스 코드에서 비밀을 방지하는 방법에 대한 일반적인 지침은 다음과 같습니다.

  • 소스 제어에 제출하기 전에 사전 체크 인 도구를 사용하여 코드에서 잠재적인 하드 코드된 비밀을 검색하고 파악합니다.
  • 소스 코드 또는 구성 파일에서 텍스트 자격 증명을 지우지 않습니다.
  • SharePoint, OneNote, 파일 공유 등에 일반 텍스트 자격 증명을 저장하지 않습니다. 또는 이메일, 메신저 등을 통해 공유합니다.
  • 쉽게 검색할 수 있는 암호 해독 키를 사용하여 비밀을 암호화하지 않습니다. 예를 들어 암호가 포함된 파일과 함께 PFX 파일을 저장하지 않습니다.
  • 약한 암호 해독으로 비밀을 암호화하지 않습니다. 예를 들어 약하거나 일반적인 암호로 PFX 파일을 암호화하지 않습니다.
  • 소스 코드에 암호화된 자격 증명을 배치하지 마세요. 대신 소스에서 자리 표시자를 사용하고 배포 시스템이 승인된 저장소의 비밀로 바꾸도록 합니다.
  • 프로덕션 배포에서와 마찬가지로 테스트, 스테이징 등과 같은 환경의 비밀에 동일한 원칙을 적용합니다. 공격자는 관리가 잘 되지 않는 비프로덕션 시스템을 표적으로 삼아 프로덕션 시스템으로 전환하는 데 사용하는 경우가 많습니다.
  • 배포 간에 비밀을 공유하지 않습니다(예: 테스트, 스테이징, 프로덕션).

하드 코드된 비밀과 직접적인 관련은 없지만 테스트, 개발 및 프로덕션에 대한 비밀을 보호하는 것도 잊지 않습니다.

  • 비밀이 노출되었을 가능성이 있을 때마다 주기적으로 비밀을 교체하세요. 비밀을 교체/재배치할 수 있는 능력이 입증되었다는 것은 안전한 시스템이라는 증거입니다. 특히, 이 기능이 없다는 것은 취약점이 있다는 더욱 강력한 증거입니다.
  • "내 테스트 자격 증명은 위험을 초래하지 않는다"는 일반적인 개발자의 논리에 굴복하지 마세요. 실제로는 거의 항상 위험을 초래합니다.
  • 비밀 관리 오류를 완전히 피할 수 있는 좋은 엔지니어링 솔루션으로 RBAC/신원 중심 솔루션을 우선적으로 사용하면서 비밀(예: 암호, 무기명 키)에서 완전히 벗어나는 것을 고려하세요.

감지

제품의 레거시 구성 요소에는 소스 코드에 숨겨진 하드 코드된 비밀이 포함될 수 있습니다. 경우에 따라 개발자의 데스크톱 컴퓨터의 비밀이 원격 분기에 들어와 릴리스 분기에 병합되어 의도치 않게 비밀이 유출될 수 있습니다. 소스 코드에 숨어 있을 수 있는 비밀을 발견하려면 코드에서 하드 코드된 비밀을 스캔할 수 있는 도구를 사용하면 됩니다.

수정

소스 코드에서 자격 증명이 발견되면 노출된 키를 무효화하고 노출에 따라 위험 분석을 수행해야 합니다. 시스템을 계속 실행해야 하는 경우에도 다음 단계를 사용하여 비밀 관리자가 수정하도록 설정할 수 있습니다.

  1. 수정을 통해 관리 ID로 전환할 수 있거나 AKV(Azure Key Vault)와 같은 비밀 관리자를 삭제해야 하는 경우 먼저 이 작업을 수행합니다. 그런 다음 업데이트된 ID 또는 키를 사용하여 다시 배포합니다.
  2. 노출된 비밀을 무효화합니다.
  3. 손상으로 인한 잠재적 손상에 대한 감사/위험 평가를 수행합니다.

클라우드 앱 및 서비스에서 사용하는 암호화 키 및 기타 비밀을 보호하려면 적절한 액세스 정책으로 Azure Key Vault를 사용합니다.

노출이 특정 고객 데이터/PII를 손상시키는 경우 다른 규정 준수/보고 요구 사항이 필요할 수도 있습니다.

소스 코드에서 현재 무효화된 비밀을 제거하고 소스 코드에서 직접 비밀을 노출하지 않는 대체 방식으로 바꿉니다. Azure AD와 같은 도구를 사용하여 가능한 경우 비밀을 제거할 기회를 찾습니다. Azure Active Directory를 통해 관리 ID를 활용하도록 인증 방법을 업데이트할 수 있습니다. 승인된 저장소만 사용하여 AKV(Azure Key Vault)와 같은 비밀을 저장하고 관리합니다. 자세한 내용은 다음을 참조하세요.

AzDO(Azure DevOps)

AzDO 사용자는 GHAzDO(Azure DevOps용 GitHub Advanced Security)를 통해 코드를 검사할 수 있습니다. 또한 GHAzDO를 사용하면 리포지토리에서 푸시 보호를 사용하도록 설정하여 비밀 노출을 방지할 수 있으며, 유출되기 전에 잠재적 노출을 파악할 수 있습니다. Azure DevOps의 코드에서 하드 코드된 비밀을 검색하는 방법에 대한 자세한 내용은 다음 각 링크에서 Azure DevOps용 Github Advanced Security에 대한 비밀 검사를 참조하세요.

GitHub에서

비밀 검사는 GitHub.com에서 다음과 같은 두 가지 형식으로 제공됩니다.

  • 파트너에 대한 비밀 검사 경고. 모든 퍼블릭 리포지토리에서 자동으로 실행됩니다. 비밀 검사 파트너가 제공한 패턴과 일치하는 모든 문자열은 관련 파트너에게 직접 보고됩니다.
  • 사용자에 대한 비밀 검사 경고. GitHub Enterprise Cloud를 사용하고 GitHub Advanced Security에 대한 라이선스가 있는 조직에서 소유한 리포지토리에 대한 추가 검사를 사용하도록 설정하고 구성할 수 있습니다. 이러한 도구는 프라이빗 및 내부 리포지토리도 지원합니다.

GitHub는 특정한 요구에 맞게 구성할 수 있는 파트너와 사용자를 위한 알려진 비밀 패턴을 제공합니다. 자세한 내용은 다음을 참조하세요.

참고 항목

Azure DevOps용 GitHub Advanced Security는 GitHub 사용자가 이미 사용할 수 있는 동일한 비밀 검사, 종속성 검사 및 CodeQL 코드 검사 솔루션을 제공하고 기본적으로 Azure DevOps에 통합하여 Azure Repos와 Azure Pipelines를 보호합니다.

추가 리소스

2.5 언어 및 OS 제공 검사 및 보호를 사용하여 실행

요약

이진 강화는 컴파일 시간 보안 컨트롤을 적용하여 수행됩니다. 여기에는 다음과 같은 완화 방법이 포함됩니다.

  • 코드에서 악용 가능한 취약성 방지,
  • 악용 시 보안 방어 수단을 트리거하는 런타임 검색을 사용하도록 설정,
  • 데이터 생성 및 보관을 사용하여 보안 인시던트로 인한 피해 제한.

이진 소비자는 강화의 모든 이점을 얻으려면 Windows 보안 기능을 옵트인해야 합니다.

Microsoft는 개발자가 더 안전하고 보안 수준이 높은 코드를 작성하고 제공할 수 있도록 C++ 프로젝트와 관련된 일련의 기능을 제공합니다. 또한 C++ 개발자는 실행 코드를 생성하는 언어에 공통으로 적용되는 보안 표준을 준수해야 합니다. Microsoft는 이 섹션에 설명된 많은 보호 사항을 적용하는 데 도움이 되는 공용 OSS 이진 검사기인 BinSkim을 유지 관리합니다. BinSkim에 대한 자세한 내용은 Binskim 사용자 가이드 | GitHub를 참조하세요.

이진 수준 컨트롤은 엔지니어링 프로세스에서 적용되는 위치에 따라 다릅니다. 컴파일러와 링커 옵션은 컴파일 시간, 런타임 오버헤드가 있는 코드 생성 변경, OS 보호와의 호환성을 위해 코드 생성 변경을 엄격하게 구분해야 합니다.

개발자 설정은 가능한 한 많은 정적 분석을 사용하도록 설정하고, 프라이빗 데이터의 생성을 사용하도록 설정하여 디버깅을 가속화하는 등의 설정을 우선적으로 사용해야 합니다. 릴리스 빌드는 보안, 성능 및 기타 코드 생성 문제의 적절한 조합으로 조정되어야 합니다. 퍼블릭 및 프라이빗에서 사용하는 빌드 데이터(예: 퍼블릭 및 프라이빗 기호)를 적절히 생성하고 관리하도록 릴리스 프로세스를 구성해야 합니다.

최신 상태 유지: 항상 최신 컴파일러 및 도구 사용

최신 언어 지원, 정적 분석, 코드 생성 및 보안 컨트롤의 이점을 활용하려면 최신 도구 집합을 사용하여 모든 코드를 컴파일합니다. 컴파일러는 생성된 모든 구성 요소에 영향을 주므로 도구 업데이트에서 회귀 가능성이 상대적으로 높습니다. 오래된 컴파일러를 사용하면 팀이 컴파일러를 업그레이드할 시간이 충분하지 않을 수 있으므로 보안 인시던트에 대응하는 동안 정정 작업에 특히 위험합니다. 따라서 팀이 정기적으로 컴파일러 업데이트를 새로 고치고 테스트하는 기능을 개발하는 것이 좋습니다.

보안 개발 방법, 언어 버전, 프레임워크/API 사용

코드는 다음을 포함하여 C++의 안전성과 단순성을 촉진해 위험을 최소화하는 개발 방법론, 언어 버전, 프레임워크, API 등을 활용해야 합니다.

  • 모범 사례를 따르고 일반적인 문제를 방지하는 안전하고 일관된 최신 C++ 코드를 작성하는 지침은 C++ Core Guidelines GSL(지침 지원 라이브러리)을 참조하세요.
  • C++ Core Guidelines에서 사용하도록 제안하는 함수 및 형식은 Microsoft GSL 구현을 참조하세요.
  • 리소스로부터 안전한 C++ 컨테이너, CRT(C 런타임 라이브러리) 메모리 오버플로 보호: 리소스로부터 안전한 std::vectorstd::string를 우선적으로 사용합니다. C 데이터를 사용해야 하는 경우 버퍼 오용 및 정의되지 않은 언어 동작으로 인한 메모리 손상을 방지하도록 설계된 보안 버전의 CRT 함수를 사용합니다.
  • SafeInt 라이브러리는 수학 및 비교 연산의 정수 오버플로로부터 보호합니다.

보안 종속성 사용

이진 파일은 안전하지 않은 라이브러리 및 종속성에 연결해서는 안 됩니다. 개발 팀은 모든 외부 종속성을 추적하고 이러한 취약성이 발생할 때 더 안전한 버전으로 업데이트하여 이러한 구성 요소의 CVE/식별된 보안 취약성을 해결해야 합니다.

보안 대응의 코드 출처 보장 및 효율성 극대화

컴파일을 사용하면 강력한 코드 출처 보장을 통해 백도어 및 기타 악성 코드의 도입을 감지하고 방지할 수 있습니다. 그 결과 생성되는 데이터는 디버깅 및 조사에 중요한 역할을 하며, 손상된 경우 효율적인 보안 대응을 위해 모든 소프트웨어 릴리스에 대해 보관해야 합니다. 다음 컴파일러 스위치는 보안 응답에 중요한 정보를 생성합니다.

  • Visual C++의 /ZH:SHA_SHA256 - 암호화된 보안 알고리즘을 사용하여 모든 PDB 원본 파일 해시를 생성합니다.
  • Visual C++의 /Zi, /ZI(디버그 정보 형식) - 크래시 데이터 및 기타 공용 사용 시나리오를 수집하기 위해 제거된 기호를 게시하는 것 외에도 빌드에서 릴리스된 모든 이진 파일에 대해 프라이빗 PDB를 생성하고 보관해야 합니다. 이진 분석 도구에는 컴파일 시간에 많은 보안 완화가 사용되었는지 여부를 확인하기 위해 전체 기호가 필요합니다. 프라이빗 기호는 보안 대응에 있어 중요한 역할을 하며 익스플로잇이 발생했을 때 엔지니어가 피해를 평가하고 제한하기 위해 경쟁할 때 디버깅 및 조사 비용을 절감할 수 있습니다.
  • Visual C++ 링커의 /SOURCELINK - PDB의 Sourcelink 파일 포함: 소스 링크는 언어 및 소스 제어 독립적인 시스템으로 이진 파일에 대한 소스 디버깅을 제공합니다. 소스 디버깅은 시험판 보안 유효성 검사 및 릴리스 후 인시던트 응답의 범위를 크게 향상합니다.

코드 작성 시 문제를 방지하도록 컴파일러 오류 사용

예를 들어 컴파일 시 보안 관련 컴파일러 검사를 중단 오류로 사용하도록 설정해야 합니다.

이진 파일을 OS 런타임 보안 완화와 호환되는 것으로 표시

컴파일러 및 링커 설정은 다음을 포함하여 악성 코드 실행을 감지하고 완화하는 코드 생성 기능을 옵트인해야 합니다.

중요한 정보 공개 방지

컴파일러 설정은 중요한 정보 검색 방지를 옵트인해야 합니다. 최근 몇 년 동안 연구자들은 투기적 실행과 같은 하드웨어 기능으로 인해 의도하지 않은 정보 유출이 발생한다는 사실을 밝혀냈습니다.

소프트웨어 수준에서 예기치 않게 유출된 경우 기밀 데이터가 공격자에게 전송될 수 있습니다. 버퍼 및 기타 버퍼 오용을 초기화하지 못하면 신뢰할 수 있는 API를 호출하는 공격자에게 개인 기밀 데이터가 누출될 수 있습니다. 이러한 종류의 문제는 앞서 설명한 대로 추가 정적 분석을 사용하도록 설정하고 보안 리소스 컨테이너를 활용하여 가장 효과적으로 처리할 수 있습니다.

  • /Qspectre - 투기적 실행 측면 채널 공격 완화 - 투기적 실행에 의해 생성된 중요한 데이터의 공개를 방지하는 데 도움이 되는 장벽 지침을 삽입합니다. 중요한 데이터를 메모리에 저장하고 신뢰 경계를 넘어 작동하는 코드에 대해 이러한 완화를 사용하도록 설정해야 합니다. 성능에 중요한 블록이나 루프에 런타임 검사를 도입할 수 있으므로 Spectre 완화 기능을 사용할 때는 항상 적절한 벤치마크에 대한 성능 영향을 측정하는 것이 좋습니다. 이러한 코드 경로는 spectre(nomitigation) declspec 한정자를 통해 완화를 사용하지 않도록 설정할 수 있습니다. 사용하도록 설정하는 /Qspectre 프로젝트는 Microsoft 런타임 라이브러리를 포함하여 이러한 완화를 사용하여 컴파일된 라이브러리에도 연결되어야 합니다.

2.6 블랙박스 테스트 사례

요약

블랙박스 테스트는 테스트 대상 구성 요소의 내부 작동을 파악하는 것에 의존하지 않습니다. 블랙박스 테스트는 모든 계층 또는 수준에서 제품 내 기능의 엔드투엔드 기능을 테스트하도록 설계되었습니다. 블랙박스 테스트는 기능 테스트, UI 테스트, 성능 테스트 및 통합 테스트일 수 있습니다. 블랙박스 테스트는 일반적인 안정성과 기능적 정확성을 측정하고 제품이 예상대로 작동하는지 확인하는 데 유용합니다.

다른 섹션과의 관계

이러한 유형의 요구 사항 기반 테스트는 위협 모델에서 만든 가정의 유효성을 검사하고 해당 섹션에서 설명한 잠재적 위협을 다루는 데 유용합니다. 이러한 테스트는 제품의 개별 구성 요소, 특히 위협 모델에 설명된 대로 신뢰 경계를 넘어 있는 구성 요소 간의 통합을 테스트하는 데 유용합니다. 블랙박스 테스트 사례는 사용자 입력 유효성 검사를 위해 모든 종류의 에지 사례를 테스트하는 데에도 유용합니다. 알려진 에지 사례와 오류 사례를 테스트하는 것은 모두 유용합니다. 퍼지 테스트는 덜 명백한 사례를 테스트하는 데도 유용합니다.

자동화 및 회귀

이러한 테스트를 정기적으로 실행하고 결과를 이전 실행과 비교하여 호환성이 손상되는 변경 또는 성능 회귀를 파악합니다. 또한 다양한 컴퓨터 및 설치 환경에서 이러한 테스트를 실행하면 다른 아키텍처 또는 설정 변경으로 인해 발생할 수 있는 문제를 해결하는 데 도움이 될 수 있습니다.

크래시 덤프

이러한 테스트는 충돌, 중단, 교착 상태 등 다양한 시나리오를 테스트하여 안정성과 관련된 문제를 찾는 데 도움이 됩니다. 테스트 실패의 일부로 크래시 덤프를 수집하여 덤프를 Visual Studio로 직접 가져와 코드의 어떤 부분이 이러한 문제를 발생시키는지 추가로 조사할 수 있습니다. Visual Studio 내에서 기능 테스트를 실행하는 경우 블랙박스 내에서 테스트가 실패하는 위치를 정확하게 확인하여 오류를 쉽게 복제하고 디버그할 수 있으며, 신속하게 수정 사항을 테스트할 수 있습니다.

테스트 디버깅을 시작하려면 테스트 탐색기를 사용하여 유닛 테스트 디버그 - Visual Studio(Windows)를 참조하세요.

Azure에서

또한 Azure DevOps는 테스트 계획을 사용하여 이러한 테스트를 관리하고 유효성을 검사하는 데 도움이 될 수 있습니다. 이러한 테스트를 사용하여 수동 유효성 검사를 통해 승인을 보장하고 제품 요구 사항과 관련된 자동화된 테스트를 실행할 수 있습니다. Azure Test Plans 및 이를 사용하여 자동화된 테스트를 실행하는 방법에 대한 자세한 내용은 다음을 참조하세요.

2.7 코드 기반 테스트 사례

요약

코드 기반 테스트 사례는 제품의 보안 및 안정성을 유지하는 데 필수적인 부분입니다. 이러한 테스트는 작고 빠르며 병렬로 실행할 수 있도록 서로에 영향을 주지 않아야 합니다. 코드 기반 테스트는 개발자가 개발 주기를 늦출 염려 없이 코드를 변경할 때마다 개발 컴퓨터에서 로컬로 쉽게 실행할 수 있습니다.

형식 및 다른 섹션과의 관계

코드 기반 테스트 사례의 일반적인 유형은 다음과 같습니다.

  • 유닛 테스트,
  • 여러 입력 형식이 포함된 함수를 다루는 매개 변수가 있는 테스트,
  • 각 테스트 구성 요소를 별도로 유지하기 위한 구성 요소 테스트,
  • 해당 서비스 자체를 포함하도록 테스트 범위를 확장하지 않고 다른 서비스와 통신하는 코드 부분의 유효성을 검사하는 모의 테스트.

이러한 테스트는 작성된 내부 코드를 기반으로 하는 반면 블랙박스 테스트는 제품의 외부 기능 요구 사항을 기반으로 합니다.

목표

이러한 테스트를 통해 코드에 대한 높은 수준의 테스트 적용 범위를 달성하는 것이 목표입니다. 이 적용 범위와 간격이 있는 위치를 적극적으로 추적해야 합니다. 더 많은 코드 경로를 실행하는 테스트를 추가할수록 코드의 보안과 안정성에 대한 전반적인 신뢰도가 높아집니다.

Visual Studio

Visual Studio의 테스트 탐색기 도구를 사용하면 이러한 테스트를 자주 쉽게 실행하고 통과/실패율 및 실패 위치에 대한 피드백을 빠르게 받을 수 있습니다. 또한 대부분의 테스트 프레임워크는 CodeLens 기능을 지원하여 테스트 자체의 위치에서 테스트 상태를 확인하므로 테스트 도구 모음을 더 쉽게 추가하고 유지 관리할 수 있습니다. 또한 테스트 탐색기를 사용하면 이러한 테스트를 쉽게 관리할 수 있으므로 테스트 그룹, 사용자 지정 테스트 재생 목록, 필터링, 정렬, 검색 등이 가능합니다.

자세한 내용은 다음을 참조하세요.

Visual Studio에는 코드 검사를 추적하기 위한 도구도 함께 제공됩니다. 이러한 도구를 사용하면 사용자가 코드에서 변경한 내용이 기존 테스트에서 처리되는지 확인하거나 새 테스트 및 테스트되지 않은 코드 경로를 다루는 새 테스트를 추가할 수 있습니다. 또한 도구는 전체 코드 품질에 대한 신뢰도를 위해 목표 수준 이상으로 유지 관리되도록 코드 검사 백분율을 표시합니다.

이러한 도구에 대한 자세한 내용은 코드 검사 테스트 - Visual Studio(Windows)를 참조하세요.

Azure에서

또한 Azure DevOps는 빌드 파이프라인 프로세스의 일부로 전체 제품에 대한 코드 검사 결과를 추적하는 데 도움이 될 수 있습니다. 자세한 내용은 코드 검사 검토 - Azure Pipelines를 참조하세요.

2.8 기록 테스트 사례

요약

회귀 테스트 사례라고도 하는 기록 테스트 사례는 오래된 문제가 다시 발생하는 것을 방지하고 제품의 전반적인 테스트 범위를 늘립니다. 버그가 수정되면 프로젝트에 해당 테스트 사례도 추가되는지 확인해야 합니다. 시간이 지남에 따라 수정이 이루어지면 테스트 도구 모음의 전반적인 견고성이 계속 향상되어 안정성과 보안을 더욱 확실하게 보장할 수 있습니다.

키 품질 및 다른 섹션과의 관계

이러한 테스트는 버그 회귀를 테스트하기 때문에 코드 기반 테스트 사례와 함께 실행하여 제품의 전반적인 코드 검사에 기여할 수 있도록 빠르고 쉽게 실행할 수 있어야 합니다. 이와 함께 고객의 실제 예제를 사용하여 새로운 테스트 사례에 영감을 주는 것은 테스트의 적용 범위와 품질을 개선하는 좋은 방법입니다.

Visual Studio

Visual Studio를 사용하면 버그를 수정하기 위해 변경하는 동안 테스트를 쉽게 추가하고 테스트와 코드 검사를 빠르게 실행하여 모든 새로운 사례를 고려할 수 있습니다. 테스트를 작성하는 코드에서 문제 추적 시스템의 버그 ID를 참조하는 것은 회귀 테스트를 해당 문제에 연결하는 좋은 방법입니다. Visual Studio와 함께 Azure Boards 및 테스트 계획을 사용하여 다음을 수행하는 것이 좋습니다.

  • 테스트, 테스트 사례 및 문제 연결
  • 문제 및 해당 테스트의 모든 측면 추적

자세한 내용은 다음을 참조하세요.

결국 이러한 테스트를 코드 섹션을 포함해야 하는 유닛 테스트 영역에 통합하면 테스트 도구 모음을 정돈된 상태로 관리하기 쉽게 유지할 수 있습니다. 테스트 탐색기의 테스트 그룹을 사용하여 함께 속한 테스트를 효과적으로 추적할 수 있습니다. 자세한 내용은 테스트 탐색기를 사용하여 유닛 테스트 실행 - Visual Studio(Windows)를 참조하세요.

2.9 퍼지 테스트

요약 퍼지 테스트는 프로그램에 대한 입력으로 유효하지 않거나 예기치 않거나 임의의 데이터를 제공하는 자동화된 소프트웨어 테스트 기술입니다. 이를 통해 크래시, 실패한 기본 제공 또는 컴파일러 삽입 코드 어설션 및 잠재적인 메모리 누수와 같은 예외가 있는지 프로그램을 모니터링합니다.

지침

공격자가 제어할 수 있는 신뢰할 수 없는 입력을 처리할 수 있는 모든 소프트웨어에서 퍼지 테스트를 사용합니다. 새 애플리케이션 및 관련 테스트 도구 모음을 빌드하는 경우 가능한 한 빨리 주요 모듈에 대한 퍼지 테스트를 포함합니다. 소프트웨어 조각에서 처음으로 퍼지 테스트를 실행하면 이전에 알려지지 않은 실제 취약성이 거의 항상 발견됩니다. 퍼지 테스트를 시작하면 중단해서는 안 됩니다.

다른 섹션과의 관계

퍼지 테스트에서 오류를 보고하는 경우 버그를 보여 주는 재현 가능한 테스트 사례를 항상 기본적으로 제공합니다. 이 테스트 사례를 재현하고 해결한 다음 기록 테스트 사례에 추가할 수 있습니다.

ASan(Address Sanitizer) 및 퍼지 테스트와 같은 삭제기를 모두 사용하는 경우:

  • 먼저 삭제기가 사용하도록 설정된 일반 테스트를 실행하여 문제가 있는지 확인하고, 코드가 삭제기로 깨끗해지면 퍼지 테스트를 시작합니다.
  • C 또는 C++의 경우 ASan을 사용하도록 설정하는 런타임 어설션 및 메타데이터 주입을 자동화하는 컴파일러가 있습니다. 그 결과 ASan용으로 컴파일되어 생성된 이진 파일은 가양성이 없는 15개 이상의 메모리 안전 오류 범주를 정확하게 진단할 수 있는 런타임 라이브러리와 연결됩니다. 원본이 있는 상황의 C 또는 C++인 경우, 먼저 ASan을 사용하도록 설정해야 하는 LibFuzzer를 사용합니다.
  • Java, C#, Python, Rust 등으로 작성된 라이브러리의 경우 AFL++ 프레임워크를 사용합니다.

키 품질

  • 퍼지 테스트는 정적 프로그램 분석, 철저한 기능 테스트 및 수동 코드 검사로 인해 종종 누락된 취약성을 찾습니다.
  • 퍼지 테스트는 소프트웨어에서 보안 및 안정성 버그를 찾는 효과적인 방법이므로 Microsoft 보안 개발 수명 주기는 모든 제품의 신뢰할 수 없는 모든 인터페이스에서 퍼지 테스트가 필요합니다(위협 모델링 참조).
  • 신뢰할 수 없는 입력을 처리할 수 있는 소프트웨어에는 항상 퍼지 테스트를 사용합니다.
  • 퍼지 테스트는 큰 데이터 파서를 사용하는 독립 실행형 애플리케이션에 효과적입니다.

Azure 및 GitHub CI/CD

LibFuzzer 또는 AFL++를 사용하는 실행 파일을 지속적으로 만들 수 있도록 빌드를 수정합니다. OSS-Fuzz 또는 OneFuzz와 같은 서비스에서 퍼지 테스트에 필요한 별도의 컴퓨팅 리소스를 추가할 수 있습니다.

2.10 웹 애플리케이션 검사

요약

Windows에서 Microsoft Visual C++ 범위 내에서 다음과 같이 하는 것이 좋습니다.

  • 웹 애플리케이션에는 TypeScript, JavaScript 및 ASP.NET을 우선적으로 사용합니다.
  • 웹 확장을 C++로 작성하지 않습니다. Microsoft는 ActiveX를 더 이상 사용하지 않습니다.
  • 코드가 Emscripten/WASM으로 컴파일되면 더 이상 C++가 아니며 다른 도구가 적용됩니다.
  • Microsoft는 상태 저장 REST API 퍼저인 RESTler를 제공합니다.

개요 및 키 품질

웹 애플리케이션 스캐너는 웹 페이지를 탐색하여 웹 애플리케이션을 탐색하고 보안 취약성을 검사합니다. 이 크롤링에는 악의적인 입력의 자동 생성 및 애플리케이션 응답 평가가 포함됩니다. 중요한 것은 웹 애플리케이션 검사가 반드시 다음을 포함/지원해야 한다는 것입니다.

  • 신규 및 알 수 없는 앱을 포함하여 네트워크의 모든 웹앱을 카탈로그로 만들고 소수의 앱에서 수천 개의 앱으로 확장합니다.
  • 모바일 디바이스에서 사용하는 소프트웨어 버전, SOAP 및 REST API 서비스 및 API에 대한 심층 검사
  • DevOps 환경에서 애플리케이션 개발 및 배포에 보안 기본 형식을 삽입합니다. 이러한 기본 형식은 크롤러에서 작동합니다.
  • 맬웨어 검색.

2.11 포함된 소프트웨어 구성 요소 확인

요약

C++ 코드를 다른 프로그래밍 언어로 작성된 코드와 동일하게 처리하고 회사에서 채택한 SCA(소프트웨어 컴퍼지션 분석) 및 OA(원본 분석) 도구를 C++ 코드에 적용합니다. 워크플로 및 보안 검사는 CI/CD(연속 통합 및 지속적인 업데이트) 시스템의 일부로 설계되어야 합니다.

업스트림 방어

업스트림 종속성에 대한 공격 위험을 완화하려면 SCA 및 OA 도구가 실행되는 엔터프라이즈 제어 자산에 타사 원본/구성 요소를 저장해야 합니다.

  • 도구는 다음과 같은 취약성이 식별되면(공용 데이터베이스 포함) 이를 검사하고 경고해야 합니다. 홈 | CVE
  • 애플리케이션/리포지토리에 포함된 모든 소프트웨어 구성 요소에 대해 정적 분석을 실행하여 취약한 코드 패턴을 식별합니다.

종속성 방어

종속성에 대한 감사를 수행하고 유지 관리하여 이러한 모든 항목이 SCA 및 OA 도구에서 처리되고 적용되는지 확인합니다.

  • 구성 요소는 정기적으로 감사되고 확인된 최신 버전으로 업데이트되어야 합니다.
  • 패키지 피드 종속성
  • SCA/OA 도구는 단일 피드에서 제공되는 모든 패키지 종속성을 다루고 감사합니다.

SBOM

다음과 같은 모든 종속성을 나열하는 제품으로 SBOM(소프트웨어 제품 구성 정보)을 생성합니다.

  • origin(예: URL(Uniform Resource Locator))
  • version
  • 일관성(예: SHA-256 원본 해시) 및 결정적 빌드와 같은 일관성의 유효성을 검사하기 위한 기타 수단.
  • 소프트웨어 종속성 또는 OSS(오픈 소스 소프트웨어)를 포함한 빌드의 일부로 생성된 SBOM 파일을 요구하고 감사합니다.
  • Microsoft는 현재 표준화 중이며 SPDX(Software Package Data Exchange) 버전 2.2 이상 | Linux Foundation을 SBOM 문서 형식으로 권장합니다.
  • 빌드 결정론을 사용하여 비트 단위로 동일한 이진 파일을 독립적으로 생성하고 무결성에 대한 독립적인 검증을 제공할 수 있습니다.
    • 재현 가능성의 자사 또는 타사 증명
    • 신뢰할 수 있는 인증서 원본을 통한 이진 서명과 같은 다른 기술도 이진 무결성에 대한 몇 가지 보증을 제공할 수 있습니다.

추가 리소스

Microsoft 솔루션에는 다음과 같은 지침 및 제품이 포함됩니다.