View in English

  • Apple Developer
    • 시작하기

    시작하기 탐색

    • 개요
    • 알아보기
    • Apple Developer Program

    알림 받기

    • 최신 뉴스
    • Hello Developer
    • 플랫폼

    플랫폼 탐색

    • Apple 플랫폼
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    피처링

    • 디자인
    • 배포
    • 게임
    • 액세서리
    • 웹
    • 홈
    • CarPlay
    • 기술

    기술 탐색

    • 개요
    • Xcode
    • Swift
    • SwiftUI

    피처링

    • 손쉬운 사용
    • AI 및 머신러닝
    • 앱 인텐트
    • Apple Intelligence
    • 게임
    • 보안
    • Xcode Cloud
    • 커뮤니티

    커뮤니티 탐색

    • 개요
    • Apple과의 만남 이벤트
    • 커뮤니티 이벤트
    • 개발자 포럼
    • 오픈 소스

    피처링

    • WWDC
    • Swift Student Challenge
    • 개발자 이야기
    • App Store 어워드
    • Apple 디자인 어워드
    • 문서

    문서 탐색

    • 문서 라이브러리
    • 기술 개요
    • 샘플 코드
    • 휴먼 인터페이스 가이드라인
    • 비디오

    릴리즈 노트

    • 피처링 업데이트
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • 다운로드

    다운로드 탐색

    • 모든 다운로드
    • 운영 체제
    • 애플리케이션
    • 디자인 리소스

    피처링

    • Xcode
    • TestFlight
    • 서체
    • SF Symbols
    • Icon Composer
    • 지원

    지원 탐색

    • 개요
    • 도움말
    • 개발자 포럼
    • 피드백 지원
    • 문의하기

    피처링

    • 계정 도움말
    • 앱 심사 지침
    • App Store Connect 도움말
    • 새로 추가될 요구 사항
    • 계약 및 지침
    • 시스템 상태
  • 빠른 링크

    • 이벤트
    • 뉴스
    • 포럼
    • 샘플 코드
    • 비디오
 

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 전체 비디오
  • 소개
  • 소개
  • 자막 전문
  • 메모리 무결성 강화 및 포인터 인증 도입하기

    메모리 무결성 강화와 포인터 인증이 어떻게 함께 작동하여 앱을 메모리 손상으로부터 보호하는지 알아보세요. 유형 인식 보안 할당자가 어떻게 Memory Tagging Extension을 활용하여 악용을 방지하는지 살펴보고, 할당자 래퍼와 오브젝트 풀을 조정하여 하드웨어 보호를 유지하는 방법을 알아보세요. 또한 Xcode에서 arm64e와 함께 포인터 인증을 활성화하여 제어 흐름 무결성을 유지하는 방법을 살펴보세요.

    이 세션은 원래 Apple과의 만남 이벤트 ‘앱의 보안 강화하기: 보안 강화를 위한 필수 전략'의 일부로 진행되었습니다. 전체 비디오를 시청하여 더 많은 인사이트와 관련 세션을 확인하세요.

    리소스

      • HD 비디오
      • SD 비디오
  • 비디오 검색…

    오늘 첫 번째 심층 분석에 오신 것을 환영합니다. 제 이름은 헨리 카펠입니다. 저는 보안 엔지니어이고, 잠시 후 동료들이 무대에 합류할 예정입니다. 엘라와 올리버 헌트. 저희의 가장 흥미로운 보안 기능 두 가지를 살펴보겠습니다. 메모리 무결성, 강제 적용 및 포인터 인증. 이번 강연은 고급 과정이 될 것입니다. 메모리 할당자, 포인터 및 보안 모델에 대해 이야기해 보겠습니다. 먼저 여러분께 길이에 대한 이해를 돕겠습니다. 어떤 메모리 무결성 강제 조치가 애플리케이션을 보호하는 데 사용될까요? 그럼 필리포가 방법을 알려줄 거예요. 특정 사용자 지정 메모리 관리 구현 문제를 해결하기 위해 이는 보안 적용을 방해하거나 아예 작동하지 않을 수 있습니다. 청렴성 확보를 잊지 마세요. 그럼 화제를 바꿔보죠. 그리고 올리버가 무대에 올라 우리 안보 전략의 또 다른 측면을 다룰 예정입니다. 포인터 인증을 사용하는 방법 공격자가 임의 코드 실행을 달성하는 것을 방지하기 위해서입니다.

    하지만 소개는 이쯤에서 마치죠. 먼저 메모리 무결성 강제 적용부터 시작해 보겠습니다. 앞서 언급했듯이 대부분의 보안 문제는 메모리와 관련된 문제입니다. 메모리 무결성 강제 적용과 관련된 손상 버그. 우리의 임무는 DDS를 광범위하게 활용 가능하게 만드는 것입니다. 이건 엄청난 변화입니다. 이제 그들은 당신의 애플리케이션에 보안 문제를 일으키지 않을 겁니다.

    메모리 무결성 강제 기능을 우리가 사용하는 방식 그대로 공개합니다. 우리 자신에게는 문제가 되지 않습니다. 여기서는 그를 막지 못합니다. 그 이유는 우리가 자사 앱이 강력하게 지지하는 앱이라고 믿기 때문입니다. 당사 앱과 타사 앱 모두 사용자 안전을 보호하는 데 똑같이 중요합니다. 그래서 저희는 시작하는 데 도움이 될 만한 훌륭한 자료들을 모아봤습니다. 메모리 무결성 강제 적용 기능이 포함되어 있습니다. 모든 보안 측면을 설명하는 블로그 게시물을 공개할 예정입니다. 메모리 무결성 강제 적용이 작동하는 방식입니다.

    단계별로 방법을 알려주는 기술 강연이 있습니다. 애플리케이션에 메모리 무결성 강제 적용 기능을 통합하려면.

    그리고 우리는 또한 훌륭한 마무리를 몇 가지 준비했습니다. 같은 주제에 대한 문서 작성을 마무리하기 위해서입니다. 메모할 필요가 없습니다. 추후 이메일을 통해 관련 링크들을 보내드리겠습니다. 나중에 시청하시는 경우에도 해당 영상은 온라인 세션에 첨부됩니다. 그러니 꼭 한번 확인해 보세요. 그들은 훌륭해요. 오늘 자세한 소개는 생략하겠습니다. 메모리 무결성 강제 적용을 위해서입니다. 그래서 저는 저희 애플리케이션에만 집중하겠습니다. 보안 핵심 기능과 상호 작용합니다. 메모리를 활용하는 타입 인식 보안 메모리 할당자 태그 확장 기능.

    MTV는 하드웨어 기술입니다. 그리고 메모리 무결성 강화에 대한 가장 큰 투자 중 하나는, 그리고 이는 적용 과정에서 가장 눈에 띄는 영향을 미치는 요소라고 할 수 있습니다. 그럼 간단히 살펴보겠습니다. 자물쇠와 열쇠 시스템입니다. 잠금은 16바이트 단위로 메모리에 할당됩니다. 페이지 단위보다 훨씬 더 세밀한 단위입니다. 그리고 이는 동적 할당에 매우 적합합니다. 키는 포인터에 저장됩니다. 고가의 비트, 잠금 장치 및 키는 일반적으로 태그라고 불리며, 그 이름도 여기서 유래되었습니다. 메모리 태깅 소프트웨어는 태그 할당을 제어합니다. 우리는 그것을 태깅 정책이라고 부릅니다. 사진에서 노란색 버퍼 태그 7은 소프트웨어적인 결정 사항입니다. 그리고 두 개의 포인터도 마찬가지입니다. 왼쪽 하드웨어는 우리가 검사 정책이라고 부르는 것을 구현합니다. 자물쇠와 열쇠가 일치할 때만 접근을 허용합니다. 이제 포인터에 태그가 있더라도,

    이것은 소프트웨어에 큰 영향을 미치지 않습니다. 실제로 메모리 무결성 강제 적용을 활성화하는 것은 매우 간단합니다. Xcode 에서 몇 번만 클릭하면 됩니다. 상당한 도입 노력이 필요한 다른 기술들과는 달리, MIT는 대부분 수정되지 않은 소프트웨어를 기반으로 작업합니다. 물론, 뭔가 함정이 있지 않는 한, 우리가 오늘 여기에 있을 리가 없겠죠.

    애플리케이션에서 사용자 지정 메모리 관리를 구현하지 않는 한, 이 주제에 대해 몇 번 언급했는데, 그 의미를 좀 더 자세히 살펴보겠습니다. 응용 프로그램에서 찾아볼 수 있는 패턴은 세 가지입니다. 이로 인해 사용자 정의 메모리 관리가 필요하게 되었습니다. 저는 가능성이 높은 순서대로 여기서 사용하겠습니다.

    첫 번째는 할당된 래퍼입니다. 할당된 래퍼는 시스템에서 할당한 API를 감싸는 인터페이스입니다. 그리고 보통 휴대성 때문에 그렇게 합니다. 또는 메모리 작업과 관련된 추가적인 로직을 구현해야 합니다.

    이것들은 단연코 가장 흔하게 발견되는 구조입니다. 그리고 잠시 후에 이야기할 다른 두 가지 경우와는 정반대로, 이해를 돕기 위해 간단한 예를 하나 들어보겠습니다. 여기서 우리는 메모리 할당이라는 함수를 정의합니다. 이는 실제로 malloc을 호출하는 것입니다.

    나머지 코드는 malloc 디렉토리를 호출합니다. 하지만 항상 이 인터페이스로 이동합니다. 이 예시를 잘 살펴보겠습니다. 필리포가 잠시 후 무대에 올라와서 그 내용을 자세히 설명할 것입니다. 두 번째 직접 메모리 관리 패턴은 풀링 및 캐싱 전략입니다. 이러한 전략들의 목표는 다음과 같습니다. 자주 사용하는 물건을 재활용하여 성능을 향상시키기 위해, 이렇게 하면 시스템 할당자와의 왕복 통신을 피할 수 있습니다. 이것들도 어느 정도 흔하지만, 할당자 래퍼만큼 흔하지는 않습니다.

    그리고 마지막으로, 다행히도 실제로 적용되는 경우는 극히 드문 것이 있습니다. 하지만 프레임워크에서는 훨씬 더 널리 사용됩니다. 이것들은 완전히 사용자 정의 가능한 메모리 할당자입니다. 이 경우에는 교체품이 바로 사용 가능합니다. 이는 시스템 기본 설정을 완전히 우회하는 것입니다.

    직관적으로, 이 세 가지 패턴은 모두 해롭습니다. 메모리 태깅 무결성 시행의 보안에 간섭하기 때문에 또는 시스템 할당자를 완전히 우회할 수도 있습니다. 그래서 예상대로 오늘의 핵심 권장 사항이 나옵니다.

    기본 시스템 할당자를 사용하십시오. 저는 이 미끄럼틀에서 잠시 머물 거예요. 래퍼나 캐시 없이 기본 시스템 할당자를 사용하십시오. 또는 사용자 정의 구현도 가능합니다. 우리는 확장성을 확보하는 데 많은 시간을 투자합니다. 대다수 사용자에게는 빠르고 편리합니다. 그리고 이는 지난 3년 동안 처음부터 새로 개발된 것입니다. 그러니까 3년 전의 실적 수치를 기준으로 한다면, 그것들을 다시 평가해 주십시오. 기분 좋은 놀라움을 경험하실 수도 있습니다. 그리고 우리는 그 내용이 청렴성 확보에 도움이 되도록 다시 작성했습니다. 이제 우리는 그것을 이해합니다. 일부 장애물에는 존재할 만한 타당한 이유가 있습니다. 아마도 제대로 작동하지 않는 오래된 코드가 있을 뿐일 수도 있습니다. 그리고 당신은 그것을 계속 이어가야 합니다. 괜찮습니다. 그래서 이 강연의 나머지 부분에서는, 이제 어떻게 유지할 수 있는지 알아보겠습니다. 하지만 그러려면 여러분은 다음을 해야 합니다. 저희 위치 추적기가 충족하는 매우 높은 보안 기준을 충족하기 위해서입니다. 그러기 위해서는 우리가 왜 그렇게 만들었는지 이해해야 합니다. 즉, 우리는 보안에 대한 이해를 가져야 한다는 뜻입니다. 그 이면에 있는 과학적 원리.

    그럼 공격자들이 하는 일, 즉 시스템을 악용하는 행위부터 시작해 보겠습니다. 그리고 많은 사람들이 공감할 수 있는 무언가와 함께 그리고 이 주제에 대해 여러분이 좀 더 쉽게 이해할 수 있도록 설명해 드리겠습니다. 익스플로잇을 작성하는 것은 디버깅의 정반대 과정입니다.

    메모리 손상 문제를 디버깅할 때는 언제나 범죄 현장부터 다시 시작해야 합니다. 일부 메모리가 잘못 수정되었거나 잘못 사용되었습니다. 그리고 프로그램이 오작동하도록 내버려 두세요. 원인을 알아내기 위해 단서들을 모아보려고 노력합니다. 버그는 무엇이었나요? 손상된 메모리 영역은 어디였나요? 어디에서 유래되었습니까?

    착취하는 데 있어서는 정반대입니다. 어떤 기억을 바탕으로 시작했는데, 그 기억이 잘못 처리되었습니다. 그리고 당신은 수정할 가치가 있는 메모리를 찾으려고 노력합니다.

    좀 더 과학적인 방식으로 설명하자면, 저희는 업계에서 다소 독특한 접근 방식을 취하고 있습니다. 그리고 실제로는 공격자 중심적입니다.

    우리는 '공격자 유형'이라고 부르는 하나의 기억 조각을 가지고 있습니다. 이것이 바로 부패를 조장하는 원인입니다. 여기서 '유형'이라는 용어는 매우 중요한 역할을 합니다. 이는 메모리 위치의 고유한 특성을 나타냅니다. 데이터 구조일 수도 있습니다. 문자열일 수도 있고, 레코드 모음일 수도 있습니다. 다음으로는 피해자 유형이 있습니다. 공격자가 수정하려는 메모리 부분이 바로 그 부분입니다. 그것이 바로 메모리 손상의 목표입니다. 해당 메모리에는 비밀번호나 함수 포인터 등이 저장되어 있을 수 있습니다. 또는 나중에 공격자에게 능력을 부여하는 무언가 임의의 코드 실행을 수행하기 위해.

    이 두 가지 유형은 메모리 어딘가에 있습니다. 그래서 그들 사이에는 특정한 거리가 있습니다. 환자가 있을 수도 있는데, 그럴 경우 거리는 1입니다. 또는 두 지점이 겹칠 수도 있는데, 이 경우 거리는 0이 됩니다.

    공격자가 시스템을 관찰할 수 있다고 가정합니다. 임의의 횟수만큼 연산을 수행할 수 있습니다. 그들은 커널과 통신하고 파일 시스템을 살펴볼 수 있습니다. 그들이 가진 권한 내에서 할 수 있는 모든 것. 우리는 공격자의 행동을 제한하는 것에 의존하지 않습니다.

    공격자가 제어권을 확보하면 승리합니다. 그리고 공격자와 피해자 사이의 거리를 예측합니다. 그게 전부입니다. 그게 바로 기록 메모리, 즉 데이터 손상 악용의 핵심입니다.

    그리고 이것은 간단해 보일 수도 있고, 뭐, 훌륭한 과학적이죠, 그는 대개 그렇습니다. 하지만 사실 그것은 매우 심오한 의미를 담고 있습니다. 그곳에 도착하기까지 오랜 시간이 걸렸습니다. 그리고 이는 우리의 선택지가 무엇인지 명확히 보여주기 때문에 중요합니다. 메모리 손상 방지에 관해서라면. 그리고 이것이 보여주는 것은 우리가 실제로 사용할 수 있는 수단은 단 두 가지 유형뿐이라는 것입니다. 그리고 거리. 수비수 입장에서 보면, 이 게임의 핵심은 타입 선택과 거리 측정을 불가능하게 만드는 것입니다. 또는 공격자가 예측하고 제어하기가 극히 어렵습니다.

    이것이 바로 저희의 안전한 메모리 할당자들이 모두 구현하는 이유입니다. 네 가지 핵심 보안 속성.

    우선, 그들은 타입 인식을 합니다. 전통적으로 malloc을 통해 할당되는 값은 단순히 바이트 묶음일 뿐입니다. 할당자는 요청된 크기 외에는 많은 정보를 알지 못합니다. 할당의 의도를 알지 못합니다. 우리의 안전한 할당자는 타입을 이해합니다. 그리고 이러한 엄청난 이점은 주로 수동 타이핑을 통해 얻어집니다. 커널 및 컴파일 시간 자동 타이핑, 이것이 바로 우리가 사용자 공간에서 사용하는 것입니다. 타입 정보를 얻었으면 이제 게임을 시작할 수 있습니다. 우리의 할당자는 공격자가 제어하기 어렵게 만들 수 있습니다. 메모리에서 데이터 유형을 서로 다른 영역으로 분리할 수 있습니다. 그리고 종류가 워낙 많다 보니 종류별로 지역을 하나씩 지정하는 건 사실상 불가능합니다. 그게 이상적일 겁니다. 그래서 우리는 비슷한 특징을 가진 것들을 한데 모읍니다. 우리는 부팅 시점에 이러한 데이터 수집을 무작위로 수행합니다. 그래서 기기마다 그룹이 다르게 설정될 것입니다. 이는 공격자들이 취약점을 더욱 정교하게 다듬을 방법을 찾도록 강요합니다. 각기 다른 조합마다. 기기에서 실행될 수도 있습니다.

    비슷한 맥락에서, 우리는 이러한 유형 영역의 메모리 내 배치 위치를 무작위로 지정합니다. 다시 한번 말씀드리지만, 저희는 부팅 시에 이 작업을 수행합니다. 그러면 기기 간에 추가적인 차이가 발생하게 됩니다. 이로써 공격자의 시도는 다시 한번 좌절되었습니다. 서로 다른 유형 클래스 간의 거리를 예측합니다.

    그리고 마지막으로, 우리는 메모리 태깅 확장 기능을 활용합니다. 다양한 유형 클래스 내에서의 공격을 차단하기 위해. 각 위치와 자유 순환 방식마다 다른 태그를 할당합니다. 또한 해당 지역 전체에 태그가 고르게 분포되도록 합니다. 저희는 또한 해당 번호를 시행합니다. 두 개의 방사선 물체는 동일한 태그를 가지고 있거나 가지고 있습니다. 1과 작은 크기 사이의 거리를 이용하는 것이 불가능하게 만듭니다.

    이것이 바로 저희 보안 할당자가 작동하는 방식입니다. 메모리 손상 버그를 방지하기 위해,

    이제 필리포에게 무대를 넘기겠습니다. 당신이 할 수 있는 일을 누가 다룰까요? 세 가지 일반적인 사용자 지정 메모리 관리 패턴을 방지하기 위해 앞서 말씀드렸던 것처럼요. 그래서 애플리케이션의 보안을 저해하지 않습니다.

    이제 당신 차례입니다.

    제 이름은 필리포이고, Caere에서 보안 엔지니어로 일하고 있습니다. 엔리코가 말했듯이, 대부분의 경우, 메모리 무결성 강제 적용을 채택하는 것은 필수가 아닙니다. 귀하 측에서 코드 변경 사항이 있을 수 있습니다. 하지만 특별한 주의가 필요한 상황도 있습니다. 그리고 지금 제가 바로 그 과정을 진행할 내용들이 바로 이것들입니다. 각각의 요소가 기억력, 무결성, 집행력에 어떤 영향을 미치는지 살펴보겠습니다. 그리고 해당 보안 모델을 설명하고 최적의 해결 방안을 제시합니다.

    그럼 먼저 살펴보겠습니다. 아마도 가장 흔하게 발견되는 추상적인 개념에서 모든 종류의 코드베이스, 할당자 래퍼.

    그럼 엔리코가 방금 전에 보여준 예를 통해 그렇게 해봅시다. 메모리 할당 함수, 이를 통해 여러분이 찾아야 할 일련의 특징들을 정의할 기회를 얻을 수 있기 때문입니다. 코드베이스에서 할당자 래퍼를 식별합니다.

    우선, 래퍼는 기존 함수에 로직을 추가하는 함수입니다. 시스템 할당자 API. 이것들은 사용 중인 메모리를 요청할 수 있다는 점에서 일반적입니다. 서로 다른 유형을 저장하기 위해, 그리고 이러한 요소들은 코드베이스 전체에서 추상화 계층으로 사용됩니다. 할당자와 상호 작용하기 위해서입니다.

    이 모든 게 꽤 무해해 보이죠, 그렇죠? 그럼 타입 격리가 실제로 어떻게 작동하는지 살펴보겠습니다. 할당자 래퍼의 보안적 의미를 이해하기 위해서입니다.

    여기에는 패킷 처리 로직을 구현하는 코드가 있습니다.

    걱정 마세요, 이걸 전부 다 읽을 필요는 없어요. 그리고 실제로 시스템 할당자 인터페이스의 핵심적인 측면에 집중해 보겠습니다. 이것이 바로 타입 격리의 기초가 되는 부분입니다. 사실 모든 작업을 대신해주는 건 컴파일러입니다.

    Xcode 에서 타입 할당자 지원을 활성화하면, 컴파일러 기능 중 '타입 메모리 연산'이라는 기능을 활성화합니다. 이 기능을 탑재하면 컴파일러가 자동으로 타입을 추론합니다. 각 할당 코드 사이트에 대해 그리고 각 호출을 타입 인식 호출로 다시 작성합니다. 타입 정보를 추가 인수로 전달합니다.

    컴파일러가 각 할당에 서로 다른 모양을 할당하는 것을 상상할 수 있습니다. 그리고 이러한 모양들은 전달되는 정보를 정확하게 나타냅니다. 시스템 할당자에게, 이는 할당을 분리하는 데 사용됩니다. 타입 버킷팅 정책을 구현하여 해당 타입에 따라 분류합니다.

    래퍼를 구현하면 이러한 호출 지점은 컴파일러에게 불투명해집니다. 그러면 단 하나의 형태만 볼 수 있게 됩니다. 이제 시스템 할당자에 의해 모든 할당량이 하나로 묶이게 됩니다. 생성된 유형 정보만 볼 것이기 때문입니다. 래퍼 내부의 호출 지점에서.

    그럼 이 문제를 해결하기 위해 우리가 무엇을 할 수 있는지 알아봅시다. 물론, 래퍼에 의해 구현된 로직이 중요하지 않다면 말이죠. 코드의 기능에 있어서, 가장 간단한 해결책은 래퍼를 완전히 제거하는 것입니다. 그리고 시스템 할당자 인터페이스를 직접 호출합니다.

    포장지를 보관해야 한다면, 타입 인식 변형을 구현하면 제대로 작동할 것입니다. 유형 정보를 아래로 전달하세요 시스템 할당자에게 유형 메모리 연산을 채택함으로써. 운영체제 전반에 사용되는 것과 동일한 컴파일러 기술입니다.

    그럼 그 과정을 단계별로 살펴보겠습니다.

    먼저 상위 요소의 타입 인식 변형을 선언합니다. 이 함수는 크기 인자 바로 뒤에 추가적인 유형 ID 인자를 받습니다.

    그런 다음 밑줄을 사용하여 형식이 지정되지 않은 변형에 주석을 달면 됩니다. 해당 타입 변형을 지정하여 malloc 타입 매크로를 호출합니다. 그리고 크기 인수의 위치. 컴파일러에게 모든 호출을 형식이 지정되지 않은 변형으로 변환하도록 지시하고 있습니다. 타입 인식 기능을 가진 객체로 호출하는 것으로 변환합니다. 또한 각 호출 지점에서 타입 디스크립터를 합성합니다.

    마지막으로, 타입 인식 변형을 구현해야 합니다. 하지만 이건 아주 쉽습니다. 추가적인 로직은 모두 그대로 유지할 수 있습니다. 필요한 변경 사항은 적절한 유형을 호출하는 것뿐입니다. 타입 디스크립터 값을 전달하여 malloc 인터페이스를 인식합니다. 논거로서.

    이 방법을 사용하면 아무런 변경도 할 필요가 없습니다. 래퍼를 실제로 사용하는 코드로 이동합니다. 컴파일러는 각 호출 지점에서 자동으로 타입 정보를 제공합니다. 당신을 위한.

    이것은 간단한 개요일 뿐이며, 더 자세한 정보는 다음을 참조하십시오. 이 접근 방식에 대한 문서를 살펴보시기를 권장합니다.

    좋습니다. 이제 할당자 래퍼를 다루는 방법을 이해했습니다. 이제 풀과 캐시에 대해 알아보겠습니다.

    수영장에 대해 이야기할 때, 우리는 어떤 형태로든 재활용을 구현하는 모든 접근 방식을 지칭합니다. 왕복 통신을 피하기 위해 동일한 유형의 객체만 사용합니다. 시스템 할당자에게, 그러한 물건 중 하나가 폐기되었다가 다시 사용될 때마다. 캐싱 전략 또한 이 범주에 속합니다.

    이러한 맥락에서 핵심 개념은 다음과 같습니다. 이해해야 할 것은 이러한 추상화 개념이 생명주기를 바꾼다는 점입니다. 재활용되는 물건들 중 일부입니다.

    그리고 이는 안보 측면에서 심각한 문제를 야기합니다. 메모리 태깅이 제공하는 보호 기능에 대해. 그럼 예시를 통해 이러한 의미가 무엇인지 설명해 드리겠습니다.

    여기에는 객체 풀이 있습니다. 각각은 메모리 태깅을 사용하여 태그가 지정된 할당에 의해 지원됩니다.

    객체 풀에서 객체를 추출할 때, 일반적으로 해당 객체에 대한 포인터를 얻습니다. 이는 할당과 관련된 메모리와 동일한 태그를 갖게 됩니다.

    우리는 물건 사용을 마치면 다시 수영장에 넣어둡니다. 이제 코드에 버그가 있는 상황을 생각해 보겠습니다. 그리고 우리는 해당 객체를 가리키는 유효하지 않은 포인터를 계속 유지합니다. 이것이 바로 사용으로 이어질 수 있는 요인입니다. 공격자가 악용할 수 있는 취약점이 발견된 후입니다.

    만약 우리가 단순히 그 물건을 재활용한다면, 이는 매달린 포인터가 둘 다 해당한다는 것을 의미합니다. 그리고 새로 장착될 조명에도 유효한 태그가 남아 있을 것입니다. 댕글링 포인터를 제어하는 ​​공격자는 다음과 같은 작업을 수행할 수 있습니다. 재활용된 물체를 수정하기 위해, 이는 메모리 손상으로 이어져 앱의 로직이 변경될 수 있습니다.

    이러한 취약점으로부터 할당을 보호하기 위해서는, 객체를 재활용하기 전에 태그를 업데이트해야 합니다.

    태그를 다시 지정한 후에는 이전 태그를 가진 포인터를 사용하여 수행되는 모든 액세스는 이전 태그를 사용합니다. 태그가 만료되면 안전하게 오류가 발생하여 앱이 종료되고 악용을 방지합니다.

    그럼 실제로 어떻게 그것을 달성할 수 있는지 설명해 드리겠습니다.

    저희는 패킷 처리 코드에 재활용 정책을 구현했습니다. 패킷을 할당해야 할 때, 우선 우리는 유지하고 있는 스레드 로컬 큐에서 해당 값을 추출하려고 시도합니다. 그리고 우리가 릴리스 패킷 기능을 다시 채운다는 것입니다. 물건을 버릴 때 말이죠. 보시다시피, 이 접근 방식은 여러 가지가 있습니다. 방금 살펴본 바로 그 문제에 대한 것입니다. 그렇다면 MTA가 제공하는 보호 조치를 유지하기 위해 우리는 무엇을 할 수 있을까요?

    물론, 이제쯤이면 짐작하셨겠죠. 최선의 해결책은 다시 한번 시스템 할당자를 직접 사용하는 것입니다. 이렇게 하면 모든 할당이 제대로 다시 태그됩니다. 메모리에서 기대하는 보호 기능을 제공합니다. 청렴성 확보.

    우리는 수년간 디자인에 공을 들였습니다. 그리고 안전한 시스템 할당자를 구현합니다. 그리고 이는 모든 시나리오에서 기존 할당자보다 뛰어난 성능을 보여줍니다. 그리고 실제로 스레드 로컬 캐싱을 사용하면, 저희 시스템 할당자 또한 이와 같은 시나리오에 최적화되어 있습니다.

    이 방법이 적합하지 않은 드문 경우에는, 코드 프로파일링을 권장합니다. 삶을 바꾸지 않는 다양한 전략을 탐색해 보세요. 사물의 순환. 예를 들어, 사용할 객체들을 일괄적으로 할당하는 방식이 있습니다.

    좋습니다. 이 접근 방식을 사용하면 매우 쉬워집니다. 풀링 전략을 조정하기 위해 MI가 제공하는 보안 속성을 보존하기 위해서입니다.

    이제 잠시 사용자 정의 할당자에 대해 이야기해 보겠습니다. 이 기능은 애플리케이션 코드에 반드시 구현될 필요는 없을 수도 있습니다. 하지만 그것들은 여러분이 사용하고 있는 외부 종속성의 일부일 수도 있습니다. 도서관들은 역사적으로 성능상의 이유로 이러한 기능을 구현해 왔습니다. 또는 플랫폼 간 호환성을 위해서입니다.

    사용자 정의 할당자가 있는 경우에는 모든 예측이 무의미해집니다. 사용하고 있는 코드를 이해하는 것이 매우 중요합니다. 사용자 정의 할당자는 Ma의 이점을 누리지 못하고 있으며, 특히 다음과 같은 문제가 발생합니다. 귀하의 앱은 타입 격리의 보호 기능을 활용할 수 없습니다. 그리고 메모리 태깅.

    이러한 상황에서는 보안을 철저히 평가해야 합니다. 이러한 구현을 유지하는 것의 의미. 그럼 저희가 어떤 제안을 할지 짐작하시겠죠?

    해당 코드가 시스템 할당자를 직접 사용하도록 변경하십시오. 저희는 이것이 앱 보안의 기본 요소라고 진심으로 믿습니다. 하지만 저희는 예외적인 경우가 있다는 것을 알고 있습니다. 사용자 지정 할당자를 사용하지 않으면 됩니다.

    그래서 26.1 버전부터 모든 플랫폼에서 다음과 같은 변경 사항이 적용됩니다. SDK에는 필요한 모든 구성 요소가 포함되어 있습니다. 사용자 정의 할당자에 MT 지원을 구현하려면 다음을 수행하십시오.

    이제 하나씩 살펴보겠습니다. 하지만 각 할당자 구현에는 고유한 특성이 있다는 점을 고려하면, 어떻게 이해하는지는 당신에게 달려 있습니다. 이러한 구성 요소를 사용 사례에 활용하세요.

    먼저 런타임에 MT가 활성화되어 있는지 확인해야 합니다. 여기에 나와 있는 것처럼 OS 보안 구성 API를 사용하여 그렇게 할 수 있습니다. 하드웨어 메모리 태깅을 활성화한 후, 앱은 해당 기능을 지원하는 기기에서 빈 화면 모드로 실행됩니다. 하지만 동일한 코드가 해당 기능을 지원하지 않는 기기에서도 실행되어야 합니다. 명령어 세트가 비어있는 것을 전제로 하는 모든 연산을 비웁니다. 건축 설계는 오직 수행되어야만 한다. 해당 프로세스에서 '비어 있음' 옵션이 실제로 활성화되어 있는지 확인한 후.

    다음으로, 할당자가 사용하는 메모리 페이지를 할당할 때, VM에 메모리 태깅을 지원하는 페이지를 제공해 달라고 요청해야 합니다. VM 플래그를 우회합니다. VM 할당 호출에서 플래그를 비워 두세요. 이 단계에서 커널은 사용자에게 페이지를 제공합니다. 관련 태그 값이 모두 0이 됩니다.

    바로 그게 이유입니다. 마지막으로, 그리고 가장 중요하게는, 할당량에 태그를 지정하고 싶습니다. 여러 가지 가능성이 있습니다. 태그 체계를 선택할 때, 그리고 고려해야 할 미묘한 차이가 많을 것입니다. 이러한 사항들을 각각 실행할 때.

    사용 가능한 API에 대한 간략한 개요를 알려드리겠습니다. 각 위치에 다시 태그를 지정하는 간단한 예를 살펴보겠습니다. 해제되면 다시 할당자로 돌아갑니다.

    태깅과 할당에는 두 가지 부분이 있습니다. 대상을 선택하고 포인터에 포함시키세요. 그런 다음 태그를 태그 저장 메모리에 저장합니다. 태그를 선택하려면 먼저 고려해야 할 사항을 포함하는 제외 마스크를 생성해야 합니다. 현재 할당과 연관된 목표에 대해. 이렇게 하면 하드웨어에 질문할 수 있습니다. 이전에 사용한 태그를 제외하고 새로운 무작위 태그를 생성합니다. 빈 난수 생성 태그는 우리에게 포인터를 반환합니다. 동일한 메모리에 저장하지만, 상위 비트에 다른 임의 태그를 지정합니다.

    마지막으로, 빈 매장 태그를 사용하여 하드웨어 담당자에게 문의해야 합니다. 새로 생성된 태그를 태그 저장 메모리에 저장하려면 전달 방식을 사용합니다. 새 태그가 있는 포인터에서 그리고 태그를 지정해야 하는 기본 메모리 블록의 크기입니다. 이것이 바로 메모리 할당자에 메모리 태그를 지정하는 데 필요한 전부입니다.

    이것들은 모두 지원 기능을 구현하는 데 필요한 기본적인 도구들이었습니다. 메모리 할당자에서 메모리 태깅을 하려면 다음과 같이 하세요. 이것으로 밀라노에서의 여정은 사실상 끝을 맺게 되었습니다. 하지만 마무리하기 전에, 이번 세션의 핵심 내용을 다시 한번 강조하겠습니다. 메모리 무결성 강제 적용을 최대한 활용하기 위해 할 수 있는 일은 무엇일까요?

    하드웨어 메모리 태깅을 활성화해야 합니다. 그리고 Typekit 할당자에 대한 지원을 순서대로 제공합니다. 최상의 방법을 사용하여 사용자에게 매우 구체적인 보호 기능을 제공합니다. 수업용 기술. 메모리 손상 취약점을 완화하는 데 있어서, 입양하기 정말 쉬워요. 특히 대다수의 시나리오에서, 이러한 기술들이 제공하는 모든 보안상의 이점을 누릴 수 있습니다. 코드 변경 없이 제공할 수 있습니다.

    하지만 이 강연에서 살펴본 바와 같이, 보호 효과를 감소시키는 특정 패턴들이 존재합니다. 메모리 무결성 시행에 의해 제공됩니다. 코드베이스를 감사하고 이러한 문제점을 파악하도록 권장합니다. 이를 통해 노출 정도를 더 잘 평가할 수 있습니다.

    이러한 사항 중 하나를 발견할 때마다. 바람직한 해결 접근 방식은 전환이어야 합니다. 시스템 할당자를 직접 사용하는 것으로 변경합니다. 이것은 당신에게 가능한 모든 장점을 누릴 수 있게 해줍니다.

    하지만 경우에 따라서는 이것이 불가능할 수도 있습니다. 우리는 당신에게 도구를 제공했습니다. 그리고 그러한 추상적인 개념들을 적용해야 한다는 점을 이해해야 합니다. 기억력과 진실성을 지원하기 위해 보안 속성을 엄격히 시행하고 깊이 뿌리내린 보안 속성을 보존합니다. 운영 체제에 삽입됩니다.

    이제 올리버 씨를 무대 위로 모시고 제어 흐름 무결성에 대해 이야기 나눠보겠습니다. 포인터 인증을 사용합니다.

    고마워, 필리포. 안녕하세요, 여러분. 저는 올리버 헌트입니다. 보안 및 툴링 분야에서 일하는 엔지니어입니다. Apple 의 보안 도구 및 컴파일러입니다. 회의의 이 시점에서, 메모리 안전성 오류로부터 코드를 보호하는 방법에 대해 알아보았습니다. 메모리 무결성 강제 적용 기능이 포함되어 있습니다. MI는 메모리 안전성 버그를 악용하는 것을 매우 어렵게 만듭니다. 하지만 모든 공격으로부터 보호해 줄 수는 없습니다. 하드웨어를 도입하는 방법을 보여드리겠습니다. 애플리케이션에 포인터 기반 인증을 제공합니다. 제어 흐름 무결성을 유지합니다. 즉, 공격자가 저를 우회하여 임의의 메모리를 손상시킬 수 있다고 하더라도, 그들은 아직 그 능력을 갖고 있지 않다 애플리케이션이 실행할 코드를 제어하기 위해 포인터 인증을 사용합니다. 하드웨어, 컴파일러, 그리고 운영 체제는 모두 함께 작동합니다. 공격자가 표적으로 삼는 포인터의 유효성을 보장하기 위해 애플리케이션을 탈취하려는 시도 중에 발생합니다. 작동 방식은 다음과 같습니다. 내부적으로는,

    포인터 인증을 사용하면 CPU와 운영 체제는 포인터의 암호화 서명을 생성합니다. 그런 다음 그들은 해당 서명을 포인터 자체에 삽입합니다. 이러한 서명을 통해 하드웨어는 포인터의 유효성을 확인할 수 있습니다. 사용되기 전에 코드가 신뢰의 사슬을 갖게 됩니다. 포인터가 사용될 당시의 값을 모든 역추적하여 연결합니다. 원래 값으로, 그리고 포인터 인증은 이러한 포인터를 계속해서 보호합니다. 마우스를 사용하는 응용 프로그램에서도 마찬가지입니다. 서명 방식을 투명하게 조정하여 메모리 태깅 기능을 확장합니다. 기존 태그를 수용하기 위한 인증 작업도 포함됩니다. 이 모든 것이 갖춰진 상태에서 추가 태그를 사용하면 다음과 같습니다. 공격자가 포인터를 손상시키려고 시도할 때, 서명이 더 이상 유효하지 않으며 신뢰의 사슬이 끊어졌습니다.

    이제 나중에 코드가 해당 포인터를 사용하려고 할 때, 하드웨어가 이를 감지하고 애플리케이션을 안전하게 종료합니다. 공격자는 악성 코드를 실행하기 전에 저지되었습니다.

    Apple 에서는 포인터 인증 API를 개발해 왔습니다. 거의 10년 동안 저희는 이를 플랫폼 보호 도구로 사용해 왔습니다. 그 모든 시간 동안.

    이제 설계가 충분히 안정적이고 견고해졌으므로 안심하고 채택하셔도 됩니다. 그리고 저희가 사용하는 것과 똑같은 보호 조치를 여러분의 코드에도 적용하십시오. 자사 소프트웨어를 보호하기 위해서입니다. 포인터 인증은 상당한 변화를 가져오지만 코드 생성 과정에서 우리는 몇 가지 요소만 남도록 했습니다. 애플리케이션에서 차이점이 나타날 가능성이 있는 부분입니다.

    그럼 주요 사항들을 살펴보겠습니다.

    반송 주소는 오랫동안 공격자들의 표적이 되어 왔습니다. 그리고 지난 수년간 다양한 완화 조치가 시행되어 왔습니다. 포인터 인증으로 보호합니다. 이것은 한 차원 더 높은 수준으로 끌어올려졌습니다. 전화를 걸 때마다 회신 주소가 표시됩니다. 포인터 인증에서는 반환 주소 자체와 현재 호출 프레임에 대한 정보도 포함됩니다. 반송 주소에 포함된 서명에 삽입됩니다. 이 정보는 또한 다음과 같이 사용됩니다. 반송 주소를 추적하기 전에 인증 절차를 거쳐야 합니다.

    이는 반환 순간부터 신뢰의 사슬을 유지합니다. 주소는 처음 기록된 시점부터 사용되기까지, 또한 공격자가 유효하게 서명된 파일을 재사용하는 것을 방지합니다. 이전 호출에서 얻은 포인터입니다. 이 모든 것은 기본적인 호출 규약의 일부로 이루어집니다. 그리고 어셈블리로 작성된 함수에서는 거의 보이지 않습니다.

    자, 만약 여러분의 코드가 상호 작용한다면 함수 호출이라는 기본적인 것을 넘어선 호출 스택을 고려하면, 또한 모든 API가 제대로 작동하는지 확인했습니다. 그리고 이를 위해 사용하고 있는 컴파일러 기능은 계속 작동합니다. 원활하게 작동하도록.

    이제 여러분이 명시적으로 사용하고 있는 기능들을 하나씩 살펴보겠습니다. 애플리케이션의 동적 제어 흐름을 위해서입니다.

    함수 포인터부터 시작하겠습니다. 왜냐하면 이것들은 동적 제어 흐름의 가장 기본적인 형태이기 때문입니다. 신청서에 있습니다. 그리고 거의 제한 없는 온갖 종류의 기능이 있습니다. C나 C++ 같은 언어에서 간접적인 코드 실행 방식입니다. 그래서 저희는 모든 서류에 서명이 되어 있는지 확인합니다. 이는 C 언어에서 흔히 사용되는 관용구로서 중요합니다. C++에서는 함수 포인터를 정수 또는 불투명 포인터로 형변환합니다. 그리고 우리는 당신이 이것을 항상 피할 수 있는 것은 아니라는 것을 알고 있습니다. 그래서 우리는 포인터 인증을 확실히 했습니다. 이 모델은 이러한 모든 작업 과정에서 내장된 서명을 유지합니다. 코드를 변경할 필요 없이.

    이는 다시 한번 신뢰의 사슬이 유지된다는 것을 의미합니다. 공격자가 이러한 포인터를 수정할 수 있는 지점은 없습니다. 컴파일러가 그것들이 함수라는 사실조차 더 이상 알지 못하더라도 바늘.

    하지만 우리는 당신의 코드에서 당신이 원하지 않는 것이 무엇인지 알고 있습니다. 함수 포인터를 사용하여 모든 작업을 수행합니다. 그래서 언어에서 지원하는 동적 디스패치를 ​​광범위하게 활용하고 있는 것입니다.

    Swift 가상 메서드에서 final이 아닌 메서드를 호출할 때 발생하는 문제입니다. C++로 메시지를 보내거나 Objective-C 로 모든 언어로 메시지를 보냅니다. 동적 배차는 여러 단계의 간접 참조를 기반으로 구축됩니다.

    가장 간단한 형태로 말하자면, 각 객체 인스턴스는 일종의 유형 정보를 가리키는 포인터를 가지고 있습니다. 또는 메서드 테이블.

    그러면 해당 데이터 구조에는 또 다른 포인터가 있습니다. 각 방법의 실제 구현으로.

    이러한 상호작용은 공격자들에게 매력적입니다. 이러한 각 계층은 독립적으로 공격받을 수 있기 때문입니다.

    그래서 Swift, C++, Objective-C 에서는 다음과 같은 이유입니다. 우리는 이 과정의 모든 단계를 보호해 왔습니다. 그리고 이 체인에 있는 각 포인터에 대한 서명을 생성할 때, 우리는 객체의 유형, 식별 정보 등을 포함합니다. 또는 객체의 위치, 심지어 대상 메서드의 유형까지도 알 수 있습니다.

    그리고 나서 동적 호출을 할 때, 각 단계는 동일한 정보를 사용하여 인증됩니다.

    이 모든 일을 함으로써, 저희는 귀하의 애플리케이션이 단순히 보호되는 것뿐만 아니라 안전하게 보호되도록 만전을 기했습니다. 메모리 손상뿐 아니라 수명 및 유형 혼동 공격까지 발생할 수 있습니다. 하지만 이러한 수준의 보호는 포인터가 유용한 몇 안 되는 이유 중 하나입니다. 인증을 위해 코드를 변경해야 할 수도 있습니다. 그 이유를 알아보기 위해 첫 번째 인증 단계에 집중해 보겠습니다.

    각 서명에 객체의 위치 정보를 포함시킴으로써, 우리는 서명이 유효한 경우에만 유효하도록 조치했습니다. 메모리의 이 위치에.

    이는 공격자가 메모리 안전성 오류를 이용하는 것을 방지합니다. 한 객체를 다른 객체 위에 복사하는 것.

    하지만 Memcpy와 같은 저수준 함수를 사용하여 이러한 객체를 복사할 때는, 근본적으로 공격자가 하는 행동과 다를 바 없습니다. 결과는 동일할 것입니다. 나중에 해당 객체를 사용하려고 하면 인증 실패 오류가 발생합니다.

    이는 포인터 인증 방식이 변경되는 사례 중 하나입니다. 기존 코드가 정의되지 않은 상태가 되는 것을 방지합니다. 정상적으로 작동하는 것처럼 보이는 동작이 런타임에 실패하는 정의되지 않은 동작으로 이어질 수 있습니다.

    지금까지는 여러분이 받을 수 있는 최고 수준의 보호에 대해서만 다뤘습니다. 포인터 인증을 사용합니다. 훨씬 더 심오한 배열이 있지만, 당신은 절대 그것을 볼 수 없을 겁니다.

    우리는 이 구현을 설계했습니다. 기존 코드와 호환되도록 하기 위함입니다. 그러니 여러분도 이 기능을 여러분의 애플리케이션에 적용해 보고 싶어하실 거라고 확신합니다. 그럼 그 방법을 단계별로 안내해 드리겠습니다.

    자, 여러분의 애플리케이션에서 입양 절차를 시작하기 전에 말이죠. 포함시키는 모든 라이브러리가 올바른지 확인해야 합니다. 또는 포인터 인증을 지원하는 링크입니다.

    이러한 라이브러리의 작성자라면 해당 작업을 직접 수행해야 합니다. 하지만 외부에서 개발된 라이브러리를 사용하는 경우에는, 거래처에 연락하셔야 합니다. 그들이 포인터 인증을 채택하도록 하려면 그리고 범용 바이너리를 제공해 드립니다.

    그 과정이 완료되면 자체 애플리케이션에서 도입 노력을 시작할 수 있습니다.

    향상된 보안 사용 옵션을 선택하면 됩니다. Xcode 프로젝트의 빌드 설정에서 확인하세요. 이를 통해 메모리 무결성, 강제 적용 및 포인터 인증이 가능해집니다.

    이렇게 하면 Xcode 자동으로 프로젝트를 구성합니다. 익숙한 Arm64 슬라이스를 포함하는 유니버설 바이너리를 빌드합니다. 그리고 하드웨어에서 사용되는 추가적인 Arm64 e 슬라이스가 있습니다. 포인터 인증을 지원합니다.

    한 번에 한 가지씩만 실천하고 싶다면, 포인터 인증에만 집중하려면 다음을 사용하면 됩니다. 대신 '포인터 인증 활성화' 옵션을 사용하십시오.

    포인터의 모든 부분을 다시 설계했습니다. 우리는 포인터 인증 기반 보호 기능을 모두 제대로 작동하도록 설계했습니다. 기존 코드를 사용하여 그리고 대부분의 애플리케이션은 빌드될 것입니다. 그리고 이러한 모든 보호 조치가 적용된 상태에서 올바르게 실행됩니다. 하지만 물론, 그것이 보장되는 것은 아닙니다. 다음 단계는 여러분이 애플리케이션을 광범위하게 테스트하는 것입니다.

    자, 여러분이 처음 접하게 되는 버그 중 일부는 다음과 같은 결과일 수 있습니다. 기존 코드에 존재하던 버그가 이제 인증 실패로 인해 감지됩니다. 이는 예상된 결과입니다. 이제 이러한 버그들을 알았으니, 직접 수정할 수 있을 겁니다.

    하지만 작성된 코드가 있을 가능성도 있습니다. 포인터 인증과 호환되지 않는 방식으로.

    그러한 경우에는 몇 가지 변경이 필요합니다.

    이러한 불일치의 근본적인 원인은 다음과 같습니다. 의도치 않게 정의되지 않은 동작을 호출하는 경우.

    이러한 작업들이 겹치기 때문에, 공격자들이 악용하는 버그와 겹치는 경우가 많습니다. 그들은 똑같은 보호 장치에 의해 저지당합니다.

    실제로 대부분의 코드는 이러한 문제에 부딪히지 않습니다. 하지만 가장 흔한 출처 몇 가지를 간단히 살펴보겠습니다. 저희가 발견한 호환성 버그들입니다.

    우리가 목격한 가장 흔한 패턴은 안전하지 않은 상황에서 비롯됩니다. memcpy와 같은 함수를 사용하여 다형성 객체를 복사합니다.

    우리는 이미 memcpy나 유사한 함수를 사용하는 것이 왜 안전하지 않은지에 대해 이야기했습니다. 이것을 할 때. 하지만 여러분이 직접 이러한 전화를 걸지는 않더라도, 컨테이너 타입 내에 이러한 작업을 수행하는 코드가 있을 수 있습니다. 그리고 바로 그 지점에서 우리는 이러한 실패들을 목격해 왔습니다. 이러한 오류를 해결하는 방법은 더 높은 수준의 언어 기능을 채택하는 것입니다. 데이터 구조를 사용하거나 객체 복사를 위한 라이브러리 함수를 채택할 수 있습니다. 그리고 초기화는 언어 자체에 내장되어 있기 때문입니다. 그들은 당신이 가진 물건의 종류에 대해 알고 있습니다. 그리고 그들은 정확한 의미론을 보장하기 위해 필요한 모든 작업을 수행할 것입니다. 가능한 한 효율적으로.

    함수 포인터의 상위 비트에 추가 데이터를 저장하는 경우는 훨씬 더 드뭅니다. 만약 코드가 이렇게 한다면, 해당 저장소는 서명을 손상시킬 것입니다.

    이 문제를 해결하려면 스타터 모터를 옮겨야 합니다. 포인터의 맨 아래쪽 부분으로, 또는 해당 데이터를 포인터 밖으로 완전히 옮기는 방법도 있습니다.

    이것들은 우리가 관찰한 가장 흔한 패턴들입니다. 포인터 인증을 채택하는 코드도 있지만, 여전히 매우 드뭅니다. 심지어 매우 큰 코드베이스에서도 마찬가지입니다.

    하지만 만약 여러분이 애플리케이션에서 이러한 패턴을 알고 있다면, 입양 과정의 일환으로 이러한 문제들을 해결해야 합니다.

    이제 필요한 변경 사항을 모두 적용하셨으니, 그리고 테스트 결과 애플리케이션이 예상대로 작동하는 것으로 나타났습니다. 사용자들에게 배포할 예정입니다.

    다른 모든 릴리스와 마찬가지로 새로운 충돌 보고가 있을 수 있습니다. 그리고 당신은 이것이 인증 실패인지 알고 싶어하는군요.

    이 문제를 진단하는 데 도움이 되도록 프로그램이 종료될 때 다음과 같은 정보를 제공합니다. 생성된 충돌 로그에는 진단 메시지가 포함됩니다. 오류는 인증 실패 때문일 수 있습니다.

    하지만 직접 크래시 로깅을 수행하는 경우에는, 오류가 발생한 주소의 상위 비트를 검사할 수 있습니다. 유사한 진단을 제공하기 위해.

    이제, 단순히 충돌이 발생할 예정이라는 사실만 알면 됩니다. 인증 실패만으로는 충분하지 않습니다. 그럼 인증 실패 사례를 하나 살펴보겠습니다. 그러면 문제가 어떻게 나타날지, 그리고 어떻게 수정할 수 있을지 확인할 수 있습니다. 자, 여기 아주 간단한 프로그램이 있는데 인증 오류가 발생했습니다.

    Xcode 디버거에서 오류를 발견했을 때. 처음에는 다른 사고와 마찬가지로 보일 것입니다.

    하지만 인증 실패로 인해 발생하는 함정은 항상 상위 비트를 설정합니다. 오류가 발생한 주소에서. 그리고 지금 여러분이 보고 계신 것이 바로 그것입니다. 자, 설정되고 있는 존재의 정확한 부분에 집중하지 마세요. 이는 하드웨어 세대에 따라 달라질 수 있기 때문입니다.

    그리고 저희의 간단한 테스트 프로그램에서는, 해당 오류는 이 호출 직후에 발생합니다. 객체 복사 함수로 이동합니다. 그리고 우리는 앞서 내 기존 상태가 문제가 될 가능성이 있다는 것을 알게 되었습니다. 코드가 데이터를 복사하는 방식이 잘못되어 유효하지 않은 객체가 생성될 수 있습니다. 그럼 그 기능을 살펴보겠습니다.

    어쩌면 당연한 일일지도 모릅니다. 왜냐하면 이것은 무언가 잘못되는 상황을 보여주는 데모이기 때문입니다. 이 함수는 Memcpy를 사용하여 다형 객체를 복사합니다. 예전에는 이게 효과가 있었거든요. 이 예시는 코드에서 이러한 문제가 발생하는지 여부를 매우 명확하게 보여줍니다. 이는 맞춤형 또는 특수 용기 내부에서만 발생할 가능성이 높습니다. 그리고 데이터 구조.

    다행히 컴파일러가 이미 이러한 문제를 찾는 데 도움을 줍니다. 이러한 안전하지 않은 작업에 대해 조기에 경고를 발령함으로써 문제를 해결할 수 있습니다. 포인터 인증이 활성화되지 않은 경우에도 마찬가지입니다.

    코드베이스가 허용한다면 말이죠. 이러한 경고를 오류로 설정해야 합니다.

    이제 문제점을 찾으셨군요. 어떻게 해결할지 결정해야 합니다. 그리고 여러분에게는 여러 가지 선택지가 있습니다. 그럼 몇 가지 예를 살펴보겠습니다.

    가장 간단한 해결책은 형식이 지정되지 않은 메모리 접근 함수에서 벗어나는 것입니다. 그건 메모리가 표준 라이브러리로 복사되고 이동하는 내용입니다. 객체를 이동, 복사 및 초기화하는 데 필요한 함수가 제공됩니다.

    이러한 기능은 필요한 모든 작업을 보장합니다. 객체가 올바르게 초기화되었는지 확인하는 작업이 수행될 것입니다. 그리고 안전하다고 판단되면 Memcpy와 같은 함수를 사용할 것입니다.

    하지만 이미 이러한 저수준 함수에서 벗어나고 있는 상황이니, 더 높은 수준의 언어 기능을 직접 도입하는 것을 고려해 보세요.

    예를 들어, 이러한 복사 작업에 대한 안전한 대안은 다음과 같습니다. 당신에게 위치와 같은 것을 활용하기 위해서요.

    우리가 본 가장 어려운 사건은 당신에게도 매우 힘든 사건입니다. Memcpy를 사용하고 있다면 해결 방법은 다음과 같습니다. 객체의 동적 타입을 유지하려고 하기 때문입니다.

    이 문제를 해결하려면 코드 구조를 재구성해야 할 수도 있습니다. 언어 수준의 다형성과 같은 것을 사용하기 위해서입니다. 예를 들어, 이 예시에서는, 우리는 복사 방식을 가상 복제 방식으로 대체했습니다. 또는 수동으로 유형을 인식하는 로직을 사용하여 이러한 복사를 수행할 수도 있습니다. 그러니까 타입을 확인하는 거죠.

    물론, 다시 말씀드리지만, 이것은 아주 기본적인 데모 프로그램일 뿐입니다. 인증 실패 시 어떤 화면이 나타나는지 보여드리겠습니다. 그리고 그 문제를 해결할 수 있는 몇 가지 방법을 제시합니다. 하지만 거의 모든 언어에서 발생하는 인증 실패 문제는 해결되었습니다. 마찬가지로, 저수준 작업에서 벗어나야 합니다. 대신에 사용 중인 언어가 제공하는 지원 기능을 활용하세요. 런타임 및 라이브러리.

    포인터 인증이 코드를 어떻게 보호하는지에 대해 많이 이야기했습니다. 그리고 우리는 C++로 작성된 예제도 살펴보았습니다.

    하지만 포인터 인증을 도입할 필요가 없다고 생각할 수도 있습니다. 이미 입양하셨으니까요. 또는 Swift 와 같은 안전한 언어를 도입하는 과정에 있습니다.

    하지만 그것만으로는 코드를 보호하기에 충분하지 않습니다.

    그 이유를 이해하려면 공격자들이 어떤 방식으로 공격하는지 살펴볼 필요가 있습니다. 코드를 대상으로 지정하려면.

    근본적으로 공격자가 애플리케이션을 제어하려면 두 가지가 필요합니다. 우선, 그들은 당신의 애플리케이션 상태를 손상시키는 데 사용할 수 있는 버그가 필요합니다.

    이 예시에서 안전하지 않은 scanf 함수를 사용하면 공격자가 취약점을 악용할 수 있습니다. 결과 버퍼가 넘치도록.

    둘째, 손상된 상태의 결과에 대응하는 코드가 필요합니다.

    여기서 그들은 버퍼 오버플로를 이용할 수 있습니다. 오류 처리 함수의 내용을 덮어쓰려면 호출 함수 내에서 오류 처리기를 호출하는 것입니다. 그러면 해당 오류 처리기가 호출됩니다. 이 프로그램은 공격자가 선택한 명령어를 실행합니다. 이제 그들이 당신 애플리케이션의 제어 흐름을 장악했습니다. 그리고 그들은 원하는 코드를 무엇이든 실행할 수 있습니다. 소프트웨어 악용에 대해 생각할 때, 처음 발생한 버그만 생각해서는 안 됩니다. 공격자가 그 버그를 이용해 무엇을 하려는지 생각해 봐야 합니다. 그럼 지금 전화 건 사람을 살펴보겠습니다. 이건 당신이 전에 수없이 봤던 것처럼 안전하지 않은 C 또는 C++ 코드입니다. 그렇다면 안전한 언어 사용이란 어떤 모습일까요? 네, 제가 이 함수를 Swift 로 다시 작성했습니다. 그리고 C 버전과 거의 동일합니다. 사실, 오류 처리기를 덮어쓰는 데 사용된 것과 정확히 동일한 취약점을 이용했습니다. C 함수의 해당 코드를 Swift 버전에서도 대체할 수 있습니다.

    다시 말씀드리지만, 여러분이 쉽게 따라할 수 있도록 아주 간단한 예시를 사용하고 있습니다. 하지만 어떤 언어를 사용하든 결과는 동일합니다. 원래 버그가 무엇이었든 간에, 그리고 그것을 활용하는 것이 얼마나 복잡하든 상관없이. 그 이유는 사용자가 앱을 실행할 때, 그들은 단순히 당신이 작성한 코드를 실행하는 것만이 아닙니다. 그들은 모든 라이브러리의 코드를 실행하고 있습니다. 여러분의 코드와 함께 실행되는 것들입니다. 그러므로 어떤 언어를 사용하든 상관없이, 코드에 존재할 수 있는 모든 버그로부터 코드를 보호해야 합니다. 프로세스에서 실행 중인 안전하지 않은 코드 중 하나에서 발생합니다.

    포인터 인증을 도입하면 그렇게 할 수 있습니다. 공격자가 애플리케이션을 해킹하기가 훨씬 더 어려워졌습니다. 심지어 관리하는 사람들조차도 메모리 무결성, 시행 등의 다른 보호 조치를 우회하기 위해서입니다.

    그리고 기존 코드를 거의 또는 전혀 변경하지 않고도 이러한 보호 기능을 얻을 수 있습니다.

    이렇게 포인터 인증을 사용할 수 있습니다. 공격자가 앱을 탈취하는 것을 방지하기 위해서입니다.

    그럼 이만, 엔리코 씨, 함께해 주셔서 감사합니다. 필리포와 저는 기억, 진실성, 집행에 대한 이 개요를 작성했습니다. 포인터 인증은 하드웨어를 통해 사용자를 보호할 수 있습니다. 컴파일러, 운영 체제, 그리고 앱이 모두 함께 작동합니다.

    입양을 통해 분명히 알게 되실 거예요. 이러한 도구를 사용하는 것은 실용적이며, 필요한 준비물은 거의 없거나 전혀 없습니다. 코드 변경 사항을 반영하며, 무결성에 상당한 이점을 제공합니다. 그리고 앱의 전반적인 안전성을 확보하는 것입니다. 감사합니다. 그럼 이제 커트에게 다시 돌아가죠.

Developer 바닥글

  • 비디오
  • Meet with Apple
  • 메모리 무결성 강화 및 포인터 인증 도입하기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • AI 및 머신 러닝
    • Apple Intelligence
    • 오디오 및 비디오
    • 증강 현실
    • 비즈니스
    • 디자인
    • 배포
    • 교육
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 보안
    • Safari 및 웹
    메뉴 열기 메뉴 닫기
    • 문서
    • 다운로드
    • 샘플 코드
    • 비디오
    • 문서 아카이브
    메뉴 열기 메뉴 닫기
    • 도움말 및 문서
    • 문의하기
    • 포럼
    • 피드백 및 버그 리포트
    • 시스템 상태
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, ID 및 프로파일
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Centers
    • App Store 어워드
    • Apple 디자인 어워드
    • Apple Developer Academy
    • WWDC
    최신 뉴스 읽기 Apple Developer 앱 받기 bilibili, LinkedIn, WeChat, YouTube에서 팔로우하기
    Copyright © 2026 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침