[Electron] 2. 일렉트론이 보안상 까다로운 이유
2024.12.23 - [Desktop/Electron] - [Electron] 1. 왜 일렉트론(Electron)인가
[Electron] 1. 왜 일렉트론(Electron)인가
닭 잡는데 소 잡는 칼 쓰는 상황개발 1년 차가 조금 넘어갈 무렵, 다수의 키오스크 기기 안에 들어갈 정보 안내성 프로그램을 제작하는 일을 맡았습니다. 전시, 미디어 아트를 다루는 회사 특성
rediscovery.tistory.com
이전 글에서는 일렉트론을 선택한 이유와, 장단점을 살펴보았습니다. 이번 글에서는 일렉트론이 왜 보안상 다른 앱 프레임워크에 비해서 까다로운지 살펴보도록 하겠습니다.
일렉트론은 다 할 수 있다
일렉트론의 구조는 전 글에서 살펴보았습니다만, 다시 간략하게 말하자면 chromium(웹 브라우저) + Node.js(자바스크립트 런타임)으로 구성되어 있습니다. 그러나 이들이 특별하게 위험한 프로그램들은 아닙니다. 웹 브라우저야 컴퓨터의 기본 프로그램에 포함되는 필수 항목이기도 하고, 런타임은 컴퓨터 언어를 실행시켜 주는 환경이니 없으면 프로그램이 동작할 수가 없겠지요. 그러나 일렉트론 Docs의 보안 항목을 보면 상당한 압박이 느껴질 수 있습니다.
https://www.electronjs.org/docs/latest/tutorial/security
Security | Electron
A set of guidelines for building secure Electron apps
www.electronjs.org
자세한 내용은 여기서 확인 가능합니다.
보안 체크 리스트 항목이 19개나 되는 마당에 "at least" 라고 이 리스트가 지켜야 할 최소한이라고 명시하고 있습니다. 그런데 일렉트론은 왜 보안 관련해서 계속 상기 시키고 있는 것일까요? 이유는 웹 브라우저와 런타임이 합쳐졌을 시의 보안 위험의 파급력 때문입니다.
우선 웹 브라우저의 특성을 생각해봅시다. 웹 브라우저는 스크립트를 외부에서 받아 실행하는 기능을 갖고 있습니다. 그를 통해서 다양한 웹사이트에서 필요한 기능을 수행할 수 있지요. 하지만 외부 스크립트가 안전하지 않을 시 사용자는 보안 위험에 처하게 됩니다. 대표적으로 XSS , CSRF 1 등의 공격이 있습니다. 일렉트론의 chromium 은 웹 브라우저 엔진인 만큼 이러한 보안 위험에 노출되어 있습니다. 2
이번엔 Node.js 쪽도 살펴 보겠습니다. Node.js 는 자바스크립트 런타임으로, 컴퓨터에서 자바스크립트로 작성된 코드를 실행할 수 있는 환경을 제공해 줍니다. 일반적으로 런타임 자체만으로는 외부에서 공격하는 것을 걱정하지는 않습니다. 하지만 웹 브라우저와 밀접하게 연결된 Node.js 라면 비로소 문제가 발생합니다. chronium을 통해 수신한 악의적인 스크립트나 요청을 Node.js 가 그대로 받아 실행해 버리는 무지막지한 일이 발생할 수 있습니다.
간략한 원격 코드 실행(Remote Code Execution, RCE) 시나리오를 예로 들어 보겠습니다.
1. 취약한 URL 로딩
개발자는 BrowserWindow.loadURL() 메서드를 사용하여 외부 URL을 로드하는 알림 기능을 구현했습니다.
const { BrowserWindow } = require('electron');
function openNotification(url) {
const notificationWindow = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
nodeIntegration: true, // Node.js 통합 활성화 (취약점 발생 가능)
contextIsolation: false // 컨텍스트 분리 비활성화
}
});
notificationWindow.loadURL(url);
}
2. 공격자의 접근
공격자기 악성 URL을 공유합니다. 해당 URL 에는 악성 JavaScript 코드가 Electron의 Node.js 에 접근하는 코드가 포함되어 있습니다.
<script>
const fs = require('fs');
// 파일 시스템 내부에 쓰기 작업
fs.writeFileSync('C:\\Users\\Victim\\Desktop\\hacked.txt', '해킹 성공!');
// 계산기 실행
require('child_process').exec('calc.exe');
</script>
3. 사용자가 악성 URL을 클릭
사용자가 공격자가 보낸 URL을 클릭하면 애플리케이션이 BrowserWindow에서 해당 URL을 로드합니다. 미비한 보안 설정으로 인해, 악성 JavaScript가 Node.js 에 접근할 수 있게 됩니다.
4. 원격 코드 실행
공격자가 배포한 악성 스크립트는 사용자의 파일 시스템에 접근하여 임의의 파일을 생성하거나 삭제할 수 있습니다. 이 외에도 랜섬웨어나 악성 소프트웨어 설치, 민감한 사용자 정보 등을 탈취할 수 있습니다.
핵심은 웹 브라우저와 Node.js 의 분리
위와 같은 보안 위험 때문에 일렉트론에서는 chronium과 node.js 를 분리시켜 놓았습니다. 웹 브라우저에서 받은 스크립트가 바로 런타임에 영향을 끼치지 못하도록 하기 위해서 입니다. 하지먼 이 둘이 하나의 앱으로 작동하기 위해서는 서로간의 통신이 필요합니다. 때문에 일렉트론에서는 양 프로그램 사이에 허가된 요청만 수행할 수 있도록 하는 일종의 다리를 만들었습니다. 그 결과 개별적 프로세스로 실행되는 chronium 과 node.js 는 각각 renderer 프로세스, main 프로세스라고 불리고, 이 둘을 있는 다리는 IPC 통신이 된 것입니다. 보안 설정에 대한 실제 설정 방법은 이후에 추가로 설명해 보도록 하겠습니다.
지금까지 일렉트론이 가지고 있는 보안 위험과, 보안 설정 필요성에 대해 알아보았습니다. 이는 API 상의 검증과 네이티브 시스템상의 권한 정도만 신경 써야 하는 다른 애플리케이션에 비해 보안 설정들이 번거롭게 느껴질 수도 있겠습니다만, 일렉트론이 사용하는 기술의 보안 위험에 경각심을 가지고, 권장되는 보안 수칙들을 따르는 것이 안전하고 신뢰할 수 있는 앱을 만드는데 필수적임을 알아야 하겠습니다.