Unity 앱에서 URL 핸들러와 OpenURL을 안전하게 사용하는 방법

유니티 보안 팀은 유니티 크리에이터가 더욱 신뢰할 수 있는 게임과 애플리케이션을 제작할 수 있도록 지원하는 데 중점을 두고 있습니다. 이 블로그 시리즈에서 Unity로 더욱 안전한 게임과 앱을 제작하기 위한 팁, 기술, 권장 사항을 확인해 보세요.
오늘부터 유니티는 유니티로 안전하게 개발하는 방법에 대한 블로그 시리즈를 시작합니다. 이 시리즈는 유니티 개발자가 게임과 애플리케이션에 직접 적용할 수 있는 콘텐츠를 제공합니다. 유니티 제품 및 서비스 사용의 모범 사례를 중심으로 기본 지식부터 고급 지식까지 다양한 주제를 다루고자 합니다. 읽고 싶은 주제가 있으면 알려주세요. 여러분의 피드백을 기다리겠습니다. 이 블로그의 주요 초점은 URL 핸들러에 대한 개요입니다.
URL 및 파일 핸들러는 파일 유형을 지정된 파일을 열 수 있는 설치된 프로그램과 연결하지만 위험성이 따릅니다. 예를 들어 로컬 컴퓨터에서 로컬 드라이브에 있는 PDF 파일을 더블 클릭하여 열면 운영 체제가 파일 처리기 목록을 참조하여 해당 파일 유형에 할당된 프로그램을 선택하므로 PDF를 올바르게 표시할 수 있는 프로그램에서 열 수 있습니다. 파일 처리기는 일반적으로 파일 확장자(예: .pdf - 파일 이름 끝에 있는 접미사)를 사용하여 파일 처리 방법을 결정합니다.
유사한 메커니즘인 URL 핸들러는 경로 접두사를 기반으로 URL을 여는 방법을 결정합니다. 예를 들어 기본 브라우저를 여는 유비쿼터스 https:// 프로토콜을 들 수 있습니다. 일반적인 URL 체계의 또 다른 예로는 file://c:/windows/system32/drivers/gmreadme.txt가 있으며, 실행 대화 상자에 이 URL을 입력하면 Windows에서 이 라이선스 파일을 메모장에서 열게 됩니다.
URL 핸들러는 애플리케이션을 실행할 때 사용자의 시간을 절약해주는 운영 체제의 유용한 기능입니다. 하지만 이 편리한 메커니즘은 때때로 안전하지 않을 수 있습니다.
유니티 에디터와 유니티 런타임은 .NET 프레임워크뿐만 아니라 특정 유니티 스크립팅 API인 Application.OpenURL을 통해서도 URL 핸들러의 프로그래밍 방식 사용을 지원합니다. 게임 개발자는 플레이어가 게임에서 링크를 클릭하면 로컬 시스템의 웹 브라우저를 실행하도록 OpenUrl을 사용하는 경우가 많습니다. 그러나 게임 개발자가 Application.OpenURL에 전달되는 내용을 적절히 살균하지 않으면 플레이어가 위험에 처할 수 있습니다.
이 스크립팅 API는 본질적으로 안전하지 않지만, 신뢰할 수 없는 입력이 전달된 URL의 일부로 사용되는 경우에는 주의를 기울여야 합니다.
신뢰할 수 없는 입력/데이터는 신뢰할 수 있는 출처에서 제공되지 않은 모든 데이터를 의미합니다. 그렇다면 신뢰할 수 있는 출처란 무엇일까요? 이 글의 맥락에서는 엄격한 HTTPS가 활성화된 엔드포인트만 신뢰할 수 있는 것으로 간주해야 합니다.
신뢰할 수 없는 입력의 예는 여러 가지가 있습니다. 치트 방지 시스템을 설계하는 경우 플레이어의 로컬 파일 시스템을 신뢰할 수 없는 것으로 간주해야 합니다. 멀티플레이어 게임을 개발하는 경우 모든 플레이어를 신뢰할 수 없는 것으로 간주해야 합니다.
공개/개인 키 암호화 등을 활용하여 데이터/입력을 보호하는 다른 방법도 있지만, 이 글의 범위를 벗어납니다. (이에 대해 더 자세히 알고 싶다면 댓글을 남겨주세요.)
이러한 핸들러는 사용자에게 큰 편의를 제공하지만 내재된 위험을 수반합니다. 다음은 Application.OpenURL의 안전하지 않은 사용의 예입니다:
using UnityEngine;
System.Collections를 사용합니다;
public class VulnerableBrowserClass: 모노비헤이비어 {
// 플레이어가 게임 포럼에서 클릭한 링크의 URL을 전달합니다.
void OpenBrowser(string url_from_chat) {
Application.OpenURL(url_from_chat); // ←- 여기는 불량; 값이 위생 처리되지 않았습니다.
}
}
그림 1. Application.OpenURL의 안전하지 않은 사용 예시
이 예시에서는 게임 내 댓글 시스템을 통해 사용자가 링크를 공유할 수 있으며, 사용자가 링크를 클릭하면 VulnerableBrowserClass.OpenBrowser 함수가 호출됩니다.

