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 도움말
    • 새로 추가될 요구 사항
    • 계약 및 지침
    • 시스템 상태
  • 빠른 링크

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

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 전체 비디오
  • 소개
  • 소개
  • 자막 전문
  • 앱의 보안 강화하기: 보안 강화를 위한 필수 전략

    Apple Developer Center Cupertino에서 하루 종일 진행되는 활동에 참여하여 앱의 보안을 강화하고 사용자 데이터를 보호하는 방법을 알아보세요. 기존 앱을 강화하는 경우든, 새로운 프로젝트를 시작하는 경우든, Apple 엔지니어에게 직접 앱을 처음부터 강화하는 방법을 알아볼 수 있습니다.

    최신 앱이 직면한 보안 문제를 알아보고, 사용자 데이터를 보호하는 데 도움이 되도록 설계된 포괄적인 도구 및 기술 모음을 살펴보세요. 메모리 무결성 강화, 포인터 인증, 메모리 경계 안전성과 같은 강력한 기능으로 C 및 C++ 코드베이스를 보호하는 방법을 확인해 보세요. 보안에 특히 민감한 구성요소에 Swift를 도입하는 방법을 알아보세요. 내재된 안전성과 최신 추상화 기능을 활용하여 안전한 고성능 코드를 작성할 수 있습니다. 그리고 전반적인 보안 전략 수립부터 실제 구현까지 새로운 프로젝트와 기존 프로젝트를 위한 명확한 보안 로드맵을 구축하는 방법에 대한 조언을 얻을 수 있습니다.

    리소스

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

    안녕하세요, 쿠퍼티노에 있는 Apple 개발자 센터에 오신 것을 환영합니다. 저는 커트이고 기술 전도사입니다. 전 세계 개발자 관계 팀 소속입니다.

    오늘, 저와 제 동료들은 다양한 기술을 공유하게 되어 매우 기쁩니다. 메모리 안전성 취약점을 줄여 앱의 보안을 강화합니다. 다룰 내용이 많지만, 먼저 저희 행사장에 대해 좀 더 자세히 소개해 드리고 싶습니다. Apple 개발자 센터.

    개발자 센터는 Apple Park 의 일부입니다. 오늘 행사에 아주 적합한 장소이며, 소통을 위한 공간도 마련되어 있습니다. 그리고 협력.

    이 방은 빅서에 있습니다. 멋진 공간에 훌륭한 시설이 갖춰져 있어요. 저는 이 화면이 정말 마음에 들어요. 다양한 활동을 지원하도록 설계되었습니다. 이번과 같은 대면 프레젠테이션, 스튜디오 녹음 등을 포함하여, 그리고 지금 저희가 출연 중인 생방송도 있죠. 안녕하세요, 여러분.

    실험실과 브리핑룸도 있습니다. 또한 다양한 규모의 행사를 개최할 수 있는 회의실도 갖추고 있습니다.

    이곳은 전 세계에 있는 4개의 개발자 센터 중 하나입니다. Apple 디자이너와 개발자를 대상으로 세션, 랩, 워크숍 등을 개최합니다. 여기 계신 분들 중에 개발자 센터에 가보신 적 있으신가요? 좋습니다. 처음 오시는 분이든 다시 찾아주시는 분이든, 모두 환영합니다.

    저희 팀은 개발자들과 소통하는 것을 매우 좋아합니다. 저희의 목표는 여러분이 애플 플랫폼에 최적화된 최고의 앱을 만들 수 있도록 돕는 것입니다. 웹 25주년 이후로, 저희는 전 세계적으로 300개 이상의 활동(실험실 교육 포함)을 주최해 왔습니다. 워크숍 및 프레젠테이션. 다음 주에는 제 동료들이 저는 New York 시에서 새로운 디자인에 대한 워크숍을 진행하고 있습니다. 워크숍 참가자들은 액체 유리를 직접 체험하게 됩니다. 코드와 디자인을 업데이트하면서. 가까운 지역이나 온라인에서 열리는 예정된 행사에 대해 자세히 알아보려면 다음을 참조하세요. 개발자 를 확인해 보세요. 오늘 일정을 시작하기 전에, 회의실에 있는 사람들이 하루 종일 서로 소통을 유지할 수 있도록 몇 가지 팁을 드립니다. Apple Wi-Fi 네트워크를 사용하세요. 누구나 접속할 수 있고 비밀번호도 없습니다. 충전이 필요할 경우 언제든지 모든 좌석에 전원 콘센트가 마련되어 있습니다. 팔걸이 앞쪽에 있습니다.

    오늘 방송을 시청하시는 모든 분들께, 이 발표들은 녹화되어 행사 후 온라인에서 시청하실 수 있습니다. 영상을 녹화하거나 라이브 스트리밍을 할 필요가 없습니다.

    하지만 사진을 찍고 싶으시다면 얼마든지 찍으셔도 좋습니다.

    행사가 끝난 후에는 관련 링크가 포함된 후속 정보도 보내드리겠습니다. 프레젠테이션에서 언급된 모든 자료를 확인하세요. 그러면 중요한 내용을 놓치지 않을 것입니다.

    사전 준비가 끝났으니, 오늘 행사에 대해 더 자세히 이야기 나눌 수 있게 되어 기쁩니다.

    오늘 다룰 주제는 메모리 보안 취약점과 해결 방법입니다. 사람들에게 있어 전자기기는 삶의 필수적인 부분입니다. 그들의 기기에는 수많은 개인 데이터와 사적인 정보가 담겨 있습니다.

    결과적으로, 이들은 공격자들이 노리는 주요 표적이 됩니다. 이 정보에 접근하려면.

    오늘 발표에서는 다음 내용을 다룰 것입니다. 메모리 버그를 찾아 수정함으로써 공격자로부터 앱을 보호합니다. 일반적인 보호 조치를 적용하고, 심지어 메모리 안전성이 확보된 코드를 작성하는 것까지 포함합니다.

    온라인에 접속하신 분들을 위해, Slido를 사용하면 Apple 엔지니어에게 질문을 보낼 수 있습니다. 저희 팀은 질문에 답변해 드릴 준비가 되어 있으며, 여러분을 적극적으로 도와드릴 것입니다. 오늘 주제에 집중해 주시길 부탁드립니다. 저희 팀은 예시에 대한 질문에 답변해 드리기를 기대하고 있습니다. 슬라이도(Slido)의 프레젠테이션 및 일반적인 앱 보안 문제에 대해 말씀드리겠습니다. 다른 사람들이 올린 질문을 살펴보고, 마음에 드는 질문에 투표할 수 있습니다. 그리고 팀의 답변을 읽어보세요. 이 자료는 여러분의 질문을 바탕으로 만들어진 훌륭한 자료이니, 주저하지 말고 질문해주세요.

    기술 프로그램을 시작하기 전에, 빅서 무대에 특별한 손님을 모시겠습니다. 애플의 플랫폼 보안 책임자를 환영해 주시기 바랍니다. 피에르 올리비에 마르텔. 피에르.

    커트, 고마워요.

    안녕하세요 여러분. 제 이름은 피에르 올리비에 마르텔입니다. 저는 보안 엔지니어링 부서에서 플랫폼 보안 책임자를 맡고 있습니다. 그리고 건축 그룹. 먼저 오늘 온라인으로 함께해 주셔서 진심으로 감사드립니다. 이렇게 많은 분들이 와주셔서 정말 기쁩니다. 이제 우리는 기기가 사람들에게 얼마나 중요한 존재가 되었는지 모두 알고 있습니다. 누가 이러한 기기를 사용하는지, 그리고 이러한 기기와 기기에 저장된 데이터를 보호하는 것, 소통이든, 친밀한 순간이든, 건강 또는 재정 정보, 이것이 바로 우리가 개인정보보호 시스템을 구축하는 이유입니다. 그리고 처음부터 제품에 보안 기능을 통합했습니다. Apple 하드웨어를 심층적으로 통합함으로써 최고의 보안을 구현합니다. 소프트웨어 및 서비스. 지난 15년 동안, 저희 제품에는 업계 최고 수준의 보안 시스템이 다수 탑재되어 있습니다. 이러한 기능에는 보안 부팅(Secure Boot) 등이 포함됩니다. 이는 첫 번째 명령어부터 소프트웨어의 무결성을 보장합니다. 터치 ID, 얼굴 인식과 같은 인증 기술에 이르기까지, 그리고 광학 ID를 끝까지 iMessage 또는 iCloud 키체인에 사용되는 암호화 프로토콜을 종료합니다.

    우리의 나침반은 변함없이 그대로입니다. 보안은 기본적으로 내장되어 있어야 하며 사용하기 쉬워야 한다고 생각합니다. 그리고 이러한 노력의 결과는 보안 연구원들이 다음과 같은 일을 하게 된다는 것입니다. iPhone 가장 안전하고 보안이 뛰어난 소비자용 모바일 기기라는 점에 동의합니다.

    이제 여러 사건의 공통분모는 다음과 같습니다. 업계의 다른 플랫폼을 대상으로 하는 플랫폼들을 포함하여, 그들이 메모리 보안 취약점을 악용한다는 것입니다. Apple 에서는 메모리 안전성을 향상시키기 위해 열심히 노력해 왔습니다. 예를 들어, Swift 와 같은 메모리 안전 언어를 사용하여 개발함으로써 이러한 포함이 가능해집니다. 그리고 완전히 새로운 완화 조치를 대규모로 배포합니다. 오늘 여러분은 그중 일부에 대해 듣게 될 것입니다. 가장 최근에는 메모리 무결성 강제 기능을 도입했습니다. 최신 iPhone 및 Mac 모델과 함께. 이제 Emmi는 독특한 특징들을 결합한 획기적인 제품입니다. Apple Silicon 하드웨어의 강점과 당사의 고급 운영 체제 보안의 결합 업계 최초로 제공하기 위해, 기기 전반에 걸쳐 항상 활성화되는 메모리 안전 보호 기능을 제공하면서도 성능 저하를 방지합니다. 기기 성능에 관하여.

    하지만 이 장은 우리가 사용자에게 보안 장치를 배송하는 것으로 끝나지 않습니다. Apple 기기의 보안도 루팅되어 있기 때문입니다. 주변 생태계의 힘에 달려 있습니다. 따라서 안전한 생태계에 대한 우리의 관심은 세 번째 단계까지 이어집니다. 우리는 개발자 커뮤니티인 여러분과 함께 협력하는 파티 소프트웨어 생태계를 만들어갑니다. 안전한 앱을 제공하기 위해. 그러려면 앱 스토어와 플랫폼 보안 기능이 함께 작동해야 합니다. 그리고 이 파트너십이 그토록 중요한 이유가 바로 여기에 있습니다. 공격자들은 플랫폼을 구분하지 않습니다. 그리고 그 위에서 실행 중인 앱들. 그들은 가장 약한 고리를 찾는다. 따라서 우리는 플랫폼 보안 기준을 체계적으로 높여 나갈 것입니다. 우리는 이 문제를 모든 곳에서 제기해야 합니다. 사실, 우리는 이 문제를 모든 곳에서 제기해야 합니다. 이는 이러한 기술들이 널리 채택될 수 있도록 함께 노력해야 한다는 것을 의미합니다. 가능한 한 최선을 다했습니다. 그래서 저희가 진행해 온 작업 결과를 공유하게 되어 매우 기쁩니다. 또한 여러분의 앱에서 해당 기능을 도입할 수 있도록 지원합니다. 저희가 모든 사용자를 보호하기 위해 사용하는 것과 동일한 고급 보안 기술을 다수 적용하고 있습니다. 오늘 함께해 주셔서 다시 한번 감사드립니다. 환영합니다. 그럼 이제 커트에게 마이크를 넘겨서 시작해 보도록 하겠습니다.

    감사합니다.

    고마워, 피에르. 올리비에. 오늘 남은 일정에 대한 개요는 다음과 같습니다. 저희 기술 프로그램은 실습 가이드로 시작합니다. Apple 자사 앱을 보호하기 위해 사용하는 것과 동일한 메모리 보안 전략을 사용합니다. 언제, 어떻게를 포함하여 타입 지정자와 같은 빠른 성과를 통해 각 방어 계층을 적용하기 위해, 신속한 재작성과 같은 장기 투자에 그리고 향상된 보안 확장 기능.

    그다음에는 잠시 쉬면서 스트레칭을 하겠습니다. 그리고 카페인이 함유된 음료를 즐길 수도 있습니다. 그 다음에는 기억, 진실성, 집행에 대한 심층적인 탐구가 이어집니다. 그리고 포인터 인증. 두 가지 강력한 하드웨어 및 소프트웨어 보안 기능이 포함되어 있습니다. 메모리 손상 공격으로부터 어떻게 보호하는지, 그리고 여러분의 코드가 이러한 보호 조치를 훼손하지 않도록 하는 방법을 알려드립니다. 점심시간으로 80분간 휴식을 취하겠습니다. 그런 다음 여기로 돌아와서 세 번의 프레젠테이션을 더 들어보세요. C와 C++에서 경계 안전성을 도입하는 실용적인 가이드부터 시작합니다. C 언어에서 컴파일러가 강제하는 경계 주석에 대해 다룹니다. 또한 C++에서 표준 라이브러리 검사를 강화했습니다.

    짧은 휴식 후 이제 막바지에 접어들었습니다. 여기서는 Swift에 내장된 메모리 안전성 보장이 C와 어떻게 다른지 알아보겠습니다. C++에서 성능이 중요한 코드에 새로운 저오버헤드 스팬 타입을 사용하는 방법 그리고 점진적으로 어떻게 할 것인가, 안전하지 않은 코드베이스를 점진적으로 마이그레이션합니다. 엄격한 메모리 안전 모드와 C 상호 운용 기능을 사용하여 Swift 로 변환합니다.

    그리고 오늘 마지막 시간에는, 주소 살균기 사용법을 알아보세요 Xcode 의 스레드 새니타이저를 사용하면 버퍼 오버플로를 사전에 찾아낼 수 있습니다. 코드베이스에서 버그와 데이터 경쟁을 해결한 후에 사용하세요. 여기에는 소독제가 메모리 무결성 강화에 어떻게 도움이 되는지 등이 포함됩니다.

    마지막으로, 오늘 이 자리에 함께 해주신 분들을 위해 마무리 인사를 드리겠습니다. 개발자 센터 로비에 모여서 Apple 엔지니어들과 대화할 수 있는 믹서 모임에 참여해 보세요. 그리고 다른 동료 개발자들.

    자, 이제 기술 프로그램을 시작하겠습니다. 빅서 무대에 마크를 환영합니다. 표시.

    감사합니다.

    안녕하세요. 저는 애플 보안 엔지니어링 팀의 마크 미첼입니다. 그리고 제 동료 데빈과 함께 건축팀을 구성했습니다. 오늘은 여러분이 보호할 수 있는 프레임워크에 대해 설명드리겠습니다. 앱의 메모리 보안 취약점을 방지하세요.

    데빈이 사용한 전략들을 신중하게 겹겹이 쌓고 조합한 결과 오늘 제가 이야기할 내용은 iPhone 그 명성을 얻게 된 요인입니다. 현재 시판되는 소비자용 기기 중 가장 안전한 제품으로 인정받고 있습니다. 오늘 세션 동안 이러한 기능들이 무엇인지에 대해 이야기해 보겠습니다. 그것들이 무엇을 위한 것인지, 그리고 Apple 어떻게 사용하는지 예를 들어 설명해 드리겠습니다. 앱, 운영체제 및 고객을 보호하기 위해서입니다.

    Xcode 사용하면 이제 Apple 사용하는 것과 동일한 기술을 사용할 수 있습니다. 앱 사용자를 보호하기 위해서입니다.

    앱은 우리 삶의 많은 부분에 영향을 미칩니다. 이것들은 모든 사람들이 개인 정보를 믿고 맡기는 필수적인 도구입니다. 위치, 검색 기록, 방문 내역, 사진, 메시지, 재정 정보, 그리고 동시에 이러한 앱과 사용자는 인터넷에 연결되어 있습니다. 따라서 이러한 제품의 보안 취약점은 사용자를 공격에 노출시킬 수 있습니다. 이러한 공격으로 인한 비용은 사기부터 시작됩니다. 신분 도용부터 협박에 이르기까지, 그리고 드물지만 어떤 경우에는 더욱 심각한 문제가 발생할 수 있습니다. 물리적 세계의 위협.

    사람들은 자신의 데이터가 비공개로 안전하게 보호되기를 기대합니다. 그리고 그 약속이 지켜지지 않는다면 그것은 신뢰를 저버리는 행위입니다. 보안은 개인정보 보호를 가능하게 하는 기술적 기반입니다.

    먼저 메모리 안전성이 무엇을 의미하는지 간략하게 설명드리겠습니다. 그리고 이로 인해 발생할 수 있는 다양한 유형의 취약점.

    다음으로, 보안에 대한 개괄적인 설명을 드리겠습니다. 앱을 보호하기 위해 사용할 수 있는 엔지니어링 전략 그리고 우리가 어떻게 성공적으로 활용했는지 설명해 주십시오. 마지막으로 데빈이 이러한 전략을 실제로 적용하는 방법을 보여줄 것입니다. Xcode 에서 향상된 보안 기능을 사용합니다.

    그렇다면 메모리 안전성이란 무엇을 의미하는 걸까요? 메모리 안전성 버그는 가장 흔한 취약점 유형 중 하나입니다. 소프트웨어에서 공격자는 메모리 손상을 이용하여 시스템을 변경합니다. 또는 프로그램 동작을 왜곡합니다.

    Apple 의 보안 엔지니어들은 메모리 안전성을 의도된 사용 목적이라는 관점에서 생각합니다. 그리고 프로그램에서 발생하는 의도치 않은 동작. 일반적인 사용 환경에서 프로그램은 개발자 의도한 대로 작동합니다. 그리고 이치에 맞는 행동만 수행합니다. 그러니까 프로그램 진행 과정을 미로와 비슷하다고 생각하면 됩니다. 미로를 통과하는 경로가 바로 코드입니다. 개발자 특정 작업에 사용될 목적으로 개발했습니다. 나머지 경로는 사용되지 않거나 도달할 수 없는 코드 경로를 나타냅니다.

    그리고 도달할 수 없는 길은 다음과 같을 수 있습니다. 사용하지 않는 프레임워크에서 회전과 같은 작업을 수행합니다. 카메라로 촬영하거나 이메일을 보내세요. 공격자는 이러한 메모리 보안 취약점을 악용하여 공격을 시도할 수 있습니다. 프로그램을 속여 예상치 못한 상태로 만들어 그들이 사용할 수 있도록 개발자 실제로 의도했던 것과는 전혀 다른 동작을 수행합니다.

    이 예시에서는 메모리 안전성 취약점이 어느 곳에서든 발생할 수 있습니다. 의도된 경로는 미로를 푸는 완전히 새로운 방법으로 이어진다 또는 의도하지 않은 코드를 실행하기 위해 새로운 경로를 만들거나 새로운 경로를 택할 수도 있습니다. 그리고 이는 앱이 카메라를 강제로 켜도록 해당 코드를 호출하는 것을 의미할 수 있습니다. 또는 이메일을 보내세요.

    메모리 안전성은 보안의 기본이며, 메모리 안전성이 확보되지 않으면 보안이 무너집니다. 우리는 최고 수준의 보안 기능을 보장할 수 없습니다. 예를 들어, 비밀번호 해싱 방식이 얼마나 강력한지는 중요하지 않습니다. 공격자가 접근 권한을 얻을 수만 있다면 메모리 보안 취약점을 악용하여 시스템에 접근합니다.

    다음은 예시입니다. 간단한 로그인 기능입니다. 사용자가 입력한 비밀번호의 텍스트 필드 내용을 복사합니다. 디버그 빌드인지 확인하고 디버그 빌드인 경우 인증을 건너뜁니다. 그러면 개발자 책상에서 더 빠르게 테스트할 수 있을지도 모릅니다. 그리고 비밀번호 사본과 비교하는 함수를 호출합니다. 일부 비밀 키를 하드코딩하고 로그인 결과를 반환합니다. 특히 눈썰미가 좋은 분들은 눈치채셨을지도 모르겠습니다. 저 거대한 빨간색 X 표시. 명백히 메모리 보안 취약점이 있습니다. 이 코드는 복사하면 안 되는 코드입니다. 여기서 개발자 스택에 32개의 문자를 저장할 공간을 할당하고 있습니다. 비밀번호 사본을 보관하기 위해, 하지만 복사 API는 사용 가능한 공간이 얼마나 되는지 알지 못합니다. 그러면 해당 텍스트 필드에 있는 문자 수만큼 복사됩니다. 해당 버퍼에 데이터가 입력되면 스택 버퍼 오버플로가 발생합니다.

    기억의 이면에서, 대략 이런 일이 벌어지고 있습니다. 로컬 암호 저장소는 사용되는 메모리 바로 앞에 있습니다. 디버그 로그인 플래그를 유지하기 위해. 만약 비밀번호가 예를 들어 18자라면, 당연히 안전하게 저장할 수 있습니다.

    하지만 공격자가 32자 이상을 보내면 어떻게 될까요?

    그렇다면, 이 프로그램은 특정 언어로 작성되었기 때문입니다. 그건 메모리 안전성이 확보되지 않았습니다. 인접한 메모리를 덮어쓰기 시작할 겁니다. 그리고 여기 있는 메모리는 디버그 로그인 플래그를 저장하는 데 사용됩니다.

    결과적으로 개발자 의 의도와는 상관없이 이러한 결과가 나타납니다. 또는 프로그램이 이 if 문을 만났을 때 이 함수에 전달됩니다. 만약 해당 값이 공격자에 의해 덮어쓰여지거나 변경되었다면, 그들은 인증을 건너뛰도록 강제하고 어쨌든 true를 반환할 수 있습니다.

    하지만 사실 그 코드에는 훨씬 더 심각한 문제가 있습니다. 디버그 플래그를 덮어쓰면 공격자가 인증 없이 로그인할 수 있습니다. 하지만 메모리에서는 디버그 로그인 플래그 다음에 주소가 있습니다. 프로그램이 비교 작업을 수행하기 위해 호출할 함수 포인터입니다.

    공격자가 훨씬 더 긴 비밀번호를 제공하는 경우, 디버그 로그인 플래그를 사용하면 로컬 암호 버퍼에서 오버플로가 발생할 수 있습니다. 그리고 그 함수 포인터를 원하는 대로 변경할 수 있습니다. 즉, 프로그램이 비교 함수를 호출하려고 할 때, 실제로 비교하는 과정이 될 것입니다. 실제로는 공격자가 원하는 어떤 함수든 호출하게 될 것입니다. 이제 공격자는 이 프로세스를 완전히 장악했습니다. 이러한 다른 코드 경로에 접근하여 잠재적으로 사용자 데이터를 탈취할 수 있습니다.

    위 예시는 버퍼 오버플로우의 예입니다. 이는 메모리 안전성의 속성 중 하나를 위반하는 것입니다. 하지만 실제로는 다섯 개의 축이 연결되어 있습니다. 안전 장치는 모든 접근을 보장합니다. 메모리 관련 작업은 메모리 할당 범위 내에서 발생합니다. 평생 안전 기능은 메모리가 유효한 기간 동안에만 사용되도록 보장합니다. 그리고 다른 용도로 재사용되지 않았습니다.

    타입 안정성은 프로그래머가 실수로 해당 값에 접근하는 것을 방지합니다. 의도했던 방식과는 다른 방식으로 메모리가 관리됩니다.

    보장된 초기화는 메모리가 사용되기 전에 초기화되도록 보장합니다.

    마지막으로, 실 안전성은 서로 다른 실이 엉키는 것을 방지합니다. 서로의 기억을 기리며.

    공격은 대개 이런 식으로 진행됩니다. 일반적으로 앱을 공격하는 공격자는 다음을 찾습니다. 해당 앱에서 데이터에 접근하거나 이를 침해하는 것뿐만 아니라 해당 앱에서 데이터에 접근할 수 있지만, 그것은 하나의 단계로 활용하겠습니다. 다른 시스템 구성 요소를 공격하는 일련의 버그 중 첫 번째 단계입니다. 심지어 커널에 대한 권한까지 상승시켜야 합니다. 플랫폼 보안 모델을 약화시키기 위해, 그들은 시스템 전체의 파일에 접근하는 것뿐만 아니라, 하지만 위치 데이터, 사진, 연락처, 마이크와 같은 다른 자산도 포함됩니다.

    따라서 앱은 종종 더 큰 규모의 공격으로 이어지는 관문 역할을 합니다.

    동시에 최신 애플리케이션은 다음과 같은 기능을 제공합니다. 기능이 너무 많아서 많은 사용자에게 접근 권한이 부여되었습니다. 이러한 자산 대부분은 일반적인 사용 환경에서 그렇습니다. 운영체제가 보안 ​​태세를 지속적으로 발전시킴에 따라, 미래에는 그렇게 될 것이라고 예상하는 것이 합리적입니다. 공격자들은 단순히 앱을 악용하는 것만으로도 만족할 수 있습니다. 그리고 그들이 해당 환경에서 접근할 수 있는 데이터를 수집합니다. 그리고 플랫폼의 나머지 부분으로 넘어갈 필요가 없습니다. 그래서 지금 우리 모두가 함께하는 것이 정말 중요한 것입니다. 안보를 확보하면서 동시에 앞으로 나아가자.

    이제 Apple 에서 사용하고 있는 전략에 대해 이야기해 보겠습니다. 메시지와 같은 애플리케이션 및 서비스를 보호하기 위해, Safari 및 메일 앱에서 메모리 보안 취약점이 발견되었습니다.

    충분히 복잡한 코드베이스라면 어떤 경우든 마찬가지입니다. 취약점은 언제나 존재할 것이라는 점은 이미 받아들여지고 있습니다. 너무 심해졌어요.

    그래서 Apple 여러 겹의 보안 엔지니어링 계층에 의존합니다. 그리고 서로를 보완합니다.

    더 깊고 더 깊은 잠수가 있을 겁니다. 오늘 제가 소개할 여러 기술에 대해 말씀드리자면, 하지만 저는 Apple 이러한 개념들을 어떻게 적용하는지에 대한 개념을 소개하기 위해 이 자리에 왔습니다. 그리고 그 효과를 평가할 수 있는 몇 가지 방법도 있습니다. 그리고 이러한 요소들을 여러분의 응용 프로그램에 활용하는 데 필요한 노력에 대해서도 고려해야 합니다. 다섯 가지 전략에 대해 이야기하겠습니다.

    메모리 보안 취약점을 불가능하게 만드는 방법에 대해 설명하겠습니다. Swift 와 같은 메모리 안전 언어를 사용하여 코드에서 메모리 사용량을 줄이세요. 취약점에 접근할 수 없도록 만드는 방법 (접근 가능한 범위를 줄이는 방식) 공격 표면,

    취약점이 악용되지 않도록 만들기 만약 악용 사례가 발생할 경우, 그 피해를 최소화하는 완화 조치가 포함되어 있습니다.

    마지막으로, 찾는 데 도움이 되는 몇 가지 기법을 소개합니다. 또한 코드의 취약점을 제거합니다.

    가장 포괄적인 접근 방식 메모리 보안 취약점으로부터 방어하는 것은 그것들을 만들어내는 것이 거의 불가능하게 만드는 언어를 사용하다 우선, 바로.

    Apple 안전하고 성능이 뛰어난 언어인 Swift 에 막대한 투자를 해왔습니다. 또한 기본적으로 메모리 안전 기능을 제공합니다. 이는 여러 애플리케이션에 동력을 공급할 뿐만 아니라, 하지만 이는 운영 체제의 일부이기도 합니다. 그리고 여기에는 보안에 매우 중요한 코드베이스가 점점 더 많이 포함됩니다. WebKit 과 같은 기술, 복잡한 구문 분석 등 심지어 Secure Enclave 프로세스 펌웨어와 같은 임베디드 환경에서도 작동합니다. 물론, 많은 앱에는 이미 작성된 방대한 코드베이스가 있습니다. C 계열 언어에서. 메모리 안전하지 않습니다.

    강화된 보안 기능에는 F 밴드 안전과 같은 도구가 포함됩니다. C에 대한 주석 C++ 표준 라이브러리 강화 밴드 안전 오류 발생 위험을 줄이는 데 도움이 됩니다. 하지만 이것들을 메모리 보안으로 가는 디딤돌이라고 생각하세요. 그것들은 나머지 네 가지 축을 다루지 않기 때문에 최종 목표가 아닙니다.

    C 기반 언어와 Swift 다음 다섯 가지 기준에 따라 비교해 보겠습니다. C 기반 언어는 이러한 보호 기능을 전혀 제공하지 않습니다. 반면 Swift 경계 검사 배열을 사용하여 경계 안전성을 제공합니다. 그리고 다른 Swift 표준 라이브러리 추상화 기능들. 이 시스템은 자동 참조 계수 및 소유권 관리를 통해 평생 안전성을 제공합니다. 이는 런타임에 형변환 검사를 요구함으로써 타입 안정성을 보장합니다.

    Swift 변수 초기화를 요구함으로써 초기화를 보장합니다. 사용하기 전에. 또한 빠른 동시 처리를 통해 데이터 경쟁을 방지하여 스레드 안전성을 제공합니다.

    자, 이것으로 사용법에 대한 아주 간단한 설명을 마치겠습니다. 메모리 보안 취약점을 불가능하게 만들기 위해. 나중에 Swift 로 보안에 민감한 코드를 작성하는 방법에 대한 세션을 확인해 보세요. 더 자세한 정보를 원하시면.

    Apple 적극적으로 활용하는 두 번째 전략은 다음과 같습니다. 보안에 중요한 코드베이스에서 이를 공격 표면 감소라고 합니다. 여기서 핵심 이론은 개발자와 보안 엔지니어로서, 코드의 모든 취약점을 어디에 있는지 알 수는 없습니다. 그리고 여러분이 의존하는 프레임워크는 그럴 수도 있습니다. 하지만 공격자가 접근할 수 있는 코드의 양을 제한할 수는 있습니다. 기능을 수행하는 데 필요한 최소한의 세트로, 그렇게 하면 취약점이 존재할 가능성이 크게 줄어듭니다. 앱에서 실제로 사용되는 코드에 있습니다.

    Apple 시스템 전체에 걸쳐 이 기술을 사용합니다. 공격자가 활동할 수 있는 공간을 줄이기 위해, 그리고 이는 제한하는 기술부터 다양한 범위에 걸쳐 있습니다. 어떤 복잡한 문서 형식을 조건부 기능으로 파싱할 수 있을까요? 상대방이 신뢰할 만한지 여부에 따라 잠금 모드에서는 모든 기능을 완전히 비활성화할 수 있습니다. 형식 제한의 예로, 앱에서 JPEG 이미지만 송수신한다는 것을 알고 있다면, 그런 다음 수신자 측 코드를 허용합니다. 다른 형식의 이미지를 처리하려면 수백만 줄의 구문 분석 코드가 필요합니다. 공격자가 취약점을 찾을 필요가 전혀 없다는 뜻입니다. 그렇다면, 그런 경우에 즉각적인 영향을 미칠 수 있는 가장 좋은 방법은 무엇일까요? 보안을 강화하기 위해서는 JPEG 파일의 형식이 올바른지 확인하는 것이 중요합니다. 또는 프로세스에서 해당 형식만 구문 분석하도록 코어 그래픽을 구성하거나 예상과 일치하지 않으면 트래픽을 차단하면 됩니다.

    앱이 의도치 않게 노출할 수 있는 또 다른 부분입니다. 엄밀히 말하면 필요하지 않은 공격 표면은 다음과 같습니다. 직접 사용하는 웹 뷰를 통해 웹 콘텐츠를 렌더링할 때 앱 내 브라우징과 같은 기능의 경우 그리고 타사에서 가져온 프레임워크를 통해서도 가능합니다. 예를 들어 광고 SDK 같은 것들 말이죠.

    iOS 26.4부터, WebKit 에는 향상된 보안 웹뷰라는 두 가지 강력한 새 옵션이 있습니다. 이러한 모드를 사용하면 앱을 제어할 수 있습니다. 앱이 웹의 콘텐츠를 처리하는 방식을 제어합니다. 추가적인 보안 강화 조치가 포함됩니다.

    기본적으로 WkWebView는 모든 강력한 기능과 성능을 제공합니다. 앱 내에서 바로 WebKit 의 성능을 활용할 수 있습니다. 사파리의 모든 보안 완화 조치와 아키텍처를 그대로 제공하면서 말입니다. 첫 번째 새로운 모드 제한 모드, 호환성을 극대화하면 웹과의 완벽한 호환성을 유지할 수 있습니다. WebKit 현재 지원하는 항목은 다음과 같습니다. 복잡한 프레임워크 코드의 상당 부분을 제거하는 동시에 또한 최신 하드웨어 보안 완화 조치의 사용을 늘리고 있습니다.

    이러한 새로운 모드 중 두 번째인 제한 모드 봉쇄는 훨씬 더 강력한 조치를 취합니다. 이를 통해 앱의 웹뷰를 선택할 수 있습니다. 봉쇄 모드와 동일한 극단적인 수준의 보호 조치로 전환합니다. 또한 사용 빈도가 낮은 웹 기술을 제거합니다. 또한 공격자의 선택지를 더욱 줄입니다.

    Apple 은 이러한 향상된 보안 웹뷰를 도입하기 시작했습니다. 메일을 포함하여 운영체제 전반에 걸쳐 적용됩니다. 간단히 살펴보기. iOS 26.4의 캡티브 포털 바로가기 및 Apple 광고. 그리고 그때가 바로 여러분이 그것들을 시도해 보기에 정말 좋은 시기입니다.

    공격 표면 축소는 보안 투자에 있어 엄청난 수익을 가져다줍니다. 하지만 메모리 안전성 취약점이 존재할 것이라는 가정은 여전히 ​​유효합니다. 안전하지 않은 언어로 작성된 나머지 코드에서.

    그러한 경우, 차선책으로 가장 효과적인 방어 전략은 다음과 같습니다. 악의적인 행위자가 해당 취약점을 악용할 수 있는 능력을 저해하기 위함입니다.

    우리는 보안 완화라고 알려진 여러 기술을 조합하여 이를 수행합니다. 그리고 완화 조치라는 개념. 실례합니다. 위험 완화라는 개념 자체는 새로운 것이 아닙니다. 그것들은 지난 30~40년 동안 진화하고 존재해 왔습니다. Apple 끊임없이 새로운 기능을 개발하고 제공하기 위해 노력하고 있습니다. 그리고 많은 기능이 앱에서 사용 가능합니다. 그리고 사용하기에 안전하다고 확신할 때, 심지어 많은 경우 사용자가 아무것도 하지 않아도 기본적으로 활성화되어 있습니다. 완화책은 버퍼 오버플로우에 대한 초기 방어부터 시작됩니다. 실행 불가능한 스택에 대한 clang 스택 보호기와 같은 것 그리고 ASLR은 바로 통과합니다. 커널 무결성 보호와 같은 최신 하드웨어 지원 기술까지 Xcode 26에는 빠른 권한 제한 기능이 있습니다. 새롭고 강력한 소프트웨어가 있습니다. 또한 앱을 보호하는 데 사용할 수 있는 하드웨어 지원 완화 기능도 있습니다.

    포인터 인증은 컴파일러의 지원을 받는 하드웨어 기술입니다. 이 시스템은 특정 유형의 취약점 전체를 탐지하고 예방할 수 있습니다. 착취당하는 것으로부터, 또한 악용 사례가 발생하더라도 이를 방지할 수 있는 강제력을 제공합니다. 앱의 코드 흐름 무결성이 유지됩니다.

    iPhone 17 및 iPhone 17 Pro 와 함께 출시된 메모리 무결성 강제 기능 이는 5년간의 연구 결과입니다. 모델링 및 엔지니어링 또한 안전한 할당자가 제공하는 견고한 기반 위에 구축되었습니다. 향상된 메모리 태깅 기능과 결합하여, 태그 기밀성 시행으로 알려진 확장 기능 및 보안 정책. 정말 많은 내용이고, 앞으로 진행될 세션에서는 더 많은 내용이 다뤄질 것입니다. 그러한 완화 조치에 대해서는 훨씬 더 자세히 다루겠습니다. 메모리 무결성 강제 적용 및 포인터 인증 세션은 나중에 진행됩니다. 저에 대한 자세한 내용은 security.apple.com 블로그에서 확인하실 수 있습니다.

    Apple 메모리 무결성 강화가 메모리 보안에 있어 가장 중요한 업그레이드 소비자 운영 체제의 역사에서.

    하지만 드문 경우이긴 합니다. 정교한 공격자들은 여전히 ​​가능할 수도 있습니다. 접근 가능한 취약점을 찾기 위해 그리고 우리의 완화 노력에도 불구하고 착취당했습니다.

    그러한 경우, 우리의 최후의 방어선은 봉쇄라고 알려져 있습니다.

    앞서 살펴본 연쇄 반응을 생각해 보세요. 공격자가 발견한 시나리오에서 앱의 메모리 보안 취약점을 악용했습니다. 이제 그들은 그것을 완전히 장악했습니다. 이상적인 목표는 공격자를 이와 같은 환경에 가두는 것입니다. 그래서 그들은 앱 데이터나 플랫폼의 나머지 부분에 접근할 수 없습니다.

    iPhone 출시 초기부터 지금까지, 앱은 악의적인 접근을 방지하는 데 도움이 되는 샌드박스 환경에서 실행됩니다. 사용자 데이터를 보호합니다. 물론 앱은 여전히 ​​자체 데이터에 접근할 수 있습니다. 그리고 그러한 기능을 제공하는 시스템 서비스를 사용합니다. 앱이 고도로 정교한 공격자에 맞서 사용하는 프레임워크는 다음과 같습니다. 하지만 훨씬 더 극단적인 수준의 격리가 필요합니다. 앱 전체를 단순히 연결 해제하는 것은 불가능합니다. 이런 식으로 시스템을. UI를 그리는 등의 작업을 하려면 너무 많은 접근 권한이 필요합니다. 또는 그러한 환경에서 기능하는 데 필요한 리소스에 접근할 수 있어야 합니다. 따라서 메시지 와 같이 보안이 중요한 앱에는 새로운 접근 방식이 필요합니다. 그리고 사파리도 마찬가지입니다. Apple 멀티 프로세스 아키텍처를 설계했습니다. 공격자가 제공한 복잡한 데이터 처리를 이동시키는 기능 접근 권한이 거의 없는, 철저하게 샌드박스화된 환경으로 다른 서비스나 커널과 같은 시스템 리소스에 접근합니다.

    그 결과, 우리는 알려지지 않은 취약점의 위험을 다른 곳으로 옮길 수 있게 됩니다. 타협이 성공적으로 이루어지더라도, 공격자를 자산이 없는 환경에 가두어 버립니다. 메시지나 쿠키처럼요. 또한, 환경적으로도 선택지를 찾을 기회가 매우 적습니다. 권한을 높여 보안을 강화한 상태로 사용자 데이터에 접근할 수 있도록 합니다. Xcode 26에서는 앱에서 이러한 기능을 활용할 수도 있습니다. 이러한 엄격하게 제한된 보안 환경 중에서, 이러한 기능들을 향상된 보안 확장 기능이라고 합니다. 사진을 수신할 때 메시지 기능이 이 아키텍처를 어떻게 활용하는지 설명드리겠습니다.

    그래서 메시지에서는 이를 보안 확장 기능이라고 부릅니다. 방폭문. 그리고 보안 방침은 간단합니다. 수신된 모든 자산은 분석이 완료될 때까지 악성 자산으로 간주하십시오. 그리고 원시적인 유형으로 분해되거나 방폭문 내부에서 폭발됩니다. 그리고 이 정책은 권한이 더 높은 메시지 앱에 적용됩니다. 방폭문에서 반환되는 단순 유형만 검증하면 됩니다. 그리고 복잡하고 위험한 구문 분석은 가장 낮은 권한에서 발생합니다.

    그러면 메시지가 인터넷을 통해 메시지 앱으로 도착하게 되는데, 어떠한 구문 분석이나 처리도 시도하지 않고, 안전한 방폭문 내부의 방폭문으로 직접 보냅니다. 이제 이미지를 처리하고 분석할 시간입니다. 기억하시겠지만, 공격자가 보낸 것일 수도 있습니다. 당연히 대다수의 경우 이미지는 유효합니다. 그리고 메시지는 잠재적으로 복잡한 유형에서 이를 변환합니다. 훨씬 더 간단한 형식으로 변환하여 유효성 검사를 거치고 사용자에게 표시할 수 있도록 합니다. 이미지가 유효하지 않은 경우 오류가 발생합니다. 메시지 하나로 트래픽이 끊깁니다. 공격자가 Blast Door의 취약점을 성공적으로 악용할 수 있다면, 하지만 그것들은 두 번째 과정 안에 포함되어 있습니다. 메시지 데이터베이스나 시스템의 나머지 부분에 접근할 수 없습니다.

    따라서 블래스트 도어는 이제 메시지에 이미지를 다시 표시해야 합니다. 여기서 중요한 것은 우리가 고려해야 할 사항이라는 점입니다. 보안 격리 프로세스가 손상될 수 있습니다. 따라서 해당 시스템을 통해 전송되어 메시지로 다시 전송되는 모든 데이터는 신뢰할 수 없습니다. 성공적으로 변환된 이미지일 수도 있습니다. 또는 공격자의 통제 하에 있는 완전히 악의적인 데이터일 수도 있습니다.

    그러므로 가장 중요한 것은 이 아키텍처의 특징은 메시지가 안전하게 전달된다는 것입니다. 또한 수신한 데이터가 올바른 이미지 형식인지 안전하게 검증합니다. 그리고 우리가 기대하는 형식으로, 그리고 이는 메모리 안전성을 확보한 기존 전략과 기존 전략을 결합한 것입니다. 신속하고 공격 표면 감소. 해당 검증을 안전하게 수행하려면 그리고 필요한 최소한의 코드만 노출합니다. 이미지 유효성 검사가 완료되면, 해당 내용을 녹취록에 포함시켜도 안전합니다.

    이는 Apple 격리 전략을 사용하는 여러 사례 중 하나일 뿐입니다. 가장 보안에 민감한 코드베이스에서.

    마지막으로, 다섯 번째 옵션은 찾는 것입니다. 코드에서 가능한 한 많은 취약점을 제거합니다. 다른 전략들을 단독으로 추진하면서 가능한 한 많은 것을 추구합니다. 그것만으로는 공격을 막기에 충분하지 않습니다. 하지만 가장 취약한 부분을 찾아내는 데 효과적일 수 있습니다. 공격자들이 그러하듯이 가장 쉽게 얻을 수 있는 목표를 파악하는 것이죠. Apple 에서는 수동 방식을 비롯한 다양한 방법을 사용합니다. 또한 코드의 취약점을 찾는 데 도움이 되는 자동화된 기술도 사용합니다. 저희는 개발 과정 중과 개발 후 모두 코드 감사를 실시합니다. clang 정적 분석기를 사용하여 사람의 검토를 지원합니다. 그리고 지속적 통합 워크플로우에서도 마찬가지입니다. 우리는 퍼징이라는 기술을 활용하는데, 이는 도구가 자동으로 많은 파형을 생성하는 기술입니다. 취약점을 우연히 발견하기 위해 프로그램에 많은 입력값을 제공하는 행위. 주소 소독제와 같은 도구 스레드 새니타이저는 코드 디버깅뿐만 아니라 다른 여러 면에서도 도움이 될 수 있습니다. 뿐만 아니라 개발 과정에서도 취약점을 사전에 찾아내는 것도 중요합니다. 그리고 퍼징과 같은 기법과 함께 사용됩니다.

    그러니까 Apple 계층화 접근 방식을 생각하는 방식에 대한 틀이 있는 거죠. 메모리 안전성을 확보하는 코드로 만들 수 있습니다. 그리고 제가 가진 모든 도구를 사용할 수 있습니다. 이상적으로는 버그가 발생하지 않도록 하기 위해 방금 이야기한 내용입니다. Swift 와 같은 메모리 안전성이 확보된 언어를 사용하여 취약점을 공격 대상에서 제외하여 공격 가능성을 줄입니다. 사용 가능한 표면. 취약점을 악용할 수 있도록 코드에 완화 조치를 적용하세요.

    악용으로 인한 피해를 최소화합니다. 보안 강화 확장 프로그램을 사용하다가 이런 일이 발생하는 경우 복잡한 구문 분석을 수행하기 위해서입니다. 마지막으로, 식별하십시오. 그리고 코드에서 버그를 최대한 많이 제거하세요. 다른 전략들을 추진하는 동안 가능한 한 그렇게 하십시오.

    이제 데본에게 마이크를 넘기겠습니다. 애플에서 보안 관련 언어 및 도구 개발을 주도하는 인물. 감사합니다.

    고마워요, 마크. 안녕하세요, 저는 데본 코글란입니다. 저는 Apple 에서 개발자 보안 도구 그룹을 이끌고 있습니다.

    Xcode 신중하게 선별된 다양한 보호 기능을 제공합니다. 앱에 최첨단 보안 기능을 제공합니다. 각각의 보호 기능과 활성화 방법에 대해 자세히 설명드리겠습니다. 그리고 최대한의 보호 기능을 제공하기 위해 이러한 요소들을 어떻게 조합해야 하는지 설명하십시오.

    보안이란 메모리 안전성을 확보하기 위한 절충점을 찾는 것입니다. 가장 중요한 절충점은 보안상의 이점입니다. 그리고 코드 변경 및 테스트와 같은 엔지니어링 작업도 포함됩니다.

    장단점을 그래프로 나타내고, 세로축에 이점을 표시한다고 생각해 보세요. 수평적 도입 용이성.

    일부 보호 조치는 적용하기 쉽지만 효과는 떨어집니다.

    다른 방법들은 더 어렵지만 더 높은 보안을 제공합니다.

    절충점을 찾는다는 것은 최소한의 노력으로 최대한의 효과를 내는 것을 의미합니다. 최대한의 이익을 얻으면서.

    오른쪽 위 모서리가 바로 최적의 위치입니다.

    Apple 의 목표는 하드웨어와 운영 체제를 긴밀하게 공동 설계하는 것입니다. 그리고 그러한 최적점에 가까운 보호 기능을 제공하는 프로그래밍 언어들, 이 모든 것을 우수한 성능을 유지하면서 해냅니다.

    예를 들어, 메모리 무결성 강제는 강력한 보안 기능을 제공합니다. 훨씬 낮은 도입 비용으로 또한 소프트웨어만으로 보호하는 것보다 성능이 더 뛰어납니다.

    저는 서로 다른 네 가지 유형의 보호 조치에 대해 설명하겠습니다.

    제품 출시 전에 보안 취약점을 찾아낼 수 있도록 도와주는 버그 탐지 도구입니다. 더욱 강력한 보안 도입을 위한 기반을 마련합니다.

    앱 전체 보호 기능은 앱 전체의 보안을 강화합니다. 버튼 클릭 한 번으로 해결되는 경우가 많습니다. C 및 C++ 코드 강화 이는 기존의 안전하지 않은 코드 기반에 경계 안전성을 추가하는 데 도움이 될 것입니다. 그리고 Swift 는 완벽한 메모리 안전성을 제공합니다.

    이것들은 마크가 설명했던 것과 동일한 전략들입니다. 하지만 저는 여러분이 그것들을 실행하는 데 사용할 수 있는 실제 기술에 대해 자세히 설명하겠습니다. 마크는 새로운 코드베이스에 대해 보호 수준이 가장 높은 것부터 낮은 것 순으로 정렬했습니다. 거기서부터 시작하면 됩니다. 앱 개발 초기부터 전체 앱에 최고 수준의 보안을 제공합니다.

    하지만 보안을 개조할 때는 이미 공격을 받고 있는 기존 앱에, 지금 어떤 보호 조치를 적용할 수 있는지 전략적으로 접근하는 것이 중요합니다. 시간이 좀 걸릴 것입니다.

    저는 그것들에 대해 이야기하겠습니다. 배포가 더 쉬운 신속한 보안 강화 조치부터 순서대로 도입 여부를 결정하십시오. 실제로 적용하는 데 더 오랜 시간이 걸릴 정도로 매우 강력한 보호 조치입니다. 저는 여러분이 이러한 다양한 기술들을 이해하고 활용할 수 있도록 도와드리겠습니다. 이렇게 하면 앱의 보안을 최대한 강화할 수 있습니다.

    버그 발견 도구부터 시작하겠습니다.

    이것들은 출시된 앱에서 실행되는 활성 보호 기능이 아닙니다. 대신, 그것들은 빌드 단계에서 사용됩니다. 또한 제품 출시 전에 버그를 발견할 수 있도록 디버깅 시간을 제공합니다. 그들은 또한 길을 열어줍니다. 버그를 조기에 발견하여 기술 도입을 더욱 활성화합니다.

    이 도구들은 우측 아래 사분면에 있습니다.

    사용하기 쉽습니다. 실행하고 바로 문제 해결을 시작하세요.

    그들은 수정 가능한 버그를 찾아내지만, 모든 버그를 찾아낼 수는 없습니다. 따라서 예방 차원에서는 매우 효과적이지만, 다른 보호 조치들을 도입하는 것이 매우 중요합니다. 나중에 얘기할게요.

    다행인 점은 이러한 도구를 실행하면 그 작업을 더 쉽게 할 수 있다는 것입니다.

    제가 먼저 살펴볼 버그 탐지 도구는 새니타이저입니다.

    그들은 당신의 앱을 다시 컴파일합니다. 앱 실행 중에 버그를 찾는 데 도움이 되는 추가 계측 기능이 포함되어 있습니다. 그들은 C 기반 언어와 Swift 위해 일합니다.

    손 소독제의 가장 큰 장점은 바로 효과가 매우 좋다는 점입니다. 오탐이 거의 없습니다. 검사 도구가 버그를 보고하면 버그가 있는 것입니다.

    주소 검증 도구는 추적을 통해 메모리 보안 버그를 찾아냅니다. 어떤 메모리 위치가 유효하고 어떤 메모리 위치가 유효하지 않은지 판단합니다.

    마크가 지적한 것과 같은 버퍼 오버플로우를 찾아내는 데 탁월합니다. 앞서 보여드린 것처럼, 버그 수정 후 사용하세요. 프로그래머가 메모리를 해제했지만 실수로 유효하지 않은 포인터를 남겨둔 경우.

    이 도구는 힙과 스택뿐만 아니라 전역 변수에서도 메모리 손상을 찾아냅니다.

    또한 메모리가 할당되고 해제된 위치에 대한 역추적 정보를 제공합니다. 버그를 빠르게 수정하는 데 도움이 됩니다.

    스레드 새니타이저는 발생하는 데이터 경쟁을 찾아냅니다. 한 스레드가 간섭할 때 두 스레드 간에 동기화가 이루어지지 않은 상태에서 다른 스레드가 메모리에 접근하는 경우.

    이는 자동 참조 카운팅 환경에서도 메모리 손상을 초래할 수 있습니다.

    다음은 clang 정적 분석기입니다.

    앱을 실행하지 않고도 버그를 찾아냅니다. 대신, 프로그램 내에서 가능한 경로를 시뮬레이션합니다. 즉, 버그를 찾기 위해 테스트 커버리지가 필요하지 않다는 뜻입니다. 하지만 단점은 이 도구가 오탐을 일으킬 수 있다는 것입니다. 즉, 버그가 없는데도 버그라고 보고할 수 있다는 뜻입니다.

    이 분석기는 C, C++, Objective-C 지원합니다.

    이 프로그램은 버퍼 오버플로우를 포함하여 보안에 민감한 여러 버그를 찾아냅니다. 동결 후 사용, 초기화되지 않은 메모리 사용, 안전하지 않은 API 사용 등이 이에 해당합니다.

    대상 빌드 설정에서 이러한 검사를 활성화하세요. 그런 다음 제품 메뉴에서 '분석'을 선택하여 분석기를 실행하십시오.

    분석기가 버그를 발견하면, 이 기능은 문제와 그 문제가 발생하는 제어 흐름 경로를 보여줍니다.

    화살표는 버그가 발생하는 프로그램 경로의 각 단계를 보여줍니다. 그리고 메모에는 여정 중 발생한 주요 사건들이 기록되어 있습니다. 예를 들어, 사용 사례에서. 해제 후, 경로에는 메모리가 할당되고 해제되는 위치가 표시됩니다. 그리고 나중에 사용되었습니다.

    이렇게 하면 취약점을 쉽게 이해하고 수정할 수 있습니다.

    주소 소독제, 실 소독제 그리고 Clang 정적 분석기는 핵심적인 버그 발견 도구입니다. 여러분의 코드 개발을 돕기 위해서입니다. 빌드 및 테스트 시점에 사용하십시오. 그들은 당신이 설치한 벌레 중 일부는 찾아내겠지만, 전부 찾아내지는 못할 겁니다. 달리기. 이러한 도구들은 달리기를 더 쉽게 만들어주는 훌륭한 첫걸음입니다. 앱에 더욱 강력한 보안 기능을 도입하세요. 그리고 분명히 말씀드리지만, 아직 해야 할 일이 더 많습니다. 하지만 이는 추가적인 필수 보호 조치를 마련하는 길을 열어줍니다.

    다음으로는 앱 전체 보호 기능에 대해 설명하겠습니다. 이러한 보안 조치는 앱 전체에 탁월한 기본 수준의 보안을 제공합니다. 코드, 라이브러리 및 시스템 프레임워크를 포함합니다. 간편하게 추가할 수 있으며 보안을 크게 강화해 줍니다.

    타입 지정자 하드웨어를 활용한 다섯 가지의 앱 전체 보호 기능에 대해 설명하겠습니다. 메모리 태깅, 포인터 인증, 읽기 전용 메모리 그리고 향상된 보안 확장 기능.

    첫 번째 전체 애플리케이션 보호 방법은 타입 지정자(typed allocator)를 사용하는 것입니다. 이는 사용 후 해제 공격으로부터 보호하는 새로운 시스템 할당자입니다. 오른쪽 상단 모서리의 최적의 위치에 있어서 정말 훌륭합니다.

    보호 기능이 뛰어나고 입양하기도 매우 쉽습니다.

    사용 후 해제 버그는 메모리 손상의 한 형태입니다. 프로그램이 메모리를 할당한 다음 해당 메모리를 고정시키는 경우, 하지만 실수로 포인터를 매달아 놓은 채로 남겨둡니다. 해방된 기억의 유형을 희생자라고 부릅니다.

    공격자는 프로그램 조작을 통해 매달린 포인터를 악용합니다. 다른 유형을 할당합니다. 같은 장소에 있는 공격자, 그런 다음 피해자 포인터가 공격자의 데이터에 접근하도록 만듭니다. 마치 피해자 유형인 것처럼. 이는 타입 혼동입니다. 공격자가 피해자를 속여 후퇴하게 만들 수 있다면. 공격자. 공격자는 포인터를 이용하여 데이터를 제어했습니다. 의도치 않은 메모리 변경이나 예기치 않은 코드 호출이 발생할 수 있습니다.

    타입이 지정된 할당자를 사용하면, 컴파일러와 운영체제는 함께 작동합니다. 서로 다른 유형을 확률적으로 할당하여 유형 혼동을 방지합니다. 서로 다른 메모리 영역에 저장됩니다.

    가해자 할당에서 피해자는 서로 다른 범주에 속할 가능성이 높습니다. 따라서 공격자는 타입 혼동에 의존할 수 없습니다.

    아주 훌륭한 게시물이 있습니다. 차세대 보안을 향한 Apple 보안 연구 블로그 Xnu 메모리 안전성은 다음과 같습니다. 이 접근 방식을 커널에 적용하는 방법에 대해 매우 자세하게 설명합니다.

    형식 지정자 할당자를 활성화하려면. 서명 및 기능 편집기로 이동합니다. 향상된 보안 기능을 추가하고 빌드 설정을 활성화합니다.

    오늘 바로 켜세요. 오용에 대한 매우 강력한 보호 기능을 제공합니다. 취약점을 무료로 제공한 후. 체크박스 하나만 선택하고 앱을 다시 컴파일하면 됩니다.

    두 번째 유형의 전체 앱 보호 방법은 하드웨어 메모리 태깅입니다. 버퍼 오버플로 및 사용 후 해제 버그에 대해 매우 강력한 효과를 발휘합니다. 그리고 힙에 할당된 메모리.

    이는 타입이 지정된 할당자와 함께 작동하도록 설계된 CPU 기능입니다. 또한 커널의 태그 기밀성을 통해 메모리 무결성을 강화합니다.

    iPhone 17, iPhone 에어에서 사용 가능합니다. M5 기반 Mac 및 Vision Pro도 포함됩니다.

    하드웨어 메모리 태깅은 바로 그 최적점, 즉 우측 상단에 매우 가깝게 위치합니다. 높은 보호 기능을 제공하며, 설치가 간편합니다. 이 모든 것을 낮은 성능 오버헤드로 유지하면서 수행합니다.

    메모리 손상을 방지하는 방법은 다음과 같습니다.

    타입이 지정된 할당자는 각 포인터와 각 할당에 태그를 연결합니다.

    그런 다음 CPU는 태그와 포인터가 일치하는지 확인합니다. 그리고 메모리의 태그가 일치합니다. 그렇지 않다면, 이는 해제 후 사용 버그 또는 버퍼 오버런을 나타냅니다. 따라서 하드웨어는 메모리 손상을 방지하는 대신 안전하게 오류를 포착합니다.

    버퍼 오버플로우의 예시를 보여드리겠습니다.

    피해자 포인터는 자신이 가리키는 메모리와 일치하는 태그를 가지고 있습니다. 공격자 포인터도 마찬가지입니다. 버퍼 오버런이 발생하면 공격자는 공격자 포인터를 통해 피해자 메모리로 오버플로우를 일으킵니다. 하지만 공격자 포인터에는 하나의 태그가 있고 피해자 메모리에는 다른 태그가 있으므로, CPU는 공격이 계속되는 것을 허용하는 대신 불일치를 감지합니다.

    메모리 태그 불일치로 인해 앱이 충돌합니다. 따라서 메모리 태깅 진단이 활성화된 상태에서 보호 테스트를 활성화하기 전에 주소 살균제와 실 살균제 항목에도 같은 내용이 있습니다.

    그런 다음 메모리 손상을 수정하십시오.

    하드웨어 메모리 태깅을 활성화하는 방법에 대한 자세한 내용은 다음을 참조하십시오. 개발자)에서 "메모리 무결성 강제 적용으로 앱 보안 강화" 영상을 시청하세요.

    이제 보안 할당자와 하드웨어 메모리 태깅이 활성화된 경우에도 마찬가지입니다. 일부 메모리 손상 버그는 여전히 악용될 수 있습니다.

    앱 전체를 보호하는 세 번째 유형은 포인터 인증입니다.

    포인터 인증 방식에서는 하드웨어가, 컴파일러와 운영체제는 모두 함께 작동합니다. 앱의 제어 무결성을 강화하여 심층적인 보안을 제공합니다.

    이 기능은 iPhone 10 S 이상 모델과 모든 Apple Silicon Mac에서 사용할 수 있습니다.

    제어 흐름 무결성 공격에서, 공격자는 메모리 손상을 악용하여 앱 제어권을 탈취합니다.

    이로 인해 프로그램은 개발자 의도하지 않은 예기치 않은 상태에 놓이게 됩니다.

    마크가 앞서 설명했던 스택 버퍼 오버플로를 떠올려 보세요. 공격자가 암호 버퍼를 오버플로우시킨 경우 근처의 함수 포인터를 덮어쓰려면.

    매우 긴 비밀번호를 입력함으로써, 공격자는 함수 포인터의 값을 변경할 수 있습니다. 그들이 원하는 것은 무엇이든 할 수 있었다. 그러면 프로그램 내의 어떤 함수든 호출할 수 있게 됩니다. 예상치 못한 상황으로 이어진다.

    포인터 인증을 사용합니다.

    CPU는 포인터에 암호학적 서명을 합니다. 그리고 사용하기 전에 인증을 거칩니다. 포인터의 시그니처가 예상과 일치하지 않으면, 하드웨어는 예기치 않은 코드를 호출하는 대신 안전하게 트랩을 발생시킵니다.

    버퍼 오버플로우 예시에서. 이렇게 하면 공격자가 임의의 함수를 호출하는 것을 방지할 수 있습니다.

    포인터 인증은 메모리 무결성 강제와 잘 어울립니다. 보호의 최후의 보루로서.

    이는 혜택 채택 차트의 중심에 확고히 자리 잡고 있습니다. 보호 기능은 훌륭하지만, 도입하는 데 약간의 노력이 필요할 수 있습니다. 특히 복잡한 C++ 코드베이스에서,

    그러니 앱을 철저히 테스트하세요. 충돌이 발생하지 않도록 활성화한 후 사용하세요.

    또한 타입이 지정된 할당자와 함께 사용할 때 가장 효과적이기 때문입니다. 하드웨어 메모리 태깅, 포인터 인증을 다루기 전에 먼저 이러한 사항들을 채택하십시오.

    범용 바이너리를 구축해야 합니다. arm64 슬라이스와 arm64 e 슬라이스를 모두 포함하는 것, 하드웨어 지원이 없는 구형 기기에서도 앱을 실행할 수 있도록 하기 위함입니다.

    즉, 앱에 사용되는 모든 라이브러리도 유니버설 라이브러리여야 합니다.

    따라서 벤더에서 제공하는 바이너리 라이브러리나 프레임워크에 의존하는 경우, 해당 종속성의 범용 버전을 얻으려면 그들과 협력해야 합니다.

    네 번째 보호 조치는 읽기 전용 플랫폼 메모리입니다.

    동적 로더는 앱에서 코드를 로드하는 역할을 합니다. 그리고 그 라이브러리들 때문에 공격자들이 접근할 수만 있다면 매우 매력적인 공격 대상이 됩니다. 동적 로더의 메타데이터를 손상시키기 위해, 그들은 이를 이용해 당신의 애플리케이션을 완전히 제어할 수 있습니다.

    읽기 전용 플랫폼 메모리는 공격자가 해당 데이터를 수정하는 것을 방지합니다. 따라서 동적 로더 자체만이 이를 변경할 수 있습니다. 이 제품은 뛰어난 보안 보호 기능을 제공하며 도입이 매우 간편합니다.

    대부분의 앱은 호환성을 위해 변경할 필요가 없습니다.

    호환성을 보장하기 위해. 시스템 API를 사용하여 De Wilde 및 Objective-C 런타임 메타데이터를 수정하세요. 직접 수정하지 마세요.

    앱 전체의 마지막 유형 보호 기능은 프로세스 외부 강화 보안 확장 기능입니다.

    마크가 설명했듯이, 이러한 접근 방식은 일종의 봉쇄입니다. 이는 매우 강력한 보안상의 이점을 제공합니다. 하지만 이를 실행하려면 어느 정도 투자가 필요합니다.

    이를 적용하려면 신뢰할 수 없는 데이터를 처리하는 코드를 확장 프로그램으로 옮기십시오.

    그런 다음 Secure System XPC API를 사용하여 메인 앱에서 데이터를 전송하세요. 확장 프로그램에서 신뢰할 수 없는 데이터를 처리합니다. 결과를 메인 앱으로 다시 전달하고 유효성을 검사해야 합니다.

    이제, 봉쇄는 공격자가 다음을 수행할 수 있다는 것을 전제로 합니다. 메모리 손상을 악용하여 확장 기능을 무력화시키려고 합니다.

    목표는 공격자를 해당 프로세스 내에 가두는 것입니다. 따라서 그들은 메인 애플리케이션의 데이터에 접근할 수 없을 것입니다.

    이를 도입하려면 앱의 어떤 부분이 신뢰할 수 없는 데이터를 처리하는지 평가해야 합니다.

    코드베이스를 리팩토링하여 해당 부분들을 별도의 프로세스로 분리하세요. 그리고 확장 프로그램의 응답을 검증합니다. 믿지 마세요.

    이는 다른 보호 전략을 보완하는 역할을 합니다. 그것은 그것들을 대체할 수 없습니다. 그러므로 앱 전체에 메모리 무결성 강제 적용을 활성화한 후에 적용하십시오. 그리고 인수분해하는 데 시간이 다소 걸릴 수 있습니다. 포인터 인증과 병행하여 진행하십시오.

    앱 전체 보호는 여러 단계 중 일부에 불과합니다. 또는 Xcode 에서 몇 가지 단계를 거쳐 도입할 수도 있습니다. 타입 지정 할당자 하드웨어 메모리 태깅, 포인터 인증을 활성화합니다. 그리고 읽기 전용 플랫폼 메모리입니다. 향상된 보안 기능을 도입함으로써.

    그런 다음 향상된 보안 확장 프로그램을 만드세요.

    앱 전체 보호 기능을 도입하세요 앱 전체에 강력한 기본 보안 수준을 제공하기 위해서입니다.

    그러한 보호 조치는 훌륭합니다. 하지만 앱에 공격 표면이 존재한다면 더 강력한 보호 조치가 필요합니다. C 기반 언어에서.

    홀랍을 입양한 후, 보호 조치는 더욱 강력한 접근 방식을 적용합니다. 신뢰할 수 없는 입력을 처리하는 안전하지 않은 코드베이스의 경우.

    Xcode C와 C++ 모두에 대한 보호 기능을 제공합니다.

    C++부터 시작하겠습니다.

    대부분의 코드베이스는 컨테이너 클래스에 표준 라이브러리를 사용합니다. 그리고 널리 사용되는 다른 추상적인 개념들. C++ 표준 라이브러리 강화는 라이브러리 범위를 벗어난 접근으로부터 보호합니다. 그리고 표준 span 및 vector와 같은 클래스가 있습니다. 메모리 손상을 방지하는 대신 안전하게 오류를 포착합니다.

    표준 라이브러리를 광범위하게 사용하는 코드베이스의 경우, 보안 강화는 보안 도입 트레이드오프의 우측 하단 사분면에 위치합니다. 설치가 매우 간편하고 확실한 보호 기능을 제공합니다.

    더욱 강력한 보호를 위해. Xcode의 C++에서 바운드 안전 버퍼 사용 옵션은 더 강력한 보장을 제공합니다.

    이 모드에서 컴파일러는 안전하지 않은 원시 포인터 연산을 거부합니다. 대신, 관용적인 라이브러리 추상화를 사용해야 합니다. 일반적인 span, string, vector와 같습니다.

    이러한 방식으로 컴파일 시간 검사들을 결합하면 원시 포인터 연산 및 런타임 보호를 방지하기 위해, 강화된 C++ 표준 라이브러리는 언어에 경계 안전성을 제공합니다.

    하지만 C++와는 달리 C는 다음과 같은 고수준 언어 기능을 가지고 있지 않습니다. 라이브러리 추상화를 쉽게 사용할 수 있도록 연산자 오버로딩을 활용합니다. 경계 안전 포인터 연산을 위해.

    이러한 공백을 메우기 위해 Apple C 언어에 새로운 언어 확장 기능을 개발했습니다. 경계선 안전 직접 그리고 이 확장 기능을 언어 표준에 통합하는 것을 추진하고 있습니다.

    안전한 인덱싱 작동 방식은 다음과 같습니다. 포인터에 값을 입력하려면 포인터가 가리키는 메모리 영역의 경계에 대한 정보가 필요합니다. 따라서 안전을 확보하기 위해 컴파일러는 오류를 발생시켜 해당 영역에 대한 인덱싱을 방지합니다. 포인터의 범위를 결정할 수 없을 때 발생합니다. 그런 다음 주석에 범위를 추가할 수 있습니다. 컴파일러에게 경계를 결정하는 방법을 알려줍니다.

    또한 런타임 시 안전하게 오류를 처리하기 위해 경계 검사를 삽입합니다. 경계를 벗어난 접근 시.

    이와 같이 프로그래머가 제공한 주석을 조합하면 됩니다. 컴파일러가 생성하는 런타임 경계 검사를 통해 경계 안전성을 확인할 수 있습니다.

    Xcode C 및 C++ 경계 안전성 기능은 다음과 같습니다. 사분면의 왼쪽 상단 모서리에 있습니다. 그들은 강력한 보증을 제공합니다. 취약점 유형 전체를 제거함으로써, 하지만 소스 코드 수정이 필요합니다. 앱 전체 보호 기능을 적용한 후에 이러한 보호 기능을 적용하세요. 메모리 무결성 강제 적용과 같은 것들 말이죠. 가장 중요한 C 및 C++ 코드에 더욱 강력한 보안을 적용하기 위해서입니다.

    지금까지는, 저는 보호 장치를 개조하기 위해 설계된 도구에 대해 이야기했습니다. 안전하지 않은 C, C++, Objective-C 코드베이스에 적용하세요. 이는 강력한 보호 조치입니다. 하지만 완벽한 메모리 안전성을 위해서는 메모리 안전성이 보장되는 언어가 필요합니다. Swift 는 메모리 안전성을 보장하며 플랫폼 보안 보호 기능을 활용합니다. 운영체제 하드웨어 및 언어 수준에서.

    Swift 62는 새로운 경량 라이브러리 제품군을 제공합니다. 파서에서 저수준 사용을 위해 설계된 추상화 보안과 성능이 매우 중요한 기타 경우.

    예를 들어, 새로운 span 타입 제품군은 접근을 허용합니다. 소유자가 지정되지 않은 메모리를 계속 유지합니다.

    Span은 메모리 안전성이 완벽합니다. 고급 기능을 사용합니다.

    Swift 표준 라이브러리를 사용하면 수명과 바인딩을 모두 보장할 수 있습니다. 안전거리 또한 빠릅니다. 런타임 오버헤드가 전혀 없어야 할 경우에 아주 좋습니다. 평생 안전성과 고도로 최적화된 경계 검사를 위해.

    Swift Span은 컴파일 시간 검사와 수명 주기 안전성을 결합합니다. 또한 런타임 시 경계 안전성 검사를 통해 보안을 강화하고 오버헤드를 최소화할 수 있습니다.

    앱 보안을 위한 두 가지 전략이 있습니다. Swift 가 새로운 코드 형식을 채택함에 따라 기존의 보안에 민감한 코드를 수정하는 작업도 포함됩니다.

    두 가지 전략을 모두 사용하십시오.

    Swift 사용하면 메모리 안전성이 확보된 코드를 쉽게 작성할 수 있습니다. 아직 Swift 로 새로운 코드를 작성하고 있지 않다면 지금 바로 시작하세요. 오늘 당신이 작성하는 코드는 미래에 공격자들이 노리는 표적이 될 것입니다. 그러니 Swift 로 새로운 기능을 작성하세요. 기존 하위 시스템을 리팩토링하거나 현대화할 때, 이번 기회에 Swift 로도 작성해 보세요.

    보안을 강화하려면 기회주의적인 리팩토링을 기다리지 마세요. 대신, 해당 구성 요소를 Swift 로 선제적으로 다시 작성하십시오. 가장 집중해야 할 중요한 영역은 파서입니다. 특히 미디어 및 프로토콜 분야에서 그렇습니다. 복잡한 상태 기계. 객체, 생명 주기 및 신뢰할 수 없는 입력을 처리하는 모든 것을 제어합니다.

    이제 악의적인 공격자로부터 앱을 보호하는 방법을 알게 되었습니다.

    이는 Apple 자사 앱에 사용하는 것과 동일한 보호 조치입니다. 겹겹이 쌓아 올리면 정교하게 만들어집니다. 그리고 코드베이스의 주요 위치에 적용됩니다. 최고 수준의 보안을 제공해 드릴 것입니다.

    이를 적용하려면 Xcode 에서 메모리 무결성을 포함한 향상된 보안 기능을 활성화하십시오. 강제 시행 및 포인터 인증 앱 전체에 대한 기본 수준의 보호 기능을 제공하기 위해서입니다.

    신뢰할 수 없는 입력에 대한 처리 및 향상된 보안 확장 기능을 포함합니다. 경계 안전성 확장 기능을 사용하여 안전하지 않은 C 및 C++ 코드베이스를 보호하세요.

    그리고 모든 새로운 코드에 대해 메모리 안전성이 완벽한 Swift 사용하세요. 그리고 보안 표면을 대상으로 재작성합니다.

    지금은 보안이 그 어느 때보다 중요합니다. 앱과 사용자를 보호하기 위해 지금 바로 다음 단계를 실행하세요. 그리고 그들의 민감한 데이터도요. 감사합니다.

    훌륭한 개요를 제공해주신 데빈과 마크에게 감사드립니다. 잠시 쉬어가겠습니다. 태평양 표준시 기준 오전 11시 25분에 빅서 현지 시간과 온라인으로 다시 만나 뵙겠습니다.

    즐거운 휴식 보내셨기를 바랍니다. 그리고 직접 참석하신 분들은 대화를 나눌 기회가 있었기를 바랍니다. 동료 개발자들과 함께.

    다음 발표에서는 독특한 하드웨어 조합에 대해 다룹니다. 그리고 소프트웨어 보안. 저는 이 작품이 정말 훌륭하다고 생각하며, 여러분도 그렇게 생각하실 거라고 믿습니다. 엔리코를 환영하는 데 함께해 주시기 바랍니다.

    감사합니다.

    안녕하세요. 환영합니다.

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

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

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

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

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

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

    이것들은 소프트웨어에 큰 영향을 미치지 않습니다. 실제로 모든 메모리에서 무결성 강제 적용은 매우 간단합니다. Xcode 에서 몇 번만 클릭하면 됩니다. 상당한 도입 노력이 필요한 다른 기술들과는 대조적으로 그리고 제 작품들은 대부분 수정되지 않은 소프트웨어를 기반으로 합니다. 뭔가 함정이 있을 거야. 그렇지 않았다면 우리는 오늘 여기에 없었을 것입니다. 애플리케이션에서 사용자 지정 메모리 관리를 구현하지 않는 한. 이 주제에 대해 몇 번 언급했는데, 그 의미를 좀 더 자세히 살펴보겠습니다. 응용 프로그램에서 찾아볼 수 있는 패턴은 세 가지입니다. 이로 인해 사용자 정의 메모리 관리가 필요하게 되었습니다. 저는 가능성이 높은 순서대로 여기서 사용하겠습니다.

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

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

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

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

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

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

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

    메모리 손상 문제를 디버깅할 때마다, 당신은 범죄 현장에서 시작하여 잘못 변형된 어떤 기억으로 돌아갑니다. 또는 잘못 사용하면 프로그램이 오작동하게 됩니다. 원인을 알아내기 위해 단서들을 모아보려고 노력합니다. 버그는 무엇이었나요? 손상된 메모리 영역은 어디였나요? 어디에서 유래되었습니까?

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

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

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

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

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

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

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

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

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

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

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

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

    이제 당신 차례입니다.

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

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

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

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

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

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

    걱정 마세요, 이걸 전부 다 읽을 필요는 없어요. 그리고 실제로 시스템 할당자 인터페이스에 대한 호출 측면에 집중해 보겠습니다.

    이것이 바로 타입 격리의 기초가 되는 부분입니다. 사실 모든 작업을 대신해주는 건 컴파일러입니다.

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

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

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

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

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

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

    먼저 래퍼의 변형 유형을 선언합니다. 이 함수는 크기 인자 바로 뒤에 추가적인 유형 ID 인자를 받습니다.

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

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

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

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

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

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

    이러한 맥락에서 핵심 개념은 다음과 같습니다. 이해해야 할 것은 이러한 추상적인 개념들이 삶을 변화시킨다는 것입니다. 재활용되는 물건들의 순환 과정,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    먼저 실행 시 빈 공간이 활성화되어 있는지 확인해야 합니다. 여기에 나와 있는 것처럼 OS 보안 구성 API를 사용하여 그렇게 할 수 있습니다. 하드웨어 메모리 태깅을 활성화한 후, 앱은 해당 기능을 지원하는 기기에서 빈 화면 모드로 실행됩니다. 하지만 빈 값을 지원하지 않는 기기에서도 동일한 코드가 실행되어야 합니다. 의존하는 모든 작업 명령어 세트가 비어있는 아키텍처에서는 오직 다음과 같은 작업만 수행되어야 합니다. 해당 프로세스에서 '비어 있음' 옵션이 실제로 활성화되어 있는지 확인한 후.

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

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

    사용 가능한 API에 대한 간략한 개요를 알려드리겠습니다. 각 위치에 다시 태그를 지정하는 간단한 예를 살펴보겠습니다. 해당 리소스가 우리 할당자에게 다시 반환될 때.

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

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

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

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

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

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

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

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

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

    포인터 인증을 사용하면 CPU와 운영 체제는 포인터의 암호화 서명을 생성합니다. 그런 다음 그들은 해당 서명을 포인터 자체에 삽입합니다. 이러한 서명을 통해 하드웨어는 포인터의 유효성을 확인할 수 있습니다. 사용되기 전에 코드가 신뢰의 사슬을 갖게 됩니다. 포인터가 사용될 당시의 값을 모든 역추적하여 연결합니다. 원래 값으로, 그리고 포인터 인증은 이러한 포인터를 계속해서 보호합니다. Miis를 사용하는 다른 애플리케이션에서도 마찬가지입니다. 메모리 태깅 확장 기능. 서명을 투명하게 조정함으로써 기존 태그를 수용하기 위한 인증 작업, 추가 태그.

    이 모든 것이 갖춰지면 공격자가 포인터를 손상시키려고 시도할 때, 서명이 더 이상 유효하지 않으며 신뢰의 사슬이 끊어졌습니다.

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

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

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

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

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

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

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

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

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

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

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

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

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

    이러한 상호작용은 간접적인 접근 방식을 통해 이루어지며, 이는 공격자에게 매력적입니다. 이러한 각 계층은 독립적으로 공격받을 수 있기 때문입니다.

    그래서 Swift 와 C++에서는, Objective-C 이 과정의 각 단계에서 보호되었습니다.

    이 체인에 있는 각 포인터에 대한 서명을 생성할 때, 우리는 객체의 유형, 식별 정보 등을 포함합니다. 또는 객체의 위치, 심지어 대상 메서드의 유형까지도 알 수 있습니다.

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

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

    이유를 알아보기 위해 첫 번째 인증 단계에 집중해 보겠습니다.

    각 서명에 객체의 위치 정보를 포함시킴으로써, 저희는 해당 서명이 오직 이 장소에서만 유효하도록 조치했습니다. 메모리 보안 오류를 이용하여 공격자가 접근하는 것을 방지하는 메모리 내 보안 기능 한 객체를 다른 객체 위에 복사하는 것.

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

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

    지금까지는 여러분이 받을 수 있는 최고 수준의 보호에 대해서만 다뤘습니다. 포인터 인증을 사용합니다. 훨씬 더 심층적인 배열이지만, 여러분이 실제로 볼 수 있는 것은 아닙니다.

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

    자, 여러분의 애플리케이션에서 입양 절차를 시작하기 전에 말이죠. 임베드하는 모든 라이브러리가 다음 조건을 충족하는지 확인해야 합니다. 또는 포인터 인증을 지원하는 링크입니다.

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

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

    그렇게 하려면 '향상된 보안 활성화' 옵션을 선택하면 됩니다. Xcode 프로젝트의 빌드 설정에서 확인하세요. 이를 통해 메모리 무결성 강화 및 포인터 인증이 가능해집니다. 그리고 이렇게 하면, Xcode 자동으로 프로젝트를 구성해 줍니다. 익숙한 ARM 64 슬라이스를 포함하는 범용 바이너리를 빌드합니다. 그리고 하드웨어에서 사용되는 추가적인 64개의 암 슬라이스가 있습니다. 포인터 인증을 지원합니다.

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

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

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

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

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

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

    이러한 작업들이 겹치는 경우가 많기 때문에 악용되는 버그 또한 겹치는 경우가 많습니다. 공격자들이 공격하더라도, 동일한 보호 조치에 의해 저지됩니다.

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

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

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

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

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

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

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

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

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

    이를 진단하는 데 도움이 되도록 하겠습니다. 프로그램이 종료될 때, 생성된 충돌 로그에는 다음과 같은 경우 진단 메시지가 포함됩니다. 오류는 인증 실패로 인해 발생했을 수 있습니다.

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

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

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

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

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

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

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

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

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

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

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

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

    예를 들어, 이러한 복사 작업에 대한 안전한 대안은 다음과 같습니다. 배치 새 항목과 같은 것을 사용하려면.

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

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

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

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

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

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

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

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

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

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

    여기서 그들은 버퍼 오버플로를 이용할 수 있습니다. 오류 처리 함수의 내용을 덮어쓰려면 호출 함수 내에서 오류 처리기를 호출하는 것입니다.

    그러면 해당 오류 처리기가 호출됩니다. 이 프로그램은 공격자가 선택한 명령을 실행합니다. 이제 그들이 당신 애플리케이션의 제어 흐름을 장악했습니다. 그리고 그들은 원하는 코드를 무엇이든 실행할 수 있습니다.

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

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

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

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

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

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

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

    올리버, 필리포, 엔리코, 고마워요. 정말 놀라운 물건이네요. 개발자 센터에 계신 분들을 위한 다음 소식입니다. 점심은 휴게 공간에 마련되어 있습니다. 태평양 표준시 기준 오후 1시 45분에 다시 만나 뵙고 세 가지 훌륭한 강연을 더 들어보겠습니다.

    점심 식사는 즐겁게 하셨기를 바랍니다. 온라인으로 함께해주신 분들께도 감사드립니다. 아침, 점심, 저녁 식사 또는 차 한 잔을 즐겁게 드셨기를 바랍니다. 적절한 일이라면 무엇이든.

    오후 회담을 시작하기 전에, 엔지니어링 팀이 여전히 활동 중이라는 점을 다시 한번 알려드리고 싶었습니다. 온라인으로 질문을 받고 있습니다.

    그럼 오후 프로그램이 시작됩니다. 공유할 프로그래밍 언어가 몇 가지 있습니다. C 및 C++에서 경계 안전성을 구현하는 실용적인 가이드. 부엉이를 환영해 주세요.

    감사합니다. 감사합니다.

    안녕하세요. 저는 보안 도구 팀이고, 제 동료 루이스가 함께할 예정입니다. 오늘 세션은 구속력 있는 안전에 관한 것입니다. 메모리 안전 장치 전체 범주를 제거하는 기술 C 및 C++ 코드의 취약점.

    이번 세션에서 다루는 내용은 다음과 같습니다. 첫째, 실제적인 취약성을 동기로 삼았을 때 채권의 안전성이 왜 중요한지 살펴보겠습니다.

    그렇다면 어떻게 작동하는 걸까요? 왜 채권 안전 장치를 도입해야 할까요? 그리고 이를

    실제로 어떻게 적용할 수 있는지에 대해 알아보겠습니다. 또한 보다 폭넓은 채권 안전 생태계를 구축하기 위한 노력에 대해서도 이야기하겠습니다.

    마지막으로 C++에 대한 접근 방식입니다.

    실제 사례를 하나 보여드리겠습니다. 최근 널리 사용되는 오디오 라이브러리에서 클릭 없이 취약점이 발견되었습니다. 제로 클릭은 공격자가 아무런 경고 없이 임의의 명령을 실행할 수 있음을 의미합니다. 사용자가 아무것도 하지 않아도 코드가 실행됩니다. 대부분의 플랫폼에서 그렇습니다. 이는 공격자가 사용자 몰래 기기를 장악할 수 있도록 합니다. 하지만 Apple 플랫폼에서는 해당 공격은 실패합니다. 왜냐하면 채권 안전 기술이 이러한 종류의 버그들을 만들어냈기 때문입니다. 악용될 수 있는 것입니다. 그리고 오늘날, 여러분은 앱에 바로 그 보호 장치를 구축할 수 있는 도구를 얻게 됩니다.

    메모리 안전성은 여전히 ​​가장 중요한 보안 과제입니다. 시스템 프로그래밍 분야에서. 아마 당신은 이미 열심히 찾고 있을 겁니다. 정적 분석, 코드 정리 도구 및 코드 검토를 사용하여 버그를 수정합니다. 하지만 문제는 공격자들이 계속해서 새로운 버그를 찾아낸다는 것입니다.

    버그 탐지 도구는 유용합니다. 하지만 이것만으로는 공격자 모델을 근본적으로 바꾸기에는 충분하지 않습니다. 취약점 유형 전체를 제거해야만 합니다. 그래야만 더욱 안전하게 보안을 유지할 수 있습니다. 버그가 존재하면 악용될 수 없습니다.

    메모리 보안에 대한 완벽한 솔루션은 다음과 같습니다. Swift 와 같은 메모리 안전성이 뛰어난 언어를 사용하려면, 그리고 그것은 새로운 코드에 있어서 절대적으로 올바른 선택입니다.

    하지만 기존 코드베이스는 전혀 다른 이야기입니다. 때로는 수억 줄의 C 코드가 사용될 수도 있습니다. C++로 완전히 다시 작성하는 데는 수십 년이 걸릴 것입니다.

    하지만 지금 사람들에게 필요한 건 보호입니다.

    실질적인 해결책. 기존 코드는 필수적입니다.

    필요한 것은 취약점 유형 전체를 제거할 수 있는 기술입니다. 단순히 개별 버그를 찾는 것이 아닙니다.

    이러한 기술들은 완전히 새로 작성하는 것보다 도입이 더 쉬워야 합니다.

    그리고 무엇보다 중요한 것은, 점진적으로 적응할 수 있어야 한다는 점입니다. 이제 기다릴 필요 없이 오늘 바로 코드 보호를 시작할 수 있습니다. 대규모 이주 프로젝트를 위해서.

    오늘 오전에 마크는 다섯 가지 서로 다른 주제에 대해 훌륭한 개요를 제공했습니다. 메모리 안전성 버그의 유형. 이 모든 문제들은 중요하지만, 각각 다른 해결책이 필요합니다.

    이번 강연은 균형 유지 안전에 초점을 맞추겠습니다. 이는 평생 안전과 함께 두 가지 가장 큰 문제 중 하나입니다.

    앞서 언급했던 오디오 코덱 취약점, 즉 보안 문제를 기억하시나요? 그리고 이는 전체 메모리 보안 문제의 약 절반을 차지합니다.

    즉, 균형 문제를 해결해야 한다는 뜻입니다. 보안 문제가 해결되면 메모리 보안 문제의 절반이 해결될 것입니다. 그리고 애플의 보호 기능을 사용하여 앱을 보호하는 방법을 보여드리겠습니다. SI를 위한 안전 기술을 발견했습니다.

    앱에 사용할 이미지 필터를 개발한다고 상상해 보세요.

    이 함수는 버퍼와 크기를 입력받아 픽셀들을 순회합니다.

    하지만 여기서 반복 조건을 주목하세요. 크기가 작거나 같습니다. 마지막 단계에서 단 하나의 실수로 인해 발생한 고전적인 사례를 소개합니다. 버퍼 끝을 지나쳐 한 요소를 씁니다.

    이는 단순화된 예시이지만, 이는 정확히 다음과 같은 범위를 벗어난 오류를 나타냅니다. 공격자의 제어 입력과 결합될 경우, 이는 수많은 현실 세계의 악용 사례의 근본 원인이 됩니다.

    바운스 안전 확장 장치 사용법은 다음과 같습니다. C 언어는 바운스 안전성을 통해 이 문제를 해결합니다. 색인 생성에는 반송 정보가 필요합니다. 컴파일러는 포인터의 바운스 값을 알지 못하면 해당 포인터에 접근하는 것을 허용하지 않습니다.

    여기 있는 오류 메시지를 살펴보세요. 컴파일러가 이미지에 반사 정보가 없다고 알려주는 것입니다. 따라서 0이 아닌 인덱스로는 접근할 수 없습니다.

    이 오류는 필요한 바운스 주석을 찾는 데 도움을 줍니다. 이미지가 가리키는 요소의 개수를 컴파일러에게 알려줍니다.

    바로 여기서 '크기에 따라 계산한다'는 말이 등장합니다. 이 포인터가 size 요소를 가리킨다고 컴파일러에게 알려줍니다.

    이제 컴파일러는 범위를 알게 되었습니다.

    메모리에 접근하기 전에 자동으로 경계 검사를 추가합니다.

    경계 안전성 버그가 프로그램 트랩을 발생시키면 범위를 벗어나 쓰기 전에.

    해당 버그는 코드에 여전히 존재하지만 더 이상 악용될 수 없습니다.

    C 프로그램은 포인터를 다양한 방식으로 사용합니다. 따라서 경계 안전성 확장 기능은 일련의 경계를 제공합니다. 주석. 일반적인 포인터 패턴을 보여드리겠습니다. 각 경우에 어떤 주석을 사용해야 할까요?

    먼저 하나의 요소에 대한 포인터부터 시작하겠습니다.

    C와 C++에서 경계 안전 상자를 검토할 때. 분명한 패턴이 있습니다. 대부분의 문제는 배열 인덱싱과 포인터 연산에서 발생합니다.

    이 다이어그램에는 네 개의 정수로 이루어진 배열이 있습니다. 녹색 상자는 인덱스 0부터 3까지의 유효한 요소입니다. 빨간색 상자는 출입 금지 구역입니다. 메모리. 0으로 이루어진 배열에 대한 포인터를 가져옵니다. 첫 번째 요소에서부터 그렇습니다. 그리고 그것은 안전합니다. 하지만 배열 인덱싱이나 포인터 연산을 사용하면, 배열 범위를 벗어나 빨간색 영역에 접근하는 것은 쉽습니다.

    흥미롭게도 C 언어의 대부분의 포인터는 실제로 포인터 연산을 필요로 하지 않습니다. 그들은 단지 이 메시지 t처럼 하나의 대상을 가리킬 뿐입니다.

    배열처럼 값을 증가시키거나 인덱싱하면 범위를 벗어나게 됩니다. 안전하지 않고 불필요합니다.

    역참조가 필요합니다.

    화살표를 사용하여 멤버에 접근합니다. 또는 별표 연산자를 사용하여 직접 역참조할 수 있습니다.

    그리고 그 단 하나의 주석이 바로 그것을 포착하고 있습니다.

    이 포인터는 정확히 하나의 요소를 가리키거나, single일 경우 null을 가리킨다고 합니다. 컴파일러는 포인터 연산과 배열 인덱싱을 방지합니다. 포인터가 해당 객체를 벗어나 실수로 이동하는 일은 없습니다.

    이러한 버그는 컴파일 시점에 발견되었기 때문입니다. 기본적으로 안전합니다.

    네, 대부분의 포인터에는 싱글이 아주 잘 작동합니다. 단 하나의 대상을 가리키는 것들. 하지만 여러 요소를 가리키는 포인터처럼 실제로 인덱싱이 필요한 경우에는 다릅니다. 포인터 연산을 하려면 바운스 정보가 필요합니다. 안전하게 접근할 수 있는 요소의 개수를 알아야 합니다. 유효 범위는 무엇인가요?

    그 반송 정보는 어딘가에서 나와야 합니다. 다행히 대부분의 코드에는 이미 해당 기능이 있습니다.

    프로세스 이미지를 고려해 보세요. 포인터는 크기와 함께 전달됩니다.

    또는 메시지 T를 생각해 보세요. 데이터 포인터는 데이터 크기 바로 옆에 있습니다.

    이 패턴은 포인터를 사용하는 C 함수 경로 크기에서 도처에 나타납니다.

    충돌했습니다. 나란히 보관하세요.

    정보는 이미 존재합니다. 그것을 명확하게 표현할 방법만 있으면 됩니다.

    바로 거기서 'counted by'가 나옵니다. 입력. 이를 통해 이러한 포인터의 경계가 결정되었다고 말할 수 있습니다. 다른 변수에 의해. 당신은 명확하게 말하고 있습니다. 이미 코드에 존재했던 것 중 가장 흔한 어노테이션이 집계되었습니다. 하지만 다른 경계 패턴을 포착하는 다른 방법들도 있습니다.

    약간 변형된 예시를 하나 더 보여드리겠습니다. 이제 그 함수가 void 포인터를 인수로 받는다고 가정해 보세요. 불투명한 직렬화 데이터를 처리하기 위해. 데이터 유형은 알 수 없으며 사용 가능한 바이트 수도 알 수 없습니다.

    구조체에서도 마찬가지입니다. 이제 직렬화된 데이터를 받는다고 상상해 보세요. 이 데이터는 void 포인터입니다. 구조는 알려지지 않았지만, 데이터 크기는 포함된 바이트 수를 나타냅니다.

    여기서는 주석을 사용하여 크기를 조정합니다.

    counted by처럼 요소를 세는 대신 바이트를 셉니다.

    이제 다른 예를 들어보겠습니다. 픽셀 할당 함수는 이미지를 픽셀 배열로 할당합니다. 픽셀의 n개 요소에 대한 포인터를 반환하거나 할당에 실패하면 null을 반환합니다.

    n개 요소로 계산하여 사용 n이 0이 아닌 이상 반환 유형이 잘못됩니다. null을 반환하면 포인터가 n개의 요소를 가리키지 않기 때문입니다. 그것은 아무것도 가리키지 않습니다.

    여기서 counted by 또는 no를 사용합니다. 이것은 N개의 요소를 가리키거나, 그렇지 않다는 것을 의미합니다. 포인터가 null일 수 있지만 카운트가 0이 아닌 경우에 이 어노테이션을 사용하십시오.

    가장 흔한 질문들을 다뤘습니다. 하지만 다른 부모들을 위한 주석이 더 있습니다. 예를 들어 사이즈 5 같은 주석이요. 또는 null 및 Devi 및 기타.

    바인딩된 안전 확장 관련 문서에서 전체 목록을 확인할 수 있습니다.

    이제 바인딩 안전 확장 장치가 어떻게 작동하는지 아셨습니다. 그리고 여러분이 이를 채택해야 하는 이유는 다음과 같습니다.

    두 가지 이유가 있는데, 첫째는 강력한 안전성을 보장하고 둘째는 도입이 실용적이라는 점입니다.

    첫째, 강력한 안전 보장은 컴파일러가 항상 안전하다는 것을 의미합니다. 필요한 잔액 검사를 삽입합니다.

    수년간 개발자들은 다음과 같은 것에 의존해 왔습니다. 유니슨(Unison) 및 포티파이 소스(Fortify Source)와 같은 기회주의적 잔액 확인 도구에 관하여. 그렇습니다. 이러한 도구들은 가치가 있습니다. 하지만 그들은 최선을 다해 벌레를 잡습니다. 마치 끝없이 두더지 잡기 게임을 하는 것과 같습니다. 우리가 놓쳤던 부분을 찾아보세요.

    바운스 안전성은 경기의 흐름을 완전히 바꿔놓습니다. 확실한 확인을 보장합니다. 컴파일러는 안전망 역할을 합니다. 반송 정보가 항상 존재하고 항상 정확한지 확인합니다. 이로써 구조적으로 이러한 취약점 유형이 제거됩니다.

    첫째, 컴파일러는 바운스 정보가 항상 사용 가능하도록 보장합니다. 따라서 포인터에 대한 인덱싱을 시도할 때 바운스(bounce) 현상이 발생하면 컴파일 오류가 발생합니다.

    첫 번째 기능에서. 이미지에 대한 바운스 표기법은 없습니다.

    따라서 컴파일러는 배열 접근을 거부합니다.

    두 번째 함수는 반동을 제공합니다. 코드가 컴파일되고 컴파일러가 반송 검사를 삽입합니다.

    이는 코드가 컴파일되면 경계 검사가 수행된다는 의미입니다.

    네. 이건 제가 가장 좋아하는 기능 중 하나예요. 버퍼를 업데이트했지만 크기 업데이트를 잊어버린 적이 몇 번이나 있나요? 이 확장 기능을 사용하면 컴파일러가 실제로 그 관계를 이해하게 됩니다. 포인터와 크기 변수 사이에, 컴파일 시점과 런타임 모두에서 적용합니다. 즉, 실수로 경계를 벗어날 수 없다는 뜻입니다. 단정.

    위의 예를 보세요. 데이터 포인터는 아래쪽의 데이터 크기와 연결되어 있습니다. 해당 함수는 데이터를 위한 메모리를 할당하지만 데이터 크기를 업데이트하는 것을 잊습니다. 이 흔한 실수는 대개 오래된 크기 값을 남겨두는 결과를 초래합니다. 범위를 벗어난 오류에 대해.

    하지만 이제 컴파일러가 이를 즉시 감지하고 컴파일을 거부합니다.

    이 문제를 해결하려면 포인터와 함께 크기를 업데이트하면 됩니다.

    컴파일 시간 검사 그 이상. 컴파일러는 런타임 검사도 추가합니다.

    크기 필드가 100으로 하드코딩되어 있기 때문입니다. 여기서는, 컴파일러는 100이 실제로 그 안에 들어갈 수 있도록 자동으로 확인합니다. 원래 할당액입니다.

    이러한 안전 보장을 통해, 경계 안전 확장을 실질적으로 채택할 수 있습니다.

    우선, 대부분의 포인터는 주석이 필요하지 않습니다. 스마트 기본 설정은 일반적인 경우를 자동으로 처리합니다.

    또한 Abi 호환성을 유지하면서 이를 점진적으로 조정할 수 있습니다. 호환성을 유지하면서 파일을 한 번에 하나씩 변환할 수 있습니다. 나머지 코드베이스와 함께 사용하세요.

    스마트 기본 설정부터 시작하겠습니다. 메시지 처리 예시로 돌아가서, 이 함수는 단일 메시지 t 객체에 대한 포인터를 인수로 받습니다. 그리고 '싱글'이라는 단어를 추가하여 그 의미를 표현했습니다.

    이러한 패턴이 매우 흔하기 때문에, 경계 안전 확장 기능은 기본값을 단일로 설정합니다. Abi 경계에 대한 포인터를 위해. 함수 매개변수, 구조체 필드, 전역 변수 및 중첩 포인터.

    따라서 이 매개변수에는 주석을 달 필요가 없습니다. 기본적으로 싱글 모드입니다.

    다른 방식으로 계산하고 싶을 때, 예를 들어 특정 값으로 세고 싶을 때만 주석을 달면 됩니다.

    이제 여러분은 이렇게 생각하실지도 모르겠습니다. "어, 그런데..." 모든 로컬 포인터에 일일이 주석을 달아야 하나요? 내 수백만 줄의 코드 중에서요? 답은 절대 아닙니다. 지역 변수가 Abi 경계에서 노출되지 않기 때문입니다. 컴파일러가 정말 훌륭한 일을 해냈습니다. 이 기능은 백그라운드에서 자동으로 해당 포인터를 와이드 포인터로 승격시킵니다. 포인터 연산을 완벽하게 사용할 수 있고, 런타임 시 자동 검사 기능도 제공됩니다. 이렇게 하면 로컬 코드에 주석을 추가하지 않고도 이러한 모든 안전 기능을 얻을 수 있습니다. 그냥 잘 작동합니다.

    다음은 예시입니다. 이미지 처리 함수는 지역 변수를 사용합니다.

    현재 위치를 추적하고 배열의 끝을 표시하기 위해서입니다. 둘 다 자동으로 와이드 포인터가 됩니다. 별도의 주석이 필요하지 않습니다.

    PTR 값을 증가시키면 컴파일러는 경계값도 함께 유지합니다.

    참조를 해제할 때. TR은 주석을 추가하지 않고도 모든 안전 사항에 대해 자동으로 바운스 체크를 수행합니다.

    그리고 이것을 도입해야 하는 가장 실질적인 이유는 다음과 같습니다.

    이는 실제 환경에서 점진적으로 도입될 수 있도록 설계되었습니다. 개발을 일시 중단하고 하룻밤 사이에 방대한 SQL 데이터베이스를 다시

    작성하는 것은 현실적으로 불가능합니다. 이러한 주석은 포인터를 변경하지 않기 때문입니다. 아비 경계에서의 표현. 전면적인 재작성은 필요하지 않습니다. 고도의 보안이 적용된 중요 파일 하나만으로 오늘 바로 보증금 안전성을 확보할 수 있습니다. 그리고 기존의 주석 없는 프로젝트에 바로 연결합니다.

    주석이 없는 API와 같은 실제적인 시나리오가 있을 것입니다. 시스템 헤더는 기본적으로 필요합니다. 이 헤더 파일의 포인터는 안전하지 않은 것으로 간주됩니다. 바운스 정보가 없습니다. 아니요. 부도 수표는 없습니다. 컴파일러는 이를 검증할 수 없습니다.

    하지만 이렇게 하면 바운스 방지 코드가 여전히 컴파일될 수 있습니다. 또한 기존 라이브러리와 상호 운용됩니다.

    다음은 예시입니다. 파일 핸들을 열려면 `apply open` 함수를 호출하여 파일 포인터를 얻습니다.

    해당 파일은 주석이 달린 시스템 헤더에서 가져온 것이기 때문입니다. 컴파일러는 이를 안전하지 않은 포인터로 간주하여 안전한 변수에 할당합니다. f를 저장하세요,

    명시적 변환이 필요합니다.

    이렇게 하려면 단일 매크로에 대해 안전하지 않은 옵션을 사용하십시오. 기본 포인터 유형과 안전하지 않은 포인터 유형을 취합니다. 이는 내가 이러한 사항들을 알고 있다는 것을 의미합니다. 이는 단일 파일 객체를 가리키며, 제가 그에 대한 책임을 지겠습니다.

    목표는 이러한 안전하지 않은 구조를 시간이 지남에 따라 감사하고 제거하는 것입니다. 적절한 주석이 상위 시스템에 추가됨에 따라.

    좋습니다. 이론은 이쯤에서 충분한 것 같죠? 이제 재밌는 부분입니다. 프로젝트에 바인딩 안전 기능을 적용하는 정확한 방법은 다음과 같습니다.

    과정은 다음과 같습니다. 먼저 헤더에 주석을 답니다. 그다음에는 파일을 하나씩 차례대로 살펴보세요. 파일에 바인딩 보안을 활성화하세요. 수정하고, 테스트하고, 디버깅하세요. 모든 파일 작업을 완료했으면 Xcode 에서 바운드 안전성을 전역적으로 활성화하세요.

    각 단계를 하나씩 설명해 드리겠습니다. 첫째, API 계약이 정의된 헤더에 반송 주석을 추가하세요.

    먼저 이 제목을 보세요. 피터 체크 도트 h를 포함하세요. 이는 바운스 안전 주석 및 매크로를 제공합니다.

    그럼 피터를 사용해 보세요. 아비나 다른 싱글을 찾아보세요. 헤더를 구부릴 때. 이 매크로는 소비자가 Abi 포인터를 자동으로 단일 포인터로 처리하도록 합니다. 위험하지 않습니다.

    마지막으로 필요에 따라 'counted by' 또는 기타 바운스 주석을 추가하세요.

    이게 전부입니다. 이제 이 헤더는 바운스 방지됩니다. 다른 바운스 안전 코드가 이 함수를 호출하는 경우, 컴파일러는 코스 사이트에 반송 검사를 삽입합니다.

    다음으로, 소스 파일 하나를 선택합니다. 확장 프로그램을 활성화하세요.

    이렇게 하려면 컴파일러 플래그에 '-f'를 추가하면 됩니다. 해당 기능을 활성화하기 위해 빌드 단계에서 안전성을 확보했습니다. 채택하신 소스 파일에 대해서입니다.

    그런 다음 컴파일하고 컴파일러 진단 결과를 따르십시오. 컴파일러는 누락되었거나 일치하지 않는 주석을 즉시 표시합니다.

    프로세스 이미지에 대한 바운스 안전 기능을 활성화하면 됩니다. 두 번째 진단 예시가 나타납니다.

    첫 번째 조건은 함수 정의가 어노테이션과 일치해야 한다는 것입니다. 헤더 선언에서.

    두 번째 내용은 파라미터 이미지에 바운스 주석이 없다는 것입니다. 따라서 해당 영역에 대한 인덱싱은 허용되지 않습니다.

    매개변수에 크기별 계산을 추가합니다. 두 가지 진단 오류를 모두 해결합니다.

    이제 테스트를 실행하고 런타임 검사를 디버깅하세요.

    함정에 걸렸다면 컴파일러가 잘못된 어노테이션을 호출한 것입니다. 또는 이와 같이 오류 하나가 있는 실제 버그일 수도 있습니다.

    Xcode 즉시 실행을 중단하고 정확히 무슨 일이 일어났는지 알려줍니다.

    위의 참조 범위.

    여기서 논리를 수정하면 코드가 제대로 실행됩니다.

    시험에 합격하면 됩니다. 해당 파일은 보호되어 있습니다.

    나머지 파일은 시간이 지남에 따라 입양할 수 있습니다.

    프로젝트 전체가 준비되면, Xcode 빌드 설정에서 바운스 안전 확장 기능을 활성화하세요.

    그러려면 프로젝트의 빌드 설정으로 이동하세요. 보안 섹션 세트를 찾으십시오. C 언어 확장을 활성화하여 C 언어에서 바운스 안전성을 확보합니다. 네. 그 시점부터는요. 대상 시스템의 모든 C 코드는 보호되어 있으며, 새로 작성하는 코드는 반드시 보안 규칙을 준수해야 합니다.

    이건 단순한 연구 프로젝트가 아니라는 점을 분명히 말씀드리고 싶습니다. 이는 대규모로 입증되었습니다.

    Apple 이미 이 기술을 사용하여 수백만 줄의 실제 운영 코드1를 보호하고 있습니다. Apple 플랫폼을 구동하는 커널의 네트워킹 스택에 있습니다. 내장 오디오 및 이미지 코덱, 보안 부팅 라이브러리가 포함되어 있습니다. N1 네트워킹 칩의 펌웨어 등.

    해당 제품은 현재 고도의 보안 및 민감도 시스템을 통해 고객에게 배송되고 있습니다.

    Apple 이를 통해 매일 수십억 명의 사용자를 보호합니다.

    이제 당신 차례입니다. 이 정보를 활용하여 사용자들을 안전하게 보호하세요.

    당연히 C 언어를 쓰는 사람이라면 성능을 중요하게 생각할 겁니다. 무슨 함정이 있는지 궁금하실 겁니다. 따라서 성능은 커널의 네트워킹 전반에 걸쳐 측정되었습니다. 매 마이크로초가 중요한 스택. 그리고 분명히 말씀드리자면, 이 테스트 동안에는 모든 제어 경로에서 하강 안전 장치가 완벽하게 작동했습니다.

    바인딩 안전 기능이 활성화된 경우, 테스트의 93%는 오버헤드가 완전히 허용 범위 내에 있음을 보여줍니다. 측정 오차 범위.

    실제로 차이가 측정 가능한 몇몇 곳에서도 그 차이는 2% 미만에 머무릅니다. 결론적으로 말하자면, 당신은 최고의 안전성을 확보하게 되는 겁니다. 뛰어난 실용성을 자랑합니다.

    경계 안전성은 코드베이스에 있어 엄청난 이점입니다. 하지만 어디에서나 이용 가능해지면 완전히 판도를 바꾸는 일이 됩니다. 이것이 바로 우리가 국경을 초월한 안전한 생태계를 구축하는 방법입니다.

    목표는 간단합니다. 어떤 플랫폼에서든 사용자를 보호할 수 있어야 합니다. 단순히 사과만으로는 그런 일이 일어나지 않습니다. 바운스 안전 기능은 현재 clang의 Swift 포크에서 오픈 소스로 이미 구현되어 있습니다.

    또한 모든 사람이 사용할 수 있도록 llvM 메인라인에 적극적으로 통합되고 있습니다.

    하지만 그 의미는 거기서 그치지 않습니다.

    Apple C 표준 위원회와 직접 협력하고 있습니다. 채권 안전성을 C 언어 자체에 표준화하기 위해서입니다.

    궁극적으로 이는 모든 C 개발자 에게 안전을 가져다줄 것입니다. 어떤 플랫폼을 대상으로 개발하든 상관없이.

    좋습니다, 이제 루이스에게 C++ 접근 방식에 대해 이야기해 달라고 부탁하겠습니다.

    감사합니다. 안녕하세요 여러분, 제 이름은 루이스입니다. 저는 Apple 에서 C++ 표준 라이브러리 작업을 하고 있습니다. 여기 오게 되어 정말 기쁩니다. 이제 C++ 부분으로 넘어가 보겠습니다.

    C++는 C와 다릅니다. 이미 충분한 정보를 담고 있는 많은 추상화 개념을 제공하고 있기 때문입니다. 안전을 제공하기 위해. 예를 들면, 표준 스팬에는 포인터와 크기가 포함되어 있으므로 유효한 범위를 알 수 있습니다. 접근될 때. 표준의 다른 많은 구성 요소에도 마찬가지입니다. 표준 벡터, 표준 문자열, 표준 배열 등과 같은 라이브러리.

    하지만 C++ 표준은 이러한 API에서 안전성을 강제하도록 요구하지 않습니다. 그리고 실제로 C++ 표준 라이브러리는 역사적으로 그렇게 하지 않았습니다.

    예를 들어, 코드는 다음과 같습니다. 오른쪽은 C 프로세스를 C++로 직접 번역한 것입니다. UL에서 이전에 제시한 이미지 기능입니다.

    이 함수는 원시 포인터 대신 표준 스팬을 사용합니다. 하지만 표준 범위를 사용했음에도 불구하고, 이 코드는 기본적으로 바인딩 안전성을 강제하지 않습니다.

    Xcode 사용하면 이제 이를 변경할 수 있습니다.

    이는 C++ 저장 버퍼라고 하는 두 가지 접근 방식을 사용하여 구현됩니다. 첫째, Xcode 도구를 제공합니다. C++ 코드가 관용적인 표현을 사용하고 있는지 확인하는 데 도움이 됩니다. 버퍼에 접근할 때 표준 라이브러리에서 제공하는 추상화 기능입니다.

    둘째, 이제는 또한 다음과 같은 일이 발생합니다. 강화된 C++ 표준 라이브러리를 활성화할 수 있습니다. API의 오용을 적발하기 위해서입니다.

    이제 코드에서 더 안전한 추상화를 도입하는 데 도움이 되도록 설명드리겠습니다. Xcode 이제 문제가 있는 위치를 알려주는 진단 기능을 제공합니다. 코드에서 버퍼에 접근하는 방식이 관용적이지 않은 부분이 있습니다. 예를 들어, 이 코드는 프로세스 이미지의 한 버전입니다. 원시 포인터를 사용하여 작성된 함수입니다. 이 경우, 새로운 Xcode 진단 도구는 이 코드를 오류로 표시할 것입니다. 왜냐하면 안전하지 않은 원시 포인터를 사용하여 인덱싱하기 때문입니다.

    이를 통해 장소를 찾아낼 수 있습니다. 코드에서 버퍼에 접근할 때 관용적인 구문을 사용하지 않는 부분이 있습니다. 그리고 그 문제를 해결하기 위해서입니다. 이 경우 한 가지 접근 방식은 다음과 같습니다. 표준 span을 사용하여 코드를 다시 작성하면 오류가 사라질 것입니다.

    이제 관용적인 추상화를 사용하는 코드를 실제로 더 안전하게 만들려면, Xcode 강화된 C++ 표준 라이브러리도 제공합니다.

    Xcode 설정에서 활성화하면, 표준 라이브러리는 이미 포함하고 있는 기존 잔액 정보를 사용합니다. 특정 API 사용량을 확인하기 위해서입니다.

    이 예시에서는 표준 스팬을 인덱싱합니다. 강화 기능이 활성화된 경우 기존에 가지고 있는 경계 정보를 사용합니다. 접근 권한이 유효한지 확인하기 위해서입니다.

    만약 인덱스가 유효하지 않다면, 강화된 표준 라이브러리는 프로그램이 종료될 것을 보장합니다. 이는 시스템이 계속 실행되어 잠재적으로 손상될 수 있음을 의미합니다. 또는 앱에 문제가 발생할 수 있습니다. 또한 API의 사용 방식이나 계약 내용은 변경되지 않는다는 점도 주목할 만합니다.

    강화된 표준 라이브러리도 결국 ISO C++ 규격을 준수하는 라이브러리일 뿐입니다.

    강화된 라이브러리가 활성화되어도 Abi는 변경되지 않습니다. 이 모든 것은 코드 변경이 전혀 필요하지 않다는 것을 의미합니다. 추가적인 안전 기능을 활용하기 위해서입니다. 이로써 강화 조치를 쉽게 도입할 수 있게 되었습니다.

    새로운 Xcode 진단 기능과 표준 라이브러리 강화 기능을 모두 활성화하려면 다음과 같이 하십시오. 보안 설정에서 빌드 설정으로 이동하세요. C++에서 바인딩된 안전한 버퍼 사용을 강제하도록 설정합니다.

    경우에 따라 안전하지 않은 구문을 사용하는 기존 코드가 있을 수 있습니다. 하지만 아직은 현대적인 표현을 사용하도록 업데이트할 수 없습니다.

    강화된 표준 라이브러리의 이점을 계속 활용하기 위해 코드에 새로운 오류를 발생시키지 않고 즉시 실행하세요. 강화된 표준 라이브러리만 활성화하려면 다음 경로로 이동하세요. Apple Clang 언어 C++ 빌드 설정에서 그리고 C++ 표준 라이브러리 강화 기능을 활성화하도록 선택합니다.

    또한 이것이 단순히 디버깅 기능이 아니라는 점도 중요하게 알아두어야 합니다. 디버깅 기능은 생산성을 높이는 데 매우 유용합니다. 하지만 이러한 조치만으로는 코드 실행 시 진정으로 더 안전한 코드를 만들기에 충분하지 않습니다. 실제 운영 환경에서 사용 중입니다. 실제로, 강화된 표준 라이브러리를 사용하는 코드는 배포될 목적으로 만들어졌습니다. 생산 및 경화 표준 라이브러리의 해당 기능은 매우 신중하게 설계되어 그 가치를 지니게 되었습니다.

    이렇게 하면 프로덕션 환경에서 코드의 안전성을 높일 수 있습니다. 사용자의 기기에서 실행되고 실제 데이터를 처리할 때, 바로 그곳이 안전이 진정으로 중요한 지점입니다.

    강화된 표준 라이브러리를 사용할 때, 많은 API는 추가적인 안전 기능을 제공합니다. 일반적으로 컨테이너는 API에 접근할 수 있다는 인식이 널리 퍼져 있습니다. 그리고 크기를 직접 조절할 수 있는 컨테이너 수정 API 요구 사항이 강화되었습니다. 실제로 해당 API에는 이미 필요한 정보가 포함되어 있습니다. 그들의 한계를 확인하기 위해, 이러한 API의 오용을 감지하는 것은 직접적인 보안 가치를 제공합니다.

    예를 들어 컨테이너의 인덱싱 연산자가 있습니다. 그들은 예전 방식대로 다시 술집에 돌아왔습니다. 저것들은 모두 굳어졌습니다. 선택적 값에 접근하는 것도 강화되었습니다.

    일반적으로, 검증된 전제 조건은 모두 신뢰할 수 있습니다. ISO C++ 26 표준을 준수하는 구현체인지 확인해야 합니다.

    표준 라이브러리를 사용하는 경우도 몇 가지 있습니다. 기본적으로 검사 기능을 이미 제공합니다. 예를 들어 표준 함수를 호출하는 경우 함수가 이미 비어 있는 경우 예외가 발생합니다. 보안 강화는 이러한 API에 영향을 미치지 않습니다. 보안 강화가 쉬운 다른 API는 다음과 같습니다. 하지만 이는 제한적인 보안 가치만 제공하며, 강화된 보안 기능도 갖추고 있지 않습니다.

    앱 보안 강화로 인한 성능 저하를 최소화하려면, 실제로 보안 가치를 제공하는 검사가 우선적으로 처리됩니다.

    예를 들어, 널 포인터로부터 문자열을 생성하는 것은 기술적으로 정확하지 않습니다. 하지만 실제로는, 이미 세그멘테이션 오류가 발생하여 프로그램이 종료됩니다. 그렇기 때문에 명시적인 검사를 추가하는 것은 보안상 이점이 제한적입니다. 그 경우에는 그렇습니다. 마지막으로, 강화 원칙의 주목할 만한 예외는 반복자입니다. 이터레이터는 일반적으로 충분한 정보를 저장하지 않습니다. 경계 검사를 수행합니다. 해당 정보를 추가하려면 Abi를 변경해야 합니다. 그렇게 되면 입양이 훨씬 더 어려워질 것입니다. 그러한 이유로 이터레이터 접근은 강화되지 않습니다.

    이제 어떤 API가 강화되는지 잘 이해하셨으니, 여러분이 기대할 수 있는 경험에 대해 이야기해 보겠습니다. 강화된 애플리케이션을 개발할 때.

    따라서 보안 강화 검사가 실패하면 Xcode 내부에서 프로그램이 종료됩니다. 강화 검증이 실패한 장소로 이동하게 됩니다. 이는 표준 라이브러리에 포함되어 있습니다. 그런 다음 왼쪽에 있는 스택 프레임 선택기를 사용하여 탐색할 수 있습니다. 자신의 코드로 바꾸세요. 디버깅 콘솔에는 다음과 같은 오류 메시지가 표시됩니다. 실패에 대한 추가적인 맥락 설명입니다. 그런 다음 Xcode 에서 평소처럼 디버깅 워크플로를 사용하여 문제를 이해할 수 있습니다. 그리고 문제를 해결하세요.

    배송 앱에서는 상황이 조금 다릅니다. 연결할 디버거가 없으므로,

    해당 프로그램은 트랩에 의해 종료될 것입니다. C 언어의 경계 안전성 확장이 C++에서 일어나는 것과 마찬가지입니다. C 언어에서와 마찬가지로, 이 메커니즘이 가장 빠릅니다. 프로그램을 종료하는 가장 안전한 방법은 다음과 같습니다. 잠재적으로 악의적인 공격자에게 선택지를 거의 제공하지 않기 때문입니다. 어설션이 실패한 후 프로그램의 제어 흐름을 전환하기 위해서입니다.

    구체적으로 말하면, 이는 콘솔에 아무런 메시지도 기록되지 않음을 의미합니다. 이렇게 하면 프로그램에 대한 정보 유출을 방지할 수 있습니다. 또한 바이너리 파일의 크기를 최대한 작게 유지하는 데에도 도움이 됩니다. 실행 파일에 진단 문자열을 저장하지 않음으로써 가능한 한 낮출 수 있습니다.

    하지만 그게 다가 아닙니다. Xcode 추가적인 검사 모드도 제공합니다. 서로 다른 성능상의 장단점을 제공합니다.

    지금까지 제가 언급해 온 강화 모드는 다음과 같습니다. 실제로 이를 고속 모드라고 부릅니다. 고속 모드 외에도, Xcode 또한 비용이 저렴한 검사를 추가하는 확장 모드를 제공합니다. 하지만 반드시 보안상 중요한 요소는 아닙니다.

    이 모드는 엄격한 프로그래밍을 보장하는 데 매우 유용합니다. 성능 비용을 너무 많이 지불하고 있습니다.

    Xcode 일반 모드 외에도 디버그 모드를 제공합니다. 디버그 모드는 그 대신 더 철저한 검사를 수행합니다. 더 큰 성능 향상 효과를 위해서입니다.

    예를 들어, 디버그 모드에서는, C++ 라이브러리는 제공된 비교기가 올바른지 확인할 수 있습니다. 표준 정렬은 정렬에 필요한 속성을 가지고 있습니다. 이는 앱에서 미묘한 의미론적 오류를 잡아내는 데 매우 유용합니다.

    이제 빠른 모드와 확장 모드를 실제 운영 환경에서 사용할 수 있습니다. 디버그 모드는 개발 중에만 사용해야 합니다.

    또한 서로 다른 파일에서 서로 다른 모드를 혼합하여 사용할 수도 있습니다. 이 기능을 사용하면 코드베이스에 보안 강화를 점진적으로 적용할 수 있습니다. 또는 정밀한 성능 조정을 위해서입니다. 예를 들어, 광범위한 기능을 활성화할 수 있습니다. 또는 코드베이스 전체에 대한 빠른 검사. 하지만 경화 기능을 비활성화합니다. 성능에 매우 민감한 단일 소스 파일입니다.

    경화 과정이 아비에 영향을 미치지 않기 때문에 이 모든 과정이 매끄럽게 진행됩니다.

    이 기능들이 이제 일반에 공개되어서 정말 기쁩니다. Xcode 에서 가능합니다. 실제로 Apple 이 기술을 개발해 왔습니다. 꽤 오랫동안 그래왔고, 이를 얻기 위해 내부적으로 채택되었습니다. 오늘날의 모습에 이르기까지.

    특히 이 기술은 WebKit 전체에 채택되었습니다. 그리고 커널의 일부를 포함하여 운영 체제의 여러 부분에 존재합니다.

    성능에 큰 영향은 관찰되지 않았으며, 여러 버그가 발견되었습니다. 그중에는 포착하기 매우 어려웠던 것들도 포함되어 있습니다. 애플의 자체 경험 외에도, 이 기술이 업계 전반에 걸쳐 사용되고 있다는 사례가 많습니다.

    예를 들어, 구글은 자사 전체에 걸친 배포 과정을 문서화했습니다. 서버 함대. 이것은 다음과 같습니다. 수백만 줄에 달하는 성능에 민감한 코드로.

    몇 가지 조정을 거친 후 성능 저하가 0.3% 정도로 매우 낮다는 것을 확인했습니다. 그들은 보안상 심각한 버그를 포함하여 1000개 이상의 버그를 발견했다고 보고했습니다.

    업계에서 채택된 또 다른 예로는 C++ 26이 있습니다. 이는 고속 모드를 기반으로 강화된 표준 라이브러리라는 개념을 채택했습니다.

    전반적으로 이번 경험은 압도적으로 긍정적이었습니다. 그리고 이 기능이 이제 Xcode 에서 일반 사용자에게 제공되게 되어 정말 기쁩니다.

    네, 지금까지 Xcode 에서 제공하는 도구들을 살펴봤습니다. C와 C++ 모두에서 중요한 취약점 유형을 제거하는 데 도움이 됩니다. 즉, 이제 바인딩 안전 확장 기능을 도입할 수 있습니다. C 코드에서 파일별로 작업하세요. 보안에 가장 민감한 코드 부분부터 시작해야 합니다. 그리고 준비가 되면 나머지 코드 작성으로 넘어가세요. 그러니까, 프로젝트 전체의 C++ 코드에 이 기능을 활성화하세요. 빠른 모드를 즉시 활성화하세요 코드 변경 없이 애플리케이션의 보안을 강화할 수 있습니다.

    테스트 및 개발 중에는 디버그 모드를 활성화해야 합니다. 이렇게 하면 평소에는 놓칠 수 있는 미묘한 버그까지 찾아낼 수 있습니다. 코드에서 버퍼를 사용하지 않고 접근하는 부분이 있습니다. 표준 라이브러리의 관용적인 추상화. 새로운 Xcode 진단 기능을 활성화하세요. 더 자세한 내용을 알고 싶으시다면, 오늘 제가 발표한 내용과 관련하여, 자세한 자료는 온라인에서 확인하실 수 있습니다.

    사람들이 여러분의 코드가 안전하기를 기대한다는 사실을 기억하고, 모든 단계가 중요하다는 것을 명심하세요. 그러니 오늘 바로 시작해서 이 기능들을 사용해 보세요. 그럼, 커트에게 다시 넘기겠습니다.

    고마워요, 루이스. 이제 잠시 쉬어가도록 하죠. 태평양 표준시 2시 55분에 오늘의 마지막 회담을 재개하기 전에 잠시 기다리겠습니다. 감사해요.

    다시 오신 것을 환영합니다. C와 C++를 떠나서, 보안에 민감한 코드를 Swift 로 작성하는 방법에 대해 이야기해 줄 Doug를 환영해 주세요. 더그.

    감사합니다.

    안녕하세요, 저는 Swift 언어 팀의 Doug입니다. 저는 동료 펠릭스와 함께 메모리, 보안 및 Swift 에 대해 이야기하기 위해 이 자리에 왔습니다. 따라서 메모리 안전성은 주요 보안 과제입니다. 지금. 다른 발표에서는 도움이 될 수 있는 완화 조치에 대해 논의했습니다. C 및 C++ 코드베이스에서 메모리 안전성 버그를 찾아냅니다. 또는 보안 문제로 발전하는 것을 방지합니다. 하지만 이 중 어느 것도 이처럼 포괄적이지는 않습니다. 또는 메모리 안전 문제를 정의하는 것만큼 효과적일 수도 있습니다. 프로그래밍 언어 자체에 있습니다. 그럼 먼저 Swift 의 디자인 방식을 살펴보겠습니다. 메모리 안전성을 다룹니다.

    그럼 이제 성능에 대해 이야기해 보겠습니다. 그리고 최근에 도입된 Swift 기능들을 사용하는 방법 저수준 코드에서 최상의 성능을 얻기 위해 안전을 타협하는 것.

    이제 메모리 안전성이 확보된 언어로의 전환이 진행되고 있습니다. 매우 오랜 시간이 걸립니다. 그래서 우리는 안전하지 않은 코드를 캡슐화하는 모범 사례에 대해 이야기해 보겠습니다. C 계열 언어에서 Swift 로 점진적으로 마이그레이션하는 방법에 대해서도 알아보겠습니다.

    우선, 메모리 안전성은 그냥 일괄적으로 적용되는 개념이 아닙니다. 모든 오류를 예방하는 것에 관한 것입니다. 따라서 좋은 언어 설계는 특정 유형의 오류를 정의하는 방법을 제시할 수 있습니다. 또는 코드에 도입하기 어렵게 만들 수도 있습니다. 하지만 현실은 프로그래밍 오류가 발생한다는 것입니다. 따라서 메모리 안전성이란 프로그램이 안전하게 실행되도록 보장하는 것입니다. 작성된 내용대로 작동합니다. 언뜻 들으면 터무니없는 소리처럼 들리겠지만요. 물론, 프로그램은 작성된 대로 작동합니다. 하지만 앞서 이야기했듯이, 공격자가 메모리 안전성 버그를 악용할 때, 그들은 코드에 명시되지 않은 작업을 프로그램이 수행하도록 강제할 수 있습니다. 그래서 메모리 안전성은 보안 문제에서 매우 중요한 부분을 차지합니다. 예를 들어, 메모리 안전성 버그가 어디에든 존재하기 때문에, C 및 C++ 코드를 사용하면 프로그램이 거의 모든 작업을 수행하도록 만들 수 있습니다. 메모리 안전성이 확보된 언어는 이러한 어처구니없는 상황을 방지해 줍니다. 이제 그것은 두 가지 방법 중 하나로 그렇게 할 수 있습니다. 따라서 메모리 관련 내용을 포함할 수 있는 코드는 컴파일을 거부할 수 있습니다. 안전 문제이거나, 런타임에 검사를 추가하여 감지할 수 있습니다. 무언가 잘못되었을 때. 이러한 전략들을 결합하면 실제로 다음과 같은 결과를 얻을 수 있습니다. Swift 컴파일 타임 방식을 혼합하여 사용합니다. 그리고 잠시 후에 설명드릴 런타임 검사 기능도 있습니다. 여기에는 규칙이 하나뿐입니다. 즉, 잠재적인 메모리 안전 문제가 발생할 경우, 해당 프로그램은 더 이상 지속되어서는 안 됩니다. 손상된 상태를 유지하려고 시도하는 것은 프로그래밍이 잘못되는 방식과 정확히 일치합니다. 오류가 메모리 안전성 취약점으로 이어집니다.

    이전에 이미 이야기했던 내용입니다. 그리고 우리는 종종 메모리 보안을 무너뜨립니다. 프로그래밍 언어가 다뤄야 할 다섯 가지 축으로 나누어 설명합니다. 그러므로 이것들은 안전장치가 되어 있습니다. 수명 안전 유형 안전 초기화 안전 및 스레드 안전. C 계열 언어는 이러한 어떤 측면에서도 안전성을 제공하지 않습니다. 물론 이러한 문제들 중 일부를 완화하는 데 도움이 될 수 있는 방법들이 있습니다. 그럼 Swift 가 이러한 다양한 영역을 어떻게 해결하는지 자세히 살펴보겠습니다.

    그리고 안전이 가장 쉬운 방법입니다. 이는 접근이 메모리 블록에 대한 것인지 확인하는 절차입니다. 해당 메모리 영역 밖으로 나가지 마세요. C 언어에서 보았듯이, 할당된 메모리 영역의 끝을 지나도록 포인터를 조정할 수 있습니다. 블록을 생성한 다음 관련 없는 다른 값을 읽거나 수정합니다. 메모리 안전성 문제를 야기합니다.

    여기 있는 Swift 코드는 동일한 취약점을 만들려고 시도합니다. 요소가 12개인 배열이 있습니다. 우리는 15번째 요소에 접근하려고 합니다. Swift 는 런타임에 경계 검사를 수행합니다. 이것이 유사한 것들을 즉시 포착하도록 보장하기 위해 우리가 안전장치에 대해 이야기했던 내용으로 돌아가서. 그건 쉬운 부분이죠. 그 이후부터는 훨씬 더 흥미로워집니다. 그러므로 평생 안전이 바로 그것을 보장하는 것입니다. 메모리에 접근할 때 해당 메모리는 여전히 유효한 상태입니다. C 언어에서는 수명 안전성을 위반하는 코드를 작성하는 것이 상당히 쉽습니다. 사용 후 사용권과 같은 것이 있는 경우, 해당 코드가 할당된 메모리 일부를 해제하는 부분입니다. 그런 다음 이 오래된 포인터를 통해 접근하려고 시도합니다. 이제는 완전히 다른 의미를 가질 수도 있습니다.

    Swift 무료 사용 기간을 없애줌으로써 무료 사용 이후 발생하는 문제를 해결합니다. 따라서 여기에 코드가 있다면 제 클래스의 인스턴스를 할당할 수 있습니다. 로컬 변수에 저장하세요. 이를 사용하여 해당 객체의 메서드를 호출할 수 있습니다. 그리고 명심하세요, 세상에 공짜는 없습니다. 대신 컴파일러는 소멸 구문을 삽입할 것입니다. 해당 인스턴스가 더 이상 사용되지 않을 때, 컴파일러는 항상 올바른 방식으로 처리할 거잖아요, 그렇죠?

    Swift 컬렉션 클래스에서도 동일한 자동 수명 관리 방식이 사용됩니다. 이것들은 배열이나 딕셔너리 같은 것들입니다. 여기서는 첫 번째 줄에서 배열이 생성됩니다. 더 이상 사용되지 않으면 자동으로 할당 해제됩니다.

    Swift 자동 참조 카운팅이라는 기술을 사용합니다. 그래서 우리는 다른 전통적인 가비지 컬렉션 기술보다 이 방법을 선택했습니다. 공학적으로 매우 훌륭한 절충점을 가지고 있기 때문입니다. 자동 참조 계수 방식을 사용하는 경우, 기본적으로 프로그래밍을 할 수 있습니다. Swift 에서는 메모리 관리를 고려하지 않고도 개발할 수 있습니다. 모든 패턴이 효과가 있는 것 같습니다. 그리고 당신은 대부분의 경우 평생을 고려하지 않고 있습니다. 반면에 자동 참조 계수 방식이 있습니다. 속도가 매우 빠릅니다. 오버헤드도 매우 낮습니다. 성능과 메모리 사용량 모두에서, 그리고 여러분이 흔히 볼 수 있는 그런 종류의 멈춤 현상이 없습니다. 보다 전통적인 쓰레기 수거 방식을 사용합니다.

    하지만 때로는 그렇지 않은 경우도 있습니다. 실행 시간 오버헤드가 전혀 발생하지 않도록 해야 할 때 평생 안전을 유지하기 위해. 따라서 Swift 복사 불가능한 타입도 제공합니다. 이는 고유한 소유 자원에 대한 소유권을 설명합니다. 여기에는 절충점이 있습니다. 호환되지 않는 유형은 프로그래밍 모델이 더 제한적이라는 것입니다. 소유권에 대해 더 많이 생각하기 시작해야 합니다. 하지만 그렇게 하면 추가 비용이 전혀 들지 않습니다. 복사 불가능한 유형에 대해서는 발표 후반부에 다시 ​​다루겠습니다.

    타입 안정성은 잘못된 타입으로 메모리에 다시 접근하는 것을 방지하는 기능입니다. C 언어는 타입 안정성 문제를 쉽게 발생시킬 수 있습니다. 여러 가지 다른 방식으로요. 예를 들어, 메모리의 이 셀에 정수를 쓴다고 가정해 봅시다. 나중에 노동조합원을 통하거나 명시적인 캐스팅을 사용할 수도 있습니다. 그리고 그것을 파일로 다시 읽어들이면서 유형 혼동이 발생합니다.

    Swift C 언어의 공용체 및 형변환과 같은 기능에 상응하는 기능을 제공합니다. 하지만 둘 다 구조적으로 안전하게 설계되었습니다. Swift 열거형은 차별적입니다. 차별받는 노동조합, 즉, 현재 어떤 옵션이 활성화되어 있는지를 인코딩한다는 의미입니다. 자, 여기 리소스 열거형이 있습니다. 파일을 저장할 수 있습니다. 또는 리소스에 접근하기 위한 정수 식별자를 저장할 수도 있습니다. switch 문을 사용하여 패턴 매칭을 수행합니다. 이는 잘못된 회원에게 접근하는 일이 절대 발생하지 않도록 보장합니다. 이것은 쌍방향 액세스입니다.

    Swift의 형변환도 이와 유사합니다. 여기 있는 Swift 코드는 클래스 하나와 서브클래스 하나를 정의합니다. 해당 하위 클래스는 기존 메서드를 재정의하고 자체적으로 다른 메서드를 추가합니다. 상당히 전형적인 객체 지향 프로그래밍 방식입니다. 여기서는 다운캐스트를 시도해 보겠습니다. 여기서 `as`는 주어진 객체를 내 서브클래스로 다운캐스팅합니다. 선택적 값을 생성합니다. 이는 내 서브클래스로서 인스턴스를 포함하거나, 다운캐스트가 실패하면 비어 있게 됩니다. 그러니까 만약 그것이 하위 클래스의 인스턴스라면, 해당 코드는 본문 내부에서 실행됩니다. 그렇다면 안전한 다른 방법을 호출할 수 있습니다. 다운캐스팅이 실패하면 옵셔널은 비어 있게 됩니다. if 문의 본문은 실행되지 않습니다. 따라서 이는 주조 과정에서 발생할 수 있는 메모리 안전상의 잠재적 취약점을 제거합니다. 잘못된 형변환으로 인한 프로그래밍 오류를 방지하는 데에도 도움이 됩니다.

    초기화 안전성 또한 상당히 직접적인 문제입니다. 이것이 바로 메모리가 다시 초기화되기 전에 읽히는 것을 방지하는 장치입니다. C 언어에서는 필요하지 않습니다. 이렇게 하면 지역 변수를 만들 수 있습니다. 그리고 초기화되기 직전에 바로 사용하면 됩니다. Swift 에서 똑같은 작업을 시도하면, Swift 컴파일러는 이러한 시도를 거부할 것입니다. 즉, 변수에 값을 할당하거나 초기화하지 않았다는 의미입니다. 컴파일 시점에 이를 거부할 것입니다. 그러므로 메모리 안전성 문제는 발생하지 않을 것입니다.

    마지막으로 가장 까다로운 것은 실의 안전성입니다. 따라서 스레드 안전성 위반은 어느 곳에서든 데이터 경쟁이 발생할 수 있음을 의미합니다. 프로그램에서 메모리 안전성 문제가 발생할 수 있습니다. 그리고 이런 일은 다음과 같은 경우에도 일어날 수 있습니다. 다른 모든 측면에서 당신의 언어는 안전합니다.

    이 예시에서는 공유 가능한 변경 가능한 리소스를 보여줍니다.

    리소스 교체 함수는 해당 리소스의 값을 변경합니다. 해당 식별자로 유형을 설정하는 것을 포함합니다.

    이 모든 일이 하나의 스레드에서 일어난다고 상상해 보세요. 자, 이제 다른 게시글에서 이야기해 볼까요? 리소스 사용 기능이 있는데, 이 기능이 전환되는 역할을 합니다. 동일한 공유 리소스에서. 만약 여기서 데이터 경쟁이 벌어진다면, 이는 한 스레드가 그것을 파일로 인식한다는 의미일 수 있습니다. 동시에 다른 스레드가 정수 값을 덮어쓰고 있습니다. 기존 파일 인스턴스를 정수로 덮어씁니다. Swift 6의 동시성 모델은 이러한 데이터 경쟁을 방지합니다. 공유되는 변경 가능한 상태에 대한 동시 접근이 발생하지 않도록 보장합니다. 자, 그와 더불어, Swift 안전한 거래 방법을 제공합니다. 상위 수준에서 데이터 경쟁을 유발하지 않는 동시성을 제공합니다. 그중 하나가 배우들입니다. 따라서 액터는 자신의 상태를 캡슐화하는 유형입니다. 또한 동시 수정으로부터 보호합니다. 여기서 리소스 변수는 이제 액터의 상태의 일부입니다. 따라서 Swift 리소스 사용을 보장합니다. 그리고 해당 상태에 영향을 줄 수 있는 리소스를 교체하는 작업은 절대 동시에 실행되지 않습니다. 이는 Swift의 async await 모델을 사용하여 일관되게 적용됩니다. 따라서 액터의 메서드 호출은 항상 비동기적으로 이루어집니다. 호출자는 액터가 코드 실행을 완료할 때까지 기다려야 할 수도 있기 때문입니다. 그 통화를 안전하게 하기 전에 다른 스레드에서 이야기해 봅시다.

    Swift 데이터 경합 안전성을 위한 저수준 기본 기능도 제공합니다. 여기서 뮤텍스 유형은 특정 사용자만 접근할 수 있는 것을 의미합니다. 한 번에 하나의 스레드씩 처리합니다. 저장된 데이터에 대한 모든 접근 뮤텍스에서 발생하는 문제는 이 너비 잠금 기능을 통해 제공됩니다. 해당 데이터에 대한 임시 접근 권한. 클로저 내부에서 뮤텍스는 단 하나의 스레드만 접근할 수 있도록 보장합니다. 동시에 종료를 실행합니다.

    Swift 메모리를 사용하면 안전성이 언어 설계 단계부터 내재되어 있습니다. 여기에는 정말 얻기 힘든 이점이 하나 있습니다. 직접 경험해 보기 전까지는 설명하기 어렵습니다. 메모리 안전 언어를 사용할 때는, 단순히 걱정할 필요가 없다는 것만이 중요한 게 아니잖아요? 내가 메모리 보안 취약점을 도입하고 있는 걸까, 아니면 그런 취약점을 찾고 있는 걸까? 그냥 그 일에 대해 생각하는 걸 완전히 멈추는 거예요. 따라서 코드의 정확성에만 모든 주의를 집중할 수 있습니다. 그리고 메모리 안전과 관련이 없는 다른 우려 사항들도 있습니다.

    만약 여러분이 C 계열 언어에 익숙하다면, 아마 여러분은 이 메모리 안전 기능이 어떤 의미를 갖는지 궁금해하실 겁니다. 성능 저하를 감수해야 합니다.

    요약하자면, Swift 는 네이티브 컴파일 언어입니다. 이 시스템은 메모리 안전성 모델에 대한 효율적인 구현을 제공합니다. 많은 프로그램의 경우, 그 정도면 충분합니다.

    하지만 매우 낮은 수준의 코드의 경우에는 다음과 같습니다. 안전하지 않은 C Swift 62의 성능에 맞추기 위해 도입되었습니다. 이해를 돕기 위한 몇 가지 안전한 추상화 개념입니다. C 언어로 작성된 예제를 살펴보겠습니다. 이것은 디코더입니다. 런 길이 인코딩을 사용하는 이미지의 경우. 그러니까 반복문 안에서 입력 버퍼로부터 한 번에 4바이트씩 읽어오는 겁니다. 이것은 개수와 픽셀 데이터입니다. 그런 다음 출력 버퍼를 통해 결과를 출력합니다. 진행 과정에서 수동으로 경계 검사를 수행하는 것을 볼 수 있습니다. 이 C 코드에는 사실이 아닌 가정이 많이 포함되어 있습니다. 실제로 검증되었습니다. 따라서 우리는 카운트 매개변수가 정확하다고 가정합니다. 해당 버퍼의 크기를 정확하게 설명합니다. 입력 버퍼와 출력 버퍼 사이에 이상한 방식으로 앨리어싱 현상이 발생하지 않는다고 가정합니다. 그리고 다른 스레드에 의해 수정되거나 해제되지 않을 것입니다. 이 프로그램이 실행되는 동안. 다음은 동일한 코드를 Swift 로 번역한 것입니다. 따라서 입력 버퍼는 데이터와 개수를 모두 포함하는 배열입니다. 그래서 여러분은 알 수 있습니다. 그리고 데이터가 사라지지 않도록 보장해 줍니다. 또는 멀티스레드 프로그램에서도 이 함수가 실행되는 동안 수정될 수 있습니다.

    이제 배열 접근 시 범위 검사가 수행됩니다. 그러면 오류가 발생합니다. 런타임에 발생하며 메모리 안전성 취약점이 되지 않습니다. 하지만 저는 성능에 대해 이야기하겠다고 했잖아요. 그럼 한번 살펴보죠. 따라서 루프 내에서 올바른 범위 검사를 수행하면, 컴파일러는 종종 경계 검사를 완전히 제거하는 최적화를 수행할 수 있습니다. 그렇게 하는 것이 안전하다고 입증되었을 때.

    Swift의 copy-on-write 배열은 이제 참조 카운팅을 사용합니다. 실행 과정에서. 다시 말해, 컴파일러는 참조 카운팅 관련 트래픽을 모두 최적화하여 제거할 수 있는 경우가 많습니다. 이 예시에서는 그렇습니다. 하지만 이 추가 작업은 배열에 새 요소를 추가합니다. 배열에 이미 충분한 공간이 없다면, 더 많은 저장 용량을 가진 새로운 메모리를 할당해야 할 것입니다. 그런 다음 기존 요소들을 모두 새 위치로 복사합니다. 그건 이전에 사용했던 C 언어 구현보다 속도가 느릴 겁니다. 단순히 포인터를 통해 픽셀을 출력하는 것이었습니다.

    여기에는 두 번째 문제가 있습니다. 즉, 이러한 설계 방식은 고객이 직접 배열을 갖도록 강제한다는 것입니다. 우리는 그들에게 자신들이 작성한 사본을 제출하도록 요구할 수 있습니다. 예를 들어 보겠습니다. 배열에 데이터가 몇 개 있습니다. 하지만 이 헤더는 너비로 구성된 간단한 형태를 가지고 있습니다. 그리고 실제 출력 이미지의 높이, 그다음에는 실제로 디코딩하려는 이미지 데이터가 나옵니다. 자, 여기서 가장 큰 문제는 우리가 필요로 하는 것입니다. 이 모든 런 길이 인코딩된 픽셀 데이터의 사본을 만들려면, 우리가 작업해 온 디코딩 함수를 호출하기만 하면 됩니다. 디코딩 함수가 전체 픽셀 배열을 읽어야 하기 때문입니다. 이는 추가적인 힙 할당과 모든 이미지 데이터의 복사본 생성을 의미합니다. 우리가 절대 원하지 않는 일입니다.

    여기에도 관련된 문제가 있습니다. 즉, 디코딩 과정에서 결과 배열을 할당한다는 뜻입니다. 항상 더미 위에 있어요. 이 특정 이미지 디코딩 작업은 그 점에서 문제가 없을 수도 있습니다. 하지만 다른 발신자가 픽셀을 넣어달라고 요청할 수도 있습니다. 어떤 특정한 장소에서, 이미 할당된 고정 크기 프레임 버퍼에 저장될 수도 있습니다. 그러려면 결과를 다시 한 번 복사해야 합니다. 이런 종류의 문제는 저수준 환경에서 자주 발생할 수 있습니다. 성능에 매우 민감한 코드베이스, 배열 슬라이스나 제네릭 컬렉션을 사용하면 이 문제를 부분적으로 해결할 수 있습니다. 하지만 그런 것들은 다루기가 좀 어려울 수 있어요.

    바로 이 부분에서 새로운 span 타입 제품군이 등장합니다. 따라서 스팬은 연속적인 메모리에 안전하고 오버헤드가 낮은 접근을 제공합니다. Swift 에서 안전하지 않은 버퍼 포인터 유형을 사용해 본 경험이 있다면, 스팬은 그것들의 안전한 대응물이라고 생각할 수 있습니다.

    span의 핵심 개념은 인접한 영역을 참조한다는 것입니다. 자신이 소유하지 않은 기억. 포인터와 길이의 조합이라고 생각하시면 됩니다. 그것이 바로 메모리에 표현되는 방식이기 때문입니다. 이제 Span은 완벽한 메모리 안전성을 제공합니다. 이는 컴파일러가 검사하는 방식으로 수명 주기 안전성을 제공합니다. 실행 시간 오버헤드가 전혀 없습니다. 모든 접근에 대해 경계 검사를 실시하여 강력한 보안을 제공합니다. 하지만 가장 중요한 것은, 해당 저장소가 참조하는 위치에 대한 소유권을 갖고 있지 않다는 점입니다. 대신, 자체 저장 장치를 보유한 다양한 유형과 상호 운용됩니다. 쓰기 시 복사되는 배열을 참조하는 스팬을 얻을 수 있습니다. 또는 고정 길이 인라인 배열. 또한 안전하지 않은 포인터 유형과도 상호 운용됩니다. 이는 안전하지 않은 언어와 상호 작용할 때 중요합니다. 또는 스팬 이전에 작성된 코드.

    span 타입군은 Swift 6.2에서 도입되었습니다. 하지만, 우리는 스팬이 매우 중요하다고 생각해서 이러한 유형을 다시 배포하도록 만들었습니다. 애플 운영체제의 훨씬 이전 버전들과 비교했을 때. 이렇게 하면 지금 바로 입양할 수 있습니다. 배포 목표를 높이려면.

    좋습니다, 이제 런 길이 디코더의 입력으로 스팬(span)을 채택할 차례입니다.

    이건 많은 걸 필요로 하지 않았어요. 매개변수 형식을 배열에서 span으로 변경했습니다. span이 동일한 API를 제공하기 때문에 이것이 가능합니다. 배열처럼 요소에 접근하는 데 사용됩니다. 이 코드는 단순히 데이터를 읽어들이는 코드이기 때문에, 수정하려는 것이 아닙니다. 복사본을 반환하지 않습니다. 이 기능에서는 그 외에는 아무것도 변경할 필요가 없었습니다. 자, 달라진 점은 API 계약 호출자가 이제 필요로 하는 것입니다. 배열 대신 스팬을 제공합니다. 그럼 호출자의 코드로 돌아가서 어떻게 하는지 살펴보겠습니다.

    우선 모든 배열에는 span 속성을 가지고 있으며, 이 속성은 span 태그를 생성합니다. 이렇게 하면 코드가 컴파일됩니다. 끝에 span 태그를 추가하는 것뿐입니다. 그 방법은 효과가 있습니다. 하지만 성능이 향상되지는 않을 겁니다. 아직 새로운 배열을 생성하는 중이기 때문입니다. 스팬을 입력하기 전에 모든 데이터를 복사합니다. 우리는 더 잘할 수 있습니다. 그래서 대신에, 우리가 할 일은 원래 배열에서 스팬을 가져오는 것입니다. 그런 다음 우리가 중요하게 생각하는 부분만 골라서 아래로 전달합니다. 디코딩 함수로. 코드 읽기 작업은 자신과 관련된 스팬만 수신합니다. 하지만 추가 할당량도 없고 복사본도 없습니다. 동시에 메모리 안전성을 유지합니다.

    이 예시를 보면 span이 마치 기존 기능을 그대로 대체하는 것처럼 보입니다. 배열의 경우입니다. 그렇지 않습니다. 따라서 다른 사람이 소유한 저장소에 대한 참조입니다. 따라서 런타임 오버헤드 없이 이를 안전하게 만들려면 다음과 같이 해야 합니다. 스팬 유형 자체에는 몇 가지 필수적인 제약 조건이 있습니다.

    따라서 span은 우리가 탈출 불가능한 유형이라고 부르는 것입니다. 위에서 보여준 물결표(~) 이스케이프 가능한 구문을 사용하여 작성되었습니다. 이와 동일한 구문을 사용할 수 있습니다. span처럼 동작하는 자체적인 이스케이프 불가능한 유형을 정의할 수 있습니다. 이제 피할 수 없는 유형이 되었습니다. 앞서 했던 것처럼 함수에 인수로 전달할 수도 있습니다.

    하지만 함수에서 span을 반환할 수는 없습니다. 왜냐하면 이스케이프할 수 없는 유형의 값만 반환할 수 있기 때문입니다. 그것의 수명은 매개변수 중 하나와 연관되어 있습니다.

    이것이 무엇을 의미하는지 알아보기 위해 첫 번째 실행 함수의 본문을 자세히 살펴보겠습니다. 여기 있는 코드는 첫 번째 요소와 일치하는 요소들의 연속을 찾는 것입니다. 그리고 내부의 루프는 첫 번째 불일치를 발견하면 종료될 것입니다. 여기서 중요한 것은 논리 자체가 아니라 최종 결과입니다.

    자, 이제 우리는 무엇을 돌려줘야 할까요? 우리는 받은 데이터 매개변수에서 직접 추출한 스팬을 반환합니다. 그중에서 관련 부분만 발췌한 것입니다. 괜찮습니다. 그것은 우리에게 정보를 제공한 발신자가 그렇다는 뜻입니다. 해당 스팬을 사용하면 결과적으로 생성된 스팬이 충분히 오랫동안 유지됩니다.

    하지만 만약 코드가 데이터의 복사본을 만들었다고 상상해 보세요. 새로운 배열로 변환합니다. 이 배열은 지역 변수에 저장됩니다. 그런 다음 해당 복사본에서 스팬을 반환하려고 시도합니다. 컴파일러가 여기서 오류를 발생시킬 것입니다.

    그 이유는 새로 생성된 배열이 지역 변수에 저장되기 때문입니다. 그게 바로 이 프로젝트를 살아남게 하는 원동력입니다. 호출자가 접근할 수 있는 로컬 변수에 스팬 값을 반환할 수는 없습니다. 왜냐하면 우리가 종료하는 순간 지역 변수는 사라지기 때문입니다. 그러니까 C라는 관점에서 생각해 보면, 제가 말씀드리는 제한 사항들이 낯설지 않으실 수도 있습니다. 지역 변수의 주소를 가져온다고 상상해 보세요. 저 포인터는 아주 조심해서 다뤄야 합니다. 어딘가에 저장되지 않도록 하기 위해서입니다. 그런 다음 함수가 반환된 후에 사용됩니다. 그리고 지역 변수들이 사라졌습니다. Swift 그러한 제약 조건을 언어의 일부로 만듭니다. 따라서 메모리 안전성을 손상시키는 실수를 저지를 수 없습니다.

    Spanned 단독으로는 메모리에 대한 읽기 전용 액세스만 제공합니다. 변경 가능한 접근 권한을 제공하는 또 다른 유형의 변경 가능한 스팬이 있습니다. 그래서 여러분은 읽기뿐만 아니라 쓰기도 할 수 있습니다. 인접한 어느 위치에서든 변경 가능한 스팬 속성을 사용할 수 있습니다. 이전에 언급했던 컬렉션을 사용하여 변경 불가능한 스팬을 저장소에 저장합니다. 그런 다음 예상대로 첨자를 사용하여 해당 요소의 요소를 수정할 수 있습니다.

    여기서 안전 모델의 핵심적인 부분은 바로 가변성입니다. span을 사용하려면 기본 메모리에 대한 독점적인 액세스가 필요합니다. 즉, 메모리 블록을 참조하는 불변 스팬이 있는 경우, 다른 누구도 그 메모리에 접근할 수 없습니다. 쓰기 위한 용도도 아니고, 읽기 위한 용도도 아닙니다.

    그래서 우리 코드에서 만약 우리가 동일한 배열 내부에 접근하는 두 번째 스팬을 생성하기 위해 그런 다음 돌연변이를 시도해 보세요. 컴파일러는 접근을 방지하기 위해 여기에 오류를 발생시킬 것입니다. 돌연변이가 활성화된 동안 저장소로 이동합니다.

    이러한 독점 모델은 Swift 의 핵심 요소입니다. 사실 처음부터 시행되어 왔어요. 이는 메서드 변경과 같은 작업을 수행할 때 메모리 안전성을 보장하는 요소입니다. 그리고 입력/출력 매개변수. 대부분의 Swift 프로그래머들은 그것이 존재한다는 사실조차 모릅니다. 매우 드물기 때문입니다 이러한 상황에서 실제로 메모리 안전 위반이 발생하도록 하기 위해서입니다. 하지만 이는 메모리 안전성을 확보하기 위한 최후의 수단으로 존재합니다. 자, 이제 가변 스팬을 도입할 차례입니다. 실행 길이 디코딩 함수에서 힙을 반환하는 대신 할당된 배열입니다. 이것은 진행 중입니다. span보다 약간 더 많은 작업이 필요합니다. 하지만 다시 한번 함수 시그니처부터 살펴보겠습니다. 여기서 핵심은 새로운 저장 공간을 생성하는 대신 반환된다는 점입니다. 발신자에게. 발신자는 우리에게 어디인지 알려줄 것입니다. 이 출력 매개변수를 통해 결과를 표시합니다. 변경 가능한 스팬을 수정할 때 전달되기 때문에 전달됩니다. 결과가 나오는 곳이 바로 그곳입니다. 그리고 출력 배열에 추가하는 대신, 이제 픽셀이 직접 기록됩니다. 이 출력 매개변수를 통해 최종 위치로 이동합니다. 이는 해당 함수에서 더 이상 메모리 할당이 이루어지지 않음을 의미합니다. 읽기 및 쓰기 버퍼를 설정하는 것은 전적으로 호출자의 책임입니다. C 언어에서 했던 것처럼 말이죠. 발신자에 대해 말하자면요. 그래서 실제로 이전에는 의존했습니다. 초기 디코딩이 배열을 반환했다는 사실에 근거합니다. 그럼 다시 돌아가서 살펴보죠. 자, 그럼 이 함수에 필요한 것은 무엇일까요? 해야 할 일은 자체 픽셀 배열을 할당하는 것입니다. 그런 다음 변경 가능한 스팬을 해당 배열로 전달하여 LED 코드에 전달합니다. 결과로 생성된 픽셀을 채웁니다.

    물론, 이 호출자는 힙 할당을 직접 수행하기로 선택한 것입니다. 하지만 다른 발신자는 완전히 다른 선택을 할 수도 있습니다.

    예를 들어 보겠습니다. 이 구조는 320을 나타냅니다. 240픽셀 프레임 버퍼로 구성됩니다. 힙 메모리 할당을 피하기 위해 인라인 배열로 표현됩니다.

    이미지 디코딩 작업은 변경 가능한 참조를 사용합니다. 프레임 버퍼에 대한 정보는 Inout을 사용하여 다시 제공되었습니다. 그러면 해당 픽셀에 불변 범위가 적용됩니다. 그리고 그 정보를 LED 디코딩 장치로 전달합니다.

    무슨 일이 벌어지고 있는지 보이시나요? 디코딩 과정이 프레임에 직접 들어갑니다. 아니요. 추가 복사본은 없습니다. 메모리 할당도 없습니다. Span을 도입하는 것은 성능과 메모리 안전성 모두에서 상당한 이점입니다. Swift 코드베이스에 이 기능을 도입하시기를 권장합니다. span을 도입해야 할 만한 곳을 찾고 있다면, 시작점은 두 가지입니다. 성능적인 관점에서 보면, 배열이나 데이터 형식을 사용하는 성능에 민감한 코드를 찾아보세요. 불필요한 복사본이나 힙 할당이 발견되면 span을 사용하십시오. 디코딩 작업에서 했던 것처럼요.

    메모리 안전성 관점에서 볼 때, 먼저 코드에서 안전하지 않은 버퍼 포인터 유형 사용을 바꾸는 것부터 시작하세요. 이름에서 알 수 있듯이, 안전하지 않은 포인터 유형은 메모리 안전성을 유지하지 않습니다. 그리고 드물게 사용해야 합니다. Span은 안전하지 않은 포인터를 사용하는 대부분의 경우에 안전한 대안입니다. 비록 그 목표에 도달하기 위해서는 약간의 리팩토링이 필요할 수도 있지만 말입니다. 이제 제 동료 펠릭스에게 마이크를 넘겨서 어떻게 대처해야 할지 자세히 이야기해 보도록 하겠습니다. 메모리 안전성을 손상시키지 않고 Swift 에서 안전하지 않은 구문을 사용하는 방법.

    고마워, 더그.

    안녕하세요, 제 이름은 펠릭스이고 보안 엔지니어링 팀에서 왔습니다. 그리고 건축팀. 다음 안건은 안전하지 않은 코드를 안전하게 사용하는 방법입니다.

    이제 메모리 안전성이 확보된 언어가 프로그래밍의 미래입니다.

    Doug가 설명했듯이 span과 같은 오버헤드가 낮은 기본 요소를 사용함으로써 안전한 코드는 매우 빠르며 메모리 안전성 버그를 발생시키지 않습니다.

    동시에, 오늘날 안전하지 않은 코드는 도처에 존재합니다. 문자 그대로.

    안전한 언어 사용이 어려웠던 지역에서도 점차 확산되고 있는 가운데… 이전에도 그랬습니다. 여전히 수십억 줄에 달하는 안전하지 않은 코드가 남아 있습니다. 이는 수십 년 전부터 알려진 사실입니다. 불행히도, 이는 일반적인 공학적 상식에 어긋나는 것입니다. 코드 재작성은 위험합니다. 새로운 구현 방식은 버그를 발생시키거나 재발생시킬 수 있습니다. 그리고 기존 구현 방식이 동시에 계속 발전할 때 안전하지 않은 구현 방식과 경쟁합니다.

    이것이 바로 계획을 세우는 것이 중요한 이유입니다. 안전하지 않은 코드에서 점진적으로 벗어나기 위해, 더 작은 단위로 코드를 수정하는 방식을 사용합니다. 위험 관리가 훨씬 쉬워집니다. 그러면 성공 가능성이 크게 높아집니다.

    그리고 이것이 오늘날 중요한 이유는 Swift 독특한 특징을 가지고 있기 때문입니다. C, C++에서 점진적으로 마이그레이션할 수 있도록 설계된 기능 Objective-C 도 가능합니다.

    이러한 도구 중 첫 번째는 엄격한 메모리 안전성입니다. 이보다 더 안전한 근무 환경은 없습니다. 엄격한 메모리 안전성을 활성화하는 것보다 안전하지 않은 코드를 사용하는 것이 낫습니다. 이것은 매우 중요합니다.

    엄격한 메모리 안전성은 안전하지 않은 코드의 모든 사용 사례를 드러냅니다. 이것은 매우 유용합니다. 왜냐하면... Swift 종종 안전하지 않은 것들을 지칭할 때 '안전하지 않음'이라는 표현을 사용하지만, 일부 작업은 본질적으로 안전하지 않습니다.

    예를 들어, 이 코드에서, 배열 복사 함수는 x와 y라는 두 개의 배열 변수를 선언합니다. 그리고 memcpy를 사용하여 하나의 파일을 다른 파일로 복사합니다. 코드에는 Memcpy가 안전하지 않은 작업을 수행한다는 내용이 없습니다. 하지만 Memcpy는 C 함수입니다. 그래서 안전하지 않은 포인터를 허용합니다. 그리고 y는 암묵적으로 안전하지 않은 포인터로 변환됩니다. 이로 인해 명확한 징후 없이 메모리 안전성 버그가 발생할 수 있습니다.

    엄격한 메모리 안전성을 활성화하면 컴파일러에서 경고 메시지가 표시됩니다. 이러한 경우를 포함하여 안전하지 않은 코드 사용에 대해서는 with 표현식은 안전하지 않은 구문을 사용하지만 안전하지 않다고 표시되지는 않습니다.

    이 문제는 함수 호출 앞에 unsafe 키워드를 추가함으로써 해결됩니다.

    잠시 시간을 내어 자세히 설명드리겠습니다. 컴파일러를 참조하는 것 외에 unsafe 키워드에 대해. 경고, 이 프로그램에는 두 가지 주요 기능이 있습니다. 첫째, 이는 코드베이스를 감사할 때 보안 검토자에게 주는 경고입니다. unsafe 키워드는 잠재적으로 문제가 발생할 수 있음을 나타냅니다. 위험한 일이 벌어지고 있습니다.

    그리고 두 번째로, 그리고 훨씬 더 중요하게는, 컴파일러가 검증할 수 없는 부분을 직접 검증해야 한다는 점을 상기시켜 주는 것입니다. 확인하기 위해.

    Memcpy 예제를 다시 가져와 보겠습니다. 두 배열 모두 4바이트를 포함하고 있으므로 코드는 올바릅니다. 하지만 컴파일러는 이것이 호출의 전제 조건이라는 것을 알지 못합니다. unsafe 키워드는 Memcpy가 올바르게 사용되었는지 확인하라는 의미입니다.

    Xcode 프로젝트에서 이를 활성화하려면 다음과 같이 하세요. Swift 언어 옵션에서 엄격한 메모리 안전 설정을 찾아보세요.

    Swift 패키지에서 엄격한 메모리 안전성을 활성화하려면 다음을 추가하세요. 패키지 설명에 엄격한 메모리 안전 설정이 적용되어 있습니다.

    엄격한 메모리 안전성이 활성화된 경우에도 마찬가지입니다. 또한 안전하지 않은 코드가 눈에 띄게 표시되도록 할 것입니다. 안전하지 않은 기능은 아예 사용하지 않는 것이 가장 좋습니다.

    안전하지 않은 코드가 정말로 필요한 경우는 단 두 가지뿐입니다. 첫째, 안전하지 않은 라이브러리와 상호 운용하기 위해서입니다. 둘째, 안전한 기본 요소를 구현해야 합니다. 많은 경우, 작고 위험한 보석에는 실제로 두 가지 측면이 있습니다.

    안전한 언어로 새로운 코드를 작성하는 것은 여러 가지 이점이 있습니다. 하지만 안전하지 않은 구현 방식이 여전히 최고의 도구일 수도 있습니다. 일부 작업의 경우.

    이는 안전하지 않은 라이브러리가 흔하기 때문이며, 보안 문제는 차치하더라도, 여전히 가장 성숙한 단계일지도 모릅니다. 안전하지 않은 라이브러리를 안전한 언어로 다시 작성할 수 있는 경우. 그게 언제나 더 낫죠. 하지만 임의의 시간 범위 내에서 항상 가능한 것은 아닙니다. 안전한 재작성은 시간과 전문 지식을 필요로 합니다. 그리고 전문가들이 있습니다. Swift 라이브러리가 안전하게 사용되도록 도와줄 수 있습니다.

    Doug는 앞서 디코딩 기능을 소개했습니다. 그것이 구현되었다고 말하세요 쉽게 재작성할 수 없는 외부 C 라이브러리에 있습니다.

    Swift 헤더를 만나면 해당 함수를 `this swift`로 노출합니다. 안전하지 않은 인터페이스입니다. 소스 포인터와 동일한 매개변수를 사용합니다. 소스 크기 대상 포인터와 대상 개수입니다. 하지만 이는 여전히 안전하지 않은 값을 사용하기 때문에 이상적인 방법은 아닙니다. 하지만 Swift 에서 여전히 호출할 수 있습니다. 하지만 엄격한 메모리 보안이 활성화된 경우, 컴파일러는 동일한 안전하지 않은 구문을 생성합니다. 경고.

    안전하지 않은 것을 안전하게 감싸는 래퍼를 작성하는 것이 더 낫습니다. Doug가 보여준 것과 같은 구현 방식입니다. 이 래퍼는 스팬을 입력으로 받고, 변경 가능한 스팬을 출력으로 받습니다. 해당 래퍼에는 안전하지 않다는 내용이 많이 포함될 것입니다. 이는 스팬에서 포인터를 가져오는 각 연산 때문입니다. 또는 해당 포인터를 사용하는 경우 안전하지 않다고 표시해야 합니다. 하지만 보안 감사는 쉽습니다.

    해당 코드는 각 스팬에서 안전하지 않은 포인터를 가져옵니다. 그리고 해당 카운트와 함께 이를 C 구현체로 전달합니다.

    Swift 인터페이스 사용자를 감사할 필요는 없습니다. 스팬을 통과시키기 때문이며, 스팬은 안전합니다. 여기에는 아무런 오류가 없지만, 만약 오류가 있다면, 이 구현 방식에서는 그럴 것입니다. C 구현에 메모리 안전성 버그가 있을 수도 있습니다. 하지만 호출하는 Swift 모듈은 잘못이 없는 것으로 판명되었습니다. 빨간색 코드가 안전하게 구현될 때. 이러한 위험은 완전히 제거됩니다.

    이제 안전한 기본 요소를 구현하는 측면으로 넘어가 보겠습니다. 또 다른 일이 일어날 수도 있습니다 안전하지 않은 코드를 래핑할 때 외부 라이브러리가 사용될 수 있다는 점이 문제입니다. 수동으로 생성하고 삭제해야 하는 일종의 리소스입니다.

    디코딩 함수를 다시 보여드리겠습니다. 저는 단일 상태 비저장 디코딩 함수 대신에, 이제 RL이 포함된 디코더 객체를 생성해야 합니다. 그런 다음 RL destroy 명령어를 사용하여 해당 항목을 파괴해야 합니다. 그리고 RL 디코딩 기능은 이전과 거의 동일합니다. 하지만 이제는 디코더를 첫 번째 인수로 받습니다.

    Copyable 구조체는 DNN을 가질 수 없으므로 이 패턴에는 명시적인 DNN이 필요합니다. 이는 항상 클래스를 사용하여 구현되었습니다. 오늘날 안전하지 않은 리소스를 캡슐화하는 많은 코드가 이와 같은 형태를 띠고 있습니다. 초기화 프로그램은 RL 초기화 함수를 호출합니다. 그런 다음 초기화 함수가 소멸 함수를 호출합니다. 디코딩 기능은 이전과 거의 동일합니다.

    이 방법도 효과는 있지만, 효율성은 더 높을 수 있습니다.

    최상위 클래스 인스턴스는 동적으로 할당됩니다. 이는 수명이 긴 물체에는 일반적으로 문제가 되지 않습니다. 하지만 인스턴스를 반복적으로 생성하고 삭제하면 다음과 같은 결과가 발생합니다. malloc 및 free 호출을 불필요하게 줄이기 위해서입니다. 동적 할당을 사용하는 것은 훨씬 더 비용이 많이 듭니다. 다른 동적 할당을 감싸기 위해.

    2차 클래스 인스턴스는 참조 카운팅됩니다. 이를 통해 복잡한 메모리 관리 상황을 안전하게 유지할 수 있습니다. 하지만 물건이 결국 돈을 지불하게 될 수도 있습니다. 참조 카운트 트래픽의 경우, 수명이 매우 단순하더라도 마찬가지입니다. 마지막으로, 클래스 인스턴스의 모든 필드에는 세밀한 배타성 검사가 적용됩니다. 실행 시점에 이루어지며, 이를 통해 기존 방식보다 더 유연한 별칭 지정 작업을 수행할 수 있습니다. 구조체에 대해서요. 하지만 다시 말하지만, 간단한 연산을 수행하는 유형은 전혀 이점을 얻지 못하고 오히려 비용을 부담할 수도 있습니다. 클래스 인스턴스는 매우 다재다능하지만, 필요 이상으로 용량이 클 수 있습니다. 이는 소액의 간접비입니다. 하지만 아무런 검사도 하지 않는 안전하지 않은 구현과 비교해 보면, 그 금액은 금방 쌓입니다.

    Swift 6부터는 이러한 사용 사례에 복사 불가능 구조체를 사용할 수 있습니다.

    구조체는 동적 할당이 필요하지 않습니다. 그래서 간접비 부담 요인 하나가 줄어들었네요. 그리고 그들은 대부분 검증 가능한 코스 독점권 확인 절차를 거칩니다. 컴파일 시점에 그렇습니다. 따라서 프로그램은 처음부터 해당 요소의 수가 더 적습니다. 그리고 이러한 문제점들은 최적화를 통해 해결하기가 더 쉽습니다. 하지만 복사 불가능한 구조체를 공유하는 것은 클래스를 공유하는 것보다 훨씬 더 많은 제약이 따릅니다. 또는 복사 가능한 구조체,

    디코딩 함수에서 참조 유형의 유연성 덕분에 가능합니다.

    동일한 디코더를 여러 번 참조하는 것은 문제가 없습니다. 그리고 둘 중 하나를 통해 decode 메서드를 호출합니다.

    하지만 복사할 수 없는 구조체에 대해 똑같은 작업을 하는 것은 오류입니다. 컴파일러는 객체 A가 B로 이동되었다는 사실을 즉시 진단할 것입니다. 그리고 나서 다시 사용되었습니다. 요약하자면, 간단한 객체 관리의 경우, 클래스에 비해 복사 불가능한 구조체를 사용하면 성능 면에서 많은 이점이 있습니다. 유연성이 떨어지기 때문에 항상 사용할 수 있는 것은 아닐 수도 있습니다. 더 구체적이죠. 하지만 그 대신 더 예측 가능한 성능을 얻을 수 있습니다.

    내가 가장 원하지 않는 것 여기서 논의할 내용은 C에서 Swift 호출하는 것입니다. 현재 모든 주요 플랫폼은 안전하지 않은 C 또는 C++ 코어를 사용하고 있습니다. 그리고 모든 안전한 언어는 그 핵심을 참조해야 합니다. 어떻게든. C와의 혼합은 안전한 언어의 일반적이고 예상되는 기능입니다. 어쨌든 어려운 경우가 많습니다.

    어려울 수 있는 이유 중 하나

    언어마다 기대치가 다르다는 것입니다. 한 언어가 다른 언어를 부를 때, 두 언어 모두의 기대치를 충족해야 합니다. 예를 들어, 가비지 컬렉션을 사용하는 언어에서는, C 언어에 객체 포인터를 전달하려면 특별한 협업이 필요할 수 있습니다. 객체가 정지해 있는 동안에는 이동하지 않도록 가비지 컬렉터와 함께 사용합니다. C 언어에서 참조한 내용입니다. 또 다른 이유는 대부분의 언어가 그렇기 때문입니다. 서로 잘 이해하지 못해요. 예를 들어, C 언어를 호출할 수 있는 많은 언어에서 상호 운용성을 위해서는 글루코스가 필요합니다. 그것은 C 헤더 파일을 설명합니다. 대상 언어 컴파일러가 C 헤더 파일을 읽을 수 없기 때문입니다. 그 코드를 작성하는 것은 지루한 일입니다. 하지만 다행히도 Swift 안전하지 않은 언어와의 상호 운용성을 고려하여 설계되었습니다.

    Swift 그러한 복잡성의 대부분을 제거합니다. 개발자를 위해 C 컴파일러 전체를 내장했습니다.

    헤더 파일에서 임의의 선언을 해석하고 사용 가능하게 만들 수 있습니다. 브리징 헤더에서 인라인 함수를 파싱하여 포함합니다. 프로젝트는 브리징 헤더에서 임의의 헤더를 포함할 수 있습니다.

    그리고 Swift 선언을 사용할 수 있도록 만들 수 있습니다. C 컴파일러가 자체 헤더 파일을 생성하도록 합니다.

    Doug가 초기에 선보였던 디코딩 예제를 다시 화면에 표시하겠습니다. Doug는 span을 사용한 구현 방식이 가장 유연한 옵션임을 보여주었습니다. 해당 구현은 고유한 백엔드로 사용되었습니다. 픽셀 값을 완전히 다른 방식으로 반환하는 다른 두 함수가 있습니다. 배열을 반환하는 첫 번째 함수입니다. 두 번째는 출력을 참조로 반환하는 방식입니다. 모드 X 프레임 구조로 변환합니다.

    Swift 6.3부터, 스팬 구현은 C 함수의 백엔드 역할도 할 수 있습니다. 더그가 처음 시작했던 것과 같은 것 말입니다.

    이것은 Doug가 소개한 C 구현체입니다. 마지막으로 한 번 더 자세히 살펴봅시다. 제가 그 코드를 삭제하고 신속한 구현으로 대체할 예정이기 때문입니다.

    이를 위해서는 먼저 다음이 필요합니다. 호환 가능한 프로토타입을 가진 Swift 함수가 되려면 목표 C 함수와 함께.

    여기에는 입력 포인터, 계정 등을 받는 코드가 준비되어 있습니다. 출력 포인터, 계정, 그런 다음 입력 포인터에 걸쳐 범위를 만들고 출력 포인터에 걸쳐 범위를 만듭니다. 그리고 이는 공통적으로 사용 가능한 코드인 Swift 백엔드를 호출합니다. 다음으로 해당 함수를 C 언어에서 사용할 수 있도록 노출해야 합니다. 이를 위한 두 가지 방법이 있습니다. 첫 번째 방법은 함수에 at c 속성을 추가하는 것입니다.

    C 언어에서 사용할 때 Swift 해당 타입을 변환합니다. 적절한 대응 C 유형으로. 예를 들어 Swift 의 Int32 타입은 int32t로 변환됩니다. 기본적인 정수형 정의가 예상되는 대응값으로 변환되는 것을 확인하겠습니다. 차트 시작 부분을 보세요. 보세요. 짧은 것에서 짧은 것으로. int의 끝을 참조하세요. 등등. int는 포인터 div t로 변환된다는 점에 유의하세요. 그리고. 이것이 바로 우리 코드가 허용하는 이유입니다. 구현 시 크기 t 대신 포인터 div t를 반환합니다. 구현할 함수가 브리징 헤더에 이미 표시되어 있는 경우. 두 번째 옵션은 C 조합에서 구현을 사용하는 것입니다. Objective-C 메서드를 사용할 때와 같이 생성된 헤더에 선언을 포함하는 대신 구현 단계에서 선언합니다. 이는 컴파일러에게 기존 선언을 찾도록 요청하는 것입니다. 브리징 헤더의 디코딩 함수에 대한 내용입니다.

    이 방법을 사용할 때. 컴파일러는 Swift 프로토타입이 C 프로토타입과 일치하는지 검증합니다. 호환되지 않으면 오류가 발생합니다.

    C 언어만 사용할 경우 Swift 인자 유형을 선택해야 합니다. 하지만 C 언어로 구현할 때는, 다른 변환 방식에도 적응할 수 있습니다. 예를 들어, C 프로토타입이 크기 T를 사용하는 경우, Swift Uint 대신 int를 매개변수로 받는 구현체도 허용합니다.

    지금은 방금 일어난 일을 되돌아볼 좋은 기회입니다. 제 오른쪽에 cats라는 C 함수가 있습니다. 그리고 사진 속 반려동물을 알아보는 개들.

    이미지 구조체에 대한 포인터를 인수로 받습니다. 그리고 애완동물 기록 버퍼에 대한 포인터입니다. 이미지 압축 해제를 위한 픽셀 메모리를 관리합니다. 그리고 디코딩 함수를 호출하여 이미지를 압축 해제합니다. 마지막으로, 고양이와 개를 식별하여 고양이가 어디에 있는지 찾아냅니다. 그리고 사진에 개들이 있어요.

    이전에는 이것이 읽기 코드의 C 구현을 호출했습니다. 오른쪽은 앞서 개들이 보였던 모습입니다.

    하지만 아무것도 변경하지 않고 C 언어로 구현하면 됩니다. 학계에서, 고양이들 그리고 개 기능은 이제 안전한 빨간색 코드 구현을 사용합니다.

    그리고 이는 Swift 에서 완벽하게 작동했습니다. Swift 컴파일러가 디코딩 구현과 일치할 수 있기 때문입니다. clang이 빨간색 코드에 대해 보는 것과 동일한 C 함수 프로토타입을 사용합니다.

    C에서 필요한 건 그게 전부입니다. 구현 단계에서는 C 코드베이스를 Swift 로 마이그레이션하는 데 매우 유용한 도구입니다. 안전한 언어로 새로운 기능을 작성하세요 C 호출자가 사용해야 할 때 사용됩니다.

    이제 여러분은 span을 통해 유형만 이동하고 C 언어 간의 상호 작용에 대해 배웠습니다. 그리고 Swift, 다음으로 해야 할 일은 다음과 같습니다. 첫째, 코드에서 엄격한 메모리 안전성을 확보하십시오.

    이를 통해 코드베이스에서 안전하지 않은 작업을 고려할 수 있습니다. 다음으로, span을 사용하여 연속된 메모리에 안전하게 접근하는 방법을 알아보세요. 먼저 안전하지 않은 버퍼 포인터 사용을 교체하는 것부터 시작하세요. 다음으로 안전하지 않은 리소스를 캡슐화하여 안전한 인터페이스를 만드세요. 가능한 경우 이동 유형 클래스만 사용하고 그렇지 않으면 다른 유형으로 변경합니다. 마지막으로, 안전하지 않은 코드를 점진적으로 마이그레이션하세요. Swift의 상호 운용 기능을 사용하여 Swift 로 변환합니다. 관심 가져주셔서 감사합니다. 메모리 안전성 부족은 오늘날 보안 버그의 가장 큰 원인입니다. 그리고 저는 여러분과 함께 더 안전한 세상을 만들어 나가기를 기대합니다.

    자, 그럼 오늘 마지막 발표를 드리겠습니다. 짧은 영상인데요, Xcode 에서 새니타이저를 사용하는 방법에 대한 실용적인 개요 코드의 버그를 찾아내기 위해. 댄을 무대 위로 환영해 주시기 바랍니다.

    안녕하세요, 저는 댄이고 Apple 에서 소프트웨어 엔지니어로 일하고 있습니다. 저는 보안 도구 팀 소속이고, 데이터 소독 도구를 담당하고 있습니다. 오늘 저는 보안 버그를 찾는 방법에 대해 이야기하려고 합니다. 기존 코드에 새니타이저를 추가하세요.

    이번 발표에서는 손 소독제의 개념을 소개하겠습니다. 그리고 나서 저는 그중 두 가지, 즉 주소 소독제에 대해 이야기하겠습니다. 그리고 실 살균제는 가장 강력한 살균제 두 가지입니다.

    먼저 일반적인 개념부터 소개하겠습니다.

    살균제는 세균을 찾아내는 도구입니다. 그들은 코드에 불필요한 회계 처리와 런타임 검사를 추가합니다. 엄격한 런타임 검사 때문에, 그것들은 당신이 미처 몰랐던 버그를 발견하는 데 도움을 줄 수 있습니다. 고객에게 피해가 발생하기 전에 조치를 취하세요. 그것들은 또한 매우 귀중할 수 있습니다. 도저히 해결할 수 없을 것 같은 오류 보고서의 근본 원인을 찾아내기 위해서입니다.

    이제 소독제가 무엇인지 정의했으니, 주소 소독제에 대해 이야기해 보겠습니다. 간략히 설명하면, 주소 검증 도구가 오류를 발견하고 발생시킵니다. 프로그램이 메모리를 잘못 사용할 때 발생합니다.

    guard malloc과 같은 도구는 힙 메모리의 문제만 감지하는 것과 달리, 주소 검증 도구는 스택 및 전역 변수 영역의 문제도 감지할 수 있습니다. 또한 바이트 수준의 정밀도로 검사를 수행합니다. 즉, 아주 사소한 규칙 위반이라도 적발될 것이라는 의미입니다. 제가 다루는 버그 유형 몇 가지를 살펴보겠습니다. 손 소독제를 찾을 수 있습니다. 이 코드 조각에서. 저는 이 Nsstring 변수의 원본을 그대로 복사할 계획입니다. 눈에 잘 띄지 않을 수도 있지만, 메모리 범위를 벗어난 접근 오류가 있습니다.

    여기서 그 이유를 설명하겠습니다. 오른쪽에 표시된 원본의 기본 바이트에 대한 포인터를 가져옵니다.

    그런 다음 복사본에 원래 도트 길이 바이트를 할당합니다.

    그리고 바로 여기서부터 문제가 생기기 시작합니다.

    원래 점 길이로는 바이트 수를 알 수 없습니다. 실제로 UTF 16 코드 단위의 개수를 알려줍니다. 손을 흔드는 이모티콘은 이 두 개로 이루어져 있습니다.

    따라서 원시 복사본은 이제 5바이트 ​​할당을 가리킵니다.

    다음으로, 원본 데이터의 바이트를 복사본 데이터로 복사합니다. 하지만 마지막 두 바이트는 할당 범위를 벗어나게 됩니다. 이런 종류의 까다로운 버그는 쉽게 간과될 수 있습니다. 그리고 악용될 수 있습니다.

    다행히 Address Sanitizer가 이를 감지합니다. 그리고 여기서 버퍼 오버플로가 발생할 수 있다고 경고합니다.

    주소 검증 도구가 감지한 또 다른 버그 유형은 '사용 후 해제'입니다.

    이 C++ 예제에서는 표준 탭 벡터를 유지합니다. 오른쪽에 현재 활성화된 탭에 포인터를 고정해 두세요. 벡터에 요소 하나를 위한 공간이 예약되어 있는 것을 확인할 수 있습니다. 하지만 아직 사람이 살지 않는 곳입니다.

    첫 번째 탭인 메일 탭을 열고 활성 탭으로 설정했습니다.

    그러고 나서 다른 탭을 엽니다. 뉴스. 이로 인해 매개체가 감염 용량을 늘려야 합니다.

    이는 곧 새로운 할당 영역을 생성하고 해당 영역으로 요소를 이동시키는 것을 의미합니다.

    안타깝게도 이 일이 발생했을 때 active 값은 업데이트되지 않았습니다. 그리고 지금은 할당 해제된 메모리를 가리킵니다.

    활성 주소를 통해 탭 포인터를 다시 로드하려고 하면 문제가 발생합니다. sanitizer가 할당 해제된 메모리 사용을 나타내는 오류를 발생시킵니다.

    예시에서 보여지는 바와 같습니다. Objective-C Objective-C 가 모두 지원됩니다. 여기에는 수동 및 자동 참조 계수법이 포함됩니다.

    마지막으로 Swift 도 마찬가지입니다. 순수 Swift 에서는 메모리를 잘못 사용하는 경우가 거의 없을 것입니다.

    하지만 중요한 점은 Address Sanitizer가 여러 언어에서도 작동한다는 것입니다. 여기에 숫자로 이루어진 Swift 배열이 있습니다.

    C 함수에서 이 배열을 사용하려면, 저는 안전하지 않은 버퍼 포인터를 사용하겠습니다. 포인터 nums가 배열의 첫 번째 요소를 가리키고 있음을 주목하십시오.

    이제 합계 함수를 호출하겠습니다. 이렇게 하려면 배열의 시작 부분을 가리키는 포인터와 배열의 길이를 전달해야 합니다.

    합계 함수는 배열의 각 요소를 순회하며 모두 더합니다.

    하지만 제가 여기서 전형적인 실수를 저질렀네요. Len보다 작은 동안 반복하는 대신, 이하를 사용했습니다. 결과적으로 최종 결과는 범위를 벗어나게 될 것입니다.

    주소 검증 도구가 이를 감지하고 버퍼 오버플로에 대한 오류를 발생시킵니다. 이는 사용하는 데 있어 발생하는 보안 버그의 유형이라는 점에 유의할 필요가 있습니다. C에 대한 경계 안전 확장이 해결됩니다.

    주소 소독제에 대해 알아야 할 사항은 다음과 같습니다. 첫째, 이는 개발 중에만 사용해야 하며 런타임 보안 강화용으로는 사용할 수 없습니다.

    이처럼 강력한 도구라면 말이죠. 메모리 사용량과 실행 시간 측면에서 오버헤드가 낮으며, 각 항목당 약 2~3배 정도 더 효율적입니다. 테스트 중에 발생하는 버그를 사전에 찾아내는 데 매우 효과적입니다. 고객에게 좋은 인상을 주기 위해서는 가능한 한 많은 테스트를 진행하는 것이 중요합니다. 활성화되면,

    유닛 테스트 및 UI 테스트와 같은 자동화된 테스트에 이 기능을 활성화하세요. 개발 중 수동 테스트를 수행할 때 활성화하십시오. 그리고 그 도구를 최대한 활용하기 위해서입니다. 예외적인 상황과 드문 경로를 발생시키는 것이 정말 중요합니다.

    개발 중에 주소 검증 기능을 활성화하려면. 먼저 제품 메뉴를 열어 스키마 편집기로 이동합니다. 그다음 스키마 하위 메뉴를 열고 스키마 편집을 선택합니다.

    여기에서 운영 계획으로 이동하세요. 그런 다음 진단 탭에서 주소 정리 확인란을 선택합니다.

    테스트 플랜에 대해 주소 검증 기능을 활성화하려면 다음 단계를 따르세요. 제품 메뉴를 열고, 테스트 계획을 열고, 테스트 계획을 편집하세요.

    구성 탭을 열고 런타임 정리 섹션으로 스크롤합니다.

    그런 다음 주소 새니타이저 행을 선택하고 켜짐으로 설정합니다.

    이제 주소 검증 도구를 사용하여 테스트하는 방법을 보여드리겠습니다.

    네, 여기 혼합 언어 예제 슬라이드에 있는 제 코드가 있습니다. 저는 Swift 배열의 숫자를 가져옵니다. 그런 다음 저는 이것을 가리키는 안전하지 않은 버퍼 포인터를 가져오겠습니다. 그리고 그 안에 제 C 함수 sum을 호출하세요. 각 요소를 순회하면서 합산하겠습니다. 그리고 결과를 Swift 로 반환합니다.

    그다음에는 배열과 결과를 출력하겠습니다. 그럼 지금 실행해 보겠습니다.

    우선, 제 프로그램이 성공적으로 실행된 것을 확인할 수 있습니다.

    하지만 여기 있는 값은 확실히 올바르지 않습니다.

    이제 제품 스키마 편집에서 주소 새니타이저를 활성화하겠습니다. 주소 변조 방지 확인란을 선택하면 됩니다.

    따라서 실행 버튼을 클릭하면 소독 과정을 거쳐 다시 빌드됩니다. 그리고 곧바로 뭔가를 잡았다는 걸 알 수 있었어요. 이 줄에서 힙 버퍼 오버플로가 발생했습니다.

    왼쪽에는 이 오류로 이어진 호출 스택이 보입니다. 이것이 즉시 가능하다는 것을 알 수 있을 뿐만 아니라 64바이트 힙 할당 후.

    이 슬라이드 메뉴에서 할당이 어디에 있었는지 확인할 수 있는데, 예상대로입니다. 제가 Swift 배열을 생성했을 때였습니다.

    스택 프레임으로 돌아갑니다. 저는 실시간 디버깅 세션에 참여하고 있습니다. 그래서 현재 변수들의 값을 확인할 수 있습니다. 내가 렌과 똑같다는 걸 알 수 있어. 이는 제 루프 경계 조건에 문제가 있다는 것을 알려줍니다. 제 슬라이드에서 설명드린 바와 같습니다. 그 이유는 여기에 등호가 하나 더 있기 때문입니다. 그래서 해당 부분을 제거하고 애플리케이션을 다시 빌드해야 합니다.

    이제 실행이 성공적으로 완료되었는지 확인해 보겠습니다. 게다가 이제는 합계에서 정확한 값을 얻고 있습니다.

    네. 이제 슬라이드로 돌아가겠습니다.

    다음으로 소개해드릴 손 소독제는 프레드 손 소독제입니다.

    Fred Sanitizer는 데이터 경쟁 및 기타 동시성 문제를 감지합니다.

    데이터 경쟁은 한 스레드가 메모리 위치에 쓰기 작업을 수행할 때 발생합니다. 그리고 다른 스레드가 동기화 없이 동일한 메모리 위치에 접근합니다.

    오른쪽 코드 예제에서는 대기 중인 큐에서 첫 번째 항목을 가져옵니다. 전송하고, 해제한 다음, 헤드를 증가시키세요. 다른 스레드에서 동일한 작업을 수행하기 전까지는 잘 작동합니다. 이제 제게는 두 개의 작업자 스레드가 있습니다. 그리고 여기에는 여러 작업이 섞여 있을 수 있는 상황이 있습니다.

    프레드 원은 값이 0인 헤드를 읽습니다.

    프레드 투는 또한 값이 0인 헤드를 읽습니다.

    프레드는 보류 중인 메시지를 보내고 객체를 해제합니다.

    그런 다음 head의 값을 1로 증가시킵니다.

    데이터 경쟁이 시작됩니다. 프레드 2에 대한 읽기 작업과 프레드 1에 대한 쓰기 작업이 어떤 순서로 발생하는지에 따라 달라집니다. 이 경우 프레드 2의 인덱스 값은 다를 수 있습니다. 프레드 2가 헤드의 오래된 값을 가지게 되면 보류 중인 0으로 읽히게 됩니다. 프레드가 방금 풀어준 주소 소독기가 사용을 감지합니다. 여기서 무료로 발생한 후에, 그리고 이 실행에서는 자유 사용 이후에 발생했습니다.

    이것은 동일한 코드가 동일한 두 개의 스레드에서 실행되는 것입니다. 하지만 이번에는 그 사이에 인터리빙 작업이 없습니다. 주소 검증 도구가 이 실행에서 문제를 감지하지 못했습니다.

    하지만 좋은 소식이네요. 예상했던 결과가 나오긴 했지만요. 스레드 검사기가 여전히 여기에 문제가 있음을 감지하고 경고 메시지를 표시합니다. 두 번째 게시글의 내용은 데이터 경쟁의 일부입니다. 그리고 프레드 새니타이저는 메모리 접근 경쟁 상황도 보여줍니다.

    이 글은 첫 번째 게시글에 대한 내용입니다. 이것이 바로 실 살균제가 매우 유용한 이유입니다. 겉보기에 재현 불가능해 보이는 버그 보고서의 근본 원인을 찾기 위해서입니다.

    이 문제를 해결하기 위해 직렬 디스패치 큐를 사용합니다. 각 섹션이 원자적으로 실행되고 읽기가 제대로 이루어지도록 하기 위해 그리고 앞서 작성된 내용은 오른쪽에 동기화됩니다. 이것들을 dispatch async로 감쌌습니다. 그리고 그것들은 전용 직렬 큐에서 실행될 것입니다.

    Swift 동시성 기능을 사용하면 데이터 경쟁을 방지할 수 있습니다.

    스레드 새니타이저는 주소 새니타이저와 동일한 방식으로 활성화됩니다.

    두 가지는 상호 배타적이라는 점에 유의하십시오. 따라서 한 번에 하나만 활성화하여 실행할 수 있습니다.

    자동화 테스트의 경우, 테스트 계획에 대해 두 가지 다른 구성을 만들 수 있습니다. 하나는 주소 검증 기능이 활성화된 것이고, 다른 하나는 스레드 검증 기능이 활성화된 것입니다.

    데이터 정리 도구는 메모리 무결성 강화 도입에 중요한 역할을 합니다.

    주소 검증 도구는 잘못된 메모리 접근을 찾아 수정하는 데 도움을 줍니다. 이로 인해 Emmy 기능이 활성화될 때 충돌이 발생합니다. 스레드 새니타이저는 데이터 경쟁을 찾는 데 도움이 됩니다. 이는 종종 무료 사용 후 사용으로 이어집니다. 다행히도, 에미는 사용 후 무료 사용이 발생하면 충돌을 일으킵니다. 착취를 방지하는 것 하지만 이는 고객들에게 불만을 야기할 것입니다.

    스레드 살균제를 사용하여 버그를 찾아 수정하면 고객의 안전을 지킬 수 있습니다. 그리고 행복해요.

    다음으로 해야 할 일은 다음과 같습니다. 먼저 Address Sanitizer에서 테스트 계획의 구성을 확인하세요. 특히 코드베이스에 C, C++, 또는 Objective-C 사용하는 경우라면 더욱 그렇습니다.

    그다음에는 스레드 새니타이저를 사용하세요. C 언어나 동시성 프로그래밍 언어를 사용하는 경우 테스트 계획에 해당 내용을 추가하세요. Swift.

    Swift 코드에서 데이터 경쟁을 방지하려면 Swift 동시성 기능을 도입하세요.

    그리고 마지막으로, 다음에 설명할 수 없는 사고 보고서를 받게 될 때 또는 복제를 시도하고, 살균제를 사용하여 문제가 있는지 확인해 보세요. 어쩌면 그들이 그러한 나쁜 상황에 이르게 된 원인에 대한 단서를 제공할 수 있을지도 모릅니다. 감사합니다. 이제 커트에게 마이크를 넘기겠습니다.

    고마워요, 댄. 이것으로 오늘 발표를 마무리하겠습니다. 발표를 해주신 모든 분들께 진심으로 감사드립니다.

    오늘 다룬 내용에 덧붙여 설명드리자면, 개발에 대해 더 자세히 알아볼 수 있는 가장 좋은 방법 중 하나 Apple 플랫폼용 콘텐츠는 WWDC 영상들을 통해 제공됩니다. 그리고 다른 Apple 행사와의 만남도 있습니다. 수백 개의 동영상이 있습니다. 해당 영상들은 Apple 개발자 웹사이트나 개발자 앱에서 시청하실 수 있습니다. 익숙한 얼굴들을 발견할 수도 있을 겁니다.

    개발자 센터와 온라인에서 모두 참여해주신 여러분께 감사드립니다. 이제 온라인으로 작별 인사를 드리겠습니다. 안녕. 그리고 여기 계신 모든 분들을 로비로 초대하여 간단한 다과를 함께 나누도록 하겠습니다. 즐거운 대화였습니다. 감사합니다.

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. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침