확장 프로그램은 브라우저 내에서 특별 권한을 갖게 되는데, 이로 인해 공격자에게 매력적인 목표물이 됩니다. 확장 프로그램이 공격을 당하면 해당 프로그램의 모든 사용자는 원치 않는 악성 침입에 취약해집니다. 이러한 관행을 통합하여 확장 프로그램을 안전하게 유지하고 사용자를 보호하세요.
개발자 계정 보호
확장 프로그램 코드는 Google 계정을 통해 업로드되고 업데이트됩니다. 개발자 계정이 도용되면 공격자가 악성 코드를 모든 사용자에게 직접 푸시할 수 있습니다. 보안 키를 사용하여 2단계 인증을 사용 설정하여 이러한 계정을 보호하세요.
적절한 구성원 역할 사용
게시자에게 여러 구성원이 있는 경우 각 사용자에게 부여된 역할이 적절한지 확인합니다.
HTTP를 사용하지 않음
데이터를 요청하거나 전송할 때는 HTTP 연결을 피하세요. 모든 HTTP 연결에 도청자가 있거나 수정사항이 포함되어 있다고 가정합니다. HTTPS는 대부분의 중간자 공격을 방지하는 보안 기능이 내장되어 있으므로 항상 선호해야 합니다.
최소 권한 요청
Chrome 브라우저는 매니페스트에서 명시적으로 요청된 권한에 대한 확장 프로그램의 액세스를 제한합니다. 확장 프로그램은 종속된 API와 웹사이트만 등록하여 권한을 최소화해야 합니다.
확장 프로그램의 권한을 제한하면 잠재적 공격자가 악용할 수 있는 항목이 제한됩니다.
교차 출처 fetch()
확장은 fetch() 및 XMLHttpRequest()만 사용하여 확장 프로그램과 권한에 지정된 도메인에서 리소스를 가져올 수 있습니다. 두 호출 모두 서비스 워커의 fetch 핸들러에 의해 가로채집니다.
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"host_permissions": [
"https://developer.chrome.com/*",
"https://*.google.com/*"
],
"manifest_version": 3
}
위 샘플의 확장 프로그램은 권한에 "https://developer.chrome.com/*" 및 "https://*.google.com/*"를 나열하여 developer.chrome.com 및 Google 하위 도메인의 모든 항목에 대한 액세스를 요청합니다. 확장이 보안 침해를 당하더라도 일치 패턴을 충족하는 웹사이트와만 상호작용할 권한이 있습니다. 공격자는 "https://user_bank_info.com"에 대한 액세스 권한이 제한되거나 "https://malicious_website.com"와 상호작용할 수 있는 기능이 제한됩니다.
매니페스트 필드 제한
매니페스트에 불필요한 키와 권한을 포함하면 취약점이 발생하고 확장 프로그램이 더 눈에 띄게 됩니다. 확장 프로그램이 사용하는 매니페스트 필드로 제한합니다.
외부에서 연결 가능
"externally_connectable" 필드를 사용하여 확장 프로그램이 정보를 교환할 외부 확장 프로그램과 웹페이지를 선언합니다. 확장 프로그램이 외부에서 연결할 수 있는 사용자를 신뢰할 수 있는 소스로 제한합니다.
{
"name": "Super Safe Extension",
"externally_connectable": {
"ids": [
"iamafriendlyextensionhereisdatas"
],
"matches": [
"https://developer.chrome.com/*",
"https://*.google.com/*"
],
"accepts_tls_channel_id": false
},
...
}
웹 액세스 가능 리소스
"web_accessible_resources" 아래에서 웹으로 리소스에 액세스할 수 있도록 하면 웹사이트와 공격자가 확장 프로그램을 감지할 수 있습니다.
{
...
"web_accessible_resources": [
{
"resources": [ "test1.png", "test2.png" ],
"matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
}
]
...
}
웹 액세스 가능 리소스가 많을수록 잠재적인 공격자가 악용할 수 있는 방법이 많아집니다. 이러한 파일은 최소한으로 유지하세요.
명시적 콘텐츠 보안 정책 포함
매니페스트에 확장 프로그램의 콘텐츠 보안 정책을 포함하여 크로스 사이트 스크립팅 공격을 방지합니다. 확장 프로그램이 자체 리소스만 로드하는 경우 다음을 등록합니다.
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "default-src 'self'"
},
"manifest_version": 3
}
확장 프로그램에서 웹 어셈블리를 사용해야 하거나 샌드박스 처리된 페이지에 대한 제한을 늘려야 하는 경우 다음을 추가할 수 있습니다.
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';",
"sandboxed_pages":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
},
"manifest_version": 3
}
document.write() 및 innerHTML 피하기
document.write() 및 innerHTML를 사용하여 HTML 요소를 동적으로 만드는 것이 더 간단할 수 있지만, 확장 프로그램과 확장 프로그램이 의존하는 웹페이지가 공격자가 악성 스크립트를 삽입할 수 있는 상태로 남게 됩니다. 대신 DOM 노드를 수동으로 만들고 innerText를 사용하여 동적 콘텐츠를 삽입합니다.
function constructDOM() {
let newTitle = document.createElement('h1');
newTitle.innerText = host;
document.appendChild(newTitle);
}
콘텐츠 스크립트 신중하게 사용
콘텐츠 스크립트는 격리된 환경에 있지만 공격에 취약합니다.
- 콘텐츠 스크립트는 웹페이지와 직접 상호작용하는 확장 프로그램의 유일한 부분입니다. 이로 인해 악성 웹페이지는 콘텐츠 스크립트가 의존하는 DOM의 일부를 조작하거나 명명된 항목과 같은 놀라운 웹 표준 동작을 악용할 수 있습니다.
- 웹페이지의 DOM과 상호작용하려면 콘텐츠 스크립트가 웹페이지와 동일한 렌더러 프로세스에서 실행되어야 합니다. 이로 인해 콘텐츠 스크립트는 사이드 채널 공격(예: Spectre)을 통해 데이터가 유출될 수 있으며, 악성 웹페이지가 렌더러 프로세스를 손상시키는 경우 공격자에게 탈취될 수 있습니다.
민감한 정보 (예: 사용자의 개인 정보) 또는 브라우저 기능에 액세스할 수 있는 Chrome API를 사용하는 작업은 확장 프로그램의 서비스 워커에서 실행해야 합니다. 콘텐츠 스크립트에 확장 프로그램 권한이 실수로 노출되지 않도록 합니다.
- 콘텐츠 스크립트의 메시지가 공격자에 의해 제작되었을 수 있다고 가정합니다 (예: 모든 입력을 검증하고 정리하고 스크립트를 교차 사이트 스크립팅으로부터 보호).
- 콘텐츠 스크립트로 전송된 데이터가 웹페이지로 유출될 수 있다고 가정합니다. 민감한 정보(예: 확장 프로그램의 보안 비밀, 다른 웹 출처의 데이터, 방문 기록)를 콘텐츠 스크립트에 전송하지 마세요.
- 콘텐츠 스크립트로 트리거할 수 있는 권한 있는 작업의 범위를 제한합니다. 콘텐츠 스크립트가 임의 URL에 대한 요청을 트리거하거나 확장 프로그램 API에 임의의 인수를 전달하도록 허용하지 마세요 (예:
fetch()또는chrome.tabs.create()메서드에 임의의 URL을 전달하도록 허용하지 마세요).
입력 등록 및 삭제
확장 프로그램이 예상하는 항목으로만 리스너를 제한하고, 수신 데이터의 발신자를 검증하고, 모든 입력을 정리하여 악성 스크립트로부터 확장 프로그램을 보호하세요.
확장 프로그램은 외부 웹사이트 또는 확장 프로그램과의 통신을 예상하는 경우에만 runtime.onMessageExternal에 등록해야 합니다. 항상 발신자가 신뢰할 수 있는 소스와 일치하는지 확인하세요.
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
확장 프로그램 자체에서 runtime.onMessage 이벤트를 통해 전송되는 메시지조차도 MessageSender가 보안이 취약한 콘텐츠 스크립트에서 전송되지 않았는지 확인하기 위해 면밀히 검토해야 합니다.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.allowedAction)
console.log("This is an allowed action.");
});