그림 2. 잠재적으로 위험한 링크가 있는 샘플 시나리오
의심하지 않는 사용자에게 잠재적으로 위험한 애플리케이션의 링크를 보내는 것이 얼마나 쉬운지 알 수 있습니다(그림 2). 그림 1과 같이 해당 URL이 Application.OpenURL로 직접 전달되면 피해자의 컴퓨터는 해당 링크에서 애플리케이션을 즉시 실행하여 공격자가 피해자의 시스템을 제어할 수 있게 됩니다.
위 이미지에서 공격자는 위의 링크를 채팅 창에 https://SuperLeetCheats.com/VulnTheGame 로 표시되도록 형식을 지정할 수 있지만, 실제 링크는 파일://leethaxorz.net/super_malware.exe에 있는 멀웨어로 이동하도록 할 수 있습니다. 여기서 문제는 사용자가 서로 링크를 보낼 수 있다는 것이 아니라, 위의 코드 샘플(그림 1)에서 볼 수 있듯이 사용자(잠재적으로는 공격자)가 보낸 링크를 아무런 유효성 검사나 위생 처리 없이 Application.OpenURL로 직접 전달하는 데 있습니다. 이러한 살균 처리 없이 위의 링크를 클릭하면 Unity 에디터가 파일을 대상 플레이어의 OS에 직접 전달하여 공격자의 멀웨어가 실행될 수 있습니다.
Application.OpenURL을 사용하는 가장 안전한 방법은 신뢰할 수 없는 데이터와 함께 사용하지 않는 것입니다. 개발자 또는 서버가 제공하는 신뢰할 수 있는 전송(예: HTTPS)을 통해 제공되는 URL을 여는 경우에만 사용하세요.
원격 구성을 사용하는 경우(예: 새 업데이트를 위한 콘텐츠 URL 목록을 호스팅하는 경우) 이 데이터는 HTTPS를 통해서만 검색되도록 하고 엄격하게 적용해야 합니다. 항상 이 방식으로 원격 콘텐츠를 검색하세요.
참고: HTTPS는 위의 공격에서 설명한 것처럼 신뢰할 수 없거나 소독되지 않은 입력으로 인한 앱의 취약점을 해결하지 못합니다. 하지만 전송 중에 플레이어에게 전송되는 데이터가 변조되지 않았는지 확인할 수 있습니다.
신뢰할 수 없는 출처의 데이터에 OpenUrl을 꼭 사용해야 한다고 결정했다면 신뢰할 수 없는 출처에서 받은 입력을 위생 처리하는 데 최선을 다해야 합니다. 이를 수행하는 방법에는 정규식 패턴 일치, .Net 라이브러리를 통한 URL 구축 또는 외부 살균 라이브러리 활용 등 몇 가지가 있습니다. 그러나 이러한 완화 조치 중 어느 것도 100% 효과가 있는 것은 아니며, 어떤 솔루션을 선택하든 신뢰할 수 없는 데이터에 Application.OpenUrl(및 유사한 함수)을 사용할 경우 잠재적인 위험이 발생할 수 있습니다.
또한 위의 그림 2에서 볼 수 있듯이 사용자가 해당 링크 뒤에 어떤 URL이 있는지 알 수 있는 방법이 없습니다. 최소한 방문하려는 전체 URL이 포함된 프롬프트를 사용자에게 제공하세요. 하지만 사용자들은 눈앞에 놓인 프롬프트를 무턱대고 클릭하는 것으로 알려져 있으므로 이를 강력한 솔루션으로 간주해서는 안 됩니다.
특히 게임 내 채팅, 리뷰, 댓글 등 사용자가 일반적으로 게임 외부에 있는 콘텐츠를 인터넷에서 공유하고자 하는 리치 미디어 애플리케이션과 소셜 미디어와 유사한 기능에서 개발자가 OpenURL 및 파일 핸들러를 사용하는 것은 매우 일반적입니다. 또한 구성 파일 편집과 같은 일반적인 생산성 시나리오에서는 사용자가 선호하는 코드 편집 애플리케이션을 열어 OS에 링크를 전달하여 사용자가 편리하게 사용할 수 있도록 할 수 있습니다. Application.OpenURL은 파일 핸들러를 지원하는 플랫폼 독립적인 API로, Unity 개발자가 모든 플랫폼에 맞는 핸들러를 직접 작성하지 않아도 됩니다.
아니요. 위에서 설명한 것처럼 대부분의 운영 체제에서 공통적으로 사용되는 기능이며 많은 언어와 프레임워크에서 지원됩니다. 이 두 네이티브 .Net 라이브러리는 모두 Application.OpenURL과 동일한 기능을 제공하므로 Windows API Windows.System.LauchURIAsync (유니버설 윈도우 플랫폼[UWP] 앱용) 또는 무서운 System.Diagnostics.Process.Start의 사용에 유의하세요. LaunchURIAsync를 사용하면 Windows의 보안 애플리케이션 샌드박스 내에서 애플리케이션을 시작할 수 있으며, Process.Start를 사용하여 로컬 시스템에서 모든 실행 파일을 시작할 수 있습니다. 또한 일부 네이티브 OS 호출은 동일한 기능을 제공합니다 (예: Apple의 open(_:options:completionHandler:)). 이러한 모든 유형의 API에 신뢰할 수 없고 위생 처리되지 않은 입력이 전달되면 쉽게 악용될 수 있습니다.
Unity로 개발할 때 보안 모범 사례를 실천하고 유지하는 데 중요한 주제에 대한 기사를 정기적으로 게시할 예정입니다. 향후 주제에는 게임 데이터의 안전한 전송과 보안 소프트웨어 개발 수명 주기(SSDLC)의 민주화가 포함됩니다. 또한 내부 지침과 보안 도구의 일부를 오픈소스화하기 위해 노력하고 있습니다.
향후 글에서 더 자세히 알아보고 싶은 보안 주제가 있나요? 문의 주세요!
보안 권고 사항을 비롯하여 Unity 보안에 대해 자세히 알아보세요.
