Las extensiones tienen acceso a privilegios especiales dentro del navegador, lo que las convierte en un objetivo atractivo para los atacantes. Si una extensión está comprometida, todos los usuarios de esa extensión se vuelven vulnerables a intrusiones maliciosas y no deseadas. Incorpora estas prácticas para mantener una extensión segura y a sus usuarios protegidos.
Protege las cuentas de desarrollador
El código de extensión se sube y se actualiza a través de Cuentas de Google. Si las cuentas de los desarrolladores están comprometidas, un atacante podría enviar código malicioso directamente a todos los usuarios. Para proteger estas cuentas, habilita la autenticación de dos factores, de preferencia con una llave de seguridad.
Mantén los grupos selectivos
Si usas la publicación de grupos, limita el grupo a desarrolladores de confianza. No aceptes solicitudes de membresía de personas desconocidas.
Nunca usar HTTP
Cuando solicites o envíes datos, evita una conexión HTTP. Supongamos que cualquier conexión HTTP tendrá escuchas o contendrá modificaciones. Siempre se debe preferir HTTPS, ya que cuenta con seguridad integrada que elude la mayoría de los ataques de intermediarios.
Solicita permisos mínimos
El navegador Chrome limita el acceso de una extensión a los privilegios que se solicitaron explícitamente en el manifiesto. Las extensiones deben minimizar sus permisos. Para ello, solo deben registrar las APIs y los sitios web de los que dependen.
Limitar los privilegios de una extensión limita lo que un atacante potencial puede explotar.
Recuperación de origen cruzado()
Una extensión solo puede usar fetch()
y XMLHttpRequest()
para obtener recursos de la
extensión y de los dominios especificados en los permisos. Ten en cuenta que el controlador fetch intercepta las llamadas a ambos en el service worker.
{
"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
}
Esta extensión en el ejemplo anterior solicita acceso a todo el contenido de developer.chrome.com y subdominios de Google incluyendo "https://developer.chrome.com/*"
y "https://*.google.com/*"
en los permisos. Si se vulnera la extensión, solo tendría permiso para interactuar con sitios web que cumplan con el patrón de coincidencia. El atacante solo tendría una capacidad limitada para acceder a "https://user_bank_info.com"
o interactuar con "https://malicious_website.com"
.
Limita los campos del manifiesto
La inclusión de claves y permisos innecesarios en el manifiesto crea vulnerabilidades y hace que una extensión sea más visible. Limita los campos del manifiesto a aquellos en los que se basa la extensión.
Conectable externamente
Usa el campo "externally_connectable"
para declarar con qué extensiones externas y páginas web
la extensión intercambiará información. Restringe con quién se puede conectar la extensión de forma externa a
fuentes de confianza.
{
"name": "Super Safe Extension",
"externally_connectable": {
"ids": [
"iamafriendlyextensionhereisdatas"
],
"matches": [
"https://developer.chrome.com/*",
"https://*.google.com/*"
],
"accepts_tls_channel_id": false
},
...
}
Recursos accesibles desde la Web
Hacer que los recursos sean accesibles a través de la Web, en virtud del "web_accessible_resources"
, hará que los sitios web y los atacantes puedan detectar una extensión.
{
...
"web_accessible_resources": [
{
"resources": [ "test1.png", "test2.png" ],
"matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
}
]
...
}
Cuantos más recursos accesibles a través de la web estén disponibles, más vías puede explotar un posible atacante. Reduce al mínimo estos archivos.
Incluye una política de seguridad del contenido explícita
Incluye una política de seguridad de contenido para la extensión en el manifiesto a fin de evitar ataques de secuencias de comandos entre sitios. Si la extensión solo carga recursos desde sí misma, registra lo siguiente:
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "default-src 'self'"
},
"manifest_version": 3
}
Si la extensión necesita usar el ensamblaje web o aumentar las restricciones en las páginas de zona de pruebas, puedes agregarlas:
{
"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
}
Evita document.write() y internalHTML
Si bien puede ser más sencillo crear elementos HTML de forma dinámica con document.write()
y innerHTML
,
dejará la extensión y las páginas web de las que depende quedan abiertas a los atacantes que inserten
secuencias de comandos maliciosas. En su lugar, crea nodos del DOM manualmente y usa innerText
para insertar contenido dinámico.
function constructDOM() {
let newTitle = document.createElement('h1');
newTitle.innerText = host;
document.appendChild(newTitle);
}
Utiliza cuidadosamente las secuencias de comandos del contenido.
Si bien las secuencias de comandos de contenido se encuentran en un mundo aislado, no están inmunes a los ataques:
- Las secuencias de comandos de contenido son la única parte de una extensión que interactúa directamente con la página web. Debido a esto, las páginas web hostiles pueden manipular partes del DOM del que depende la secuencia de comandos del contenido o explotar un comportamiento estándar web sorprendente, como los elementos con nombre.
- Para interactuar con el DOM de las páginas web, las secuencias de comandos del contenido deben ejecutarse en el mismo proceso del renderizador que la página web. Esto hace que las secuencias de comandos del contenido sean vulnerables a la filtración de datos a través de ataques de canales secundarios (p.ej., Spectre) y de que un atacante tome el control si una página web maliciosa pone en riesgo el proceso del procesador.
Las operaciones que usen datos sensibles (como información privada del usuario) o las APIs de Chrome con acceso a las funciones del navegador se deben realizar en el service worker de la extensión. Evita exponer accidentalmente los privilegios de extensión a las secuencias de comandos del contenido:
- Supongamos que un atacante podría haber creado mensajes de una secuencia de comandos de contenido (p.ej., valida y limpia todas las entradas y protege tus secuencias de comandos de secuencias de comandos entre sitios).
- Supongamos que los datos enviados a la secuencia de comandos de contenido pueden filtrarse a la página web. No envíes datos sensibles (p.ej., secretos de la extensión, datos de otros orígenes web, historial de navegación) a secuencias de comandos de contenido.
- Limite el alcance de las acciones con privilegios que pueden activar las secuencias de comandos de contenido. No permitas que las secuencias de comandos de contenido activen solicitudes a URLs arbitrarias ni pasen argumentos arbitrarios a las APIs de extensión (p.ej., no permites pasar URLs arbitrarias a los métodos
fetch()
ochrome.tabs.create()
).
Registra y limpia las entradas
Para proteger una extensión de secuencias de comandos maliciosas, limita los objetos de escucha a lo que la extensión espera, valida los remitentes de los datos entrantes y depura todas las entradas.
Una extensión solo debe registrarse para runtime.onMessageExternal
si espera la comunicación de un sitio web o una extensión externos. Verifica siempre que el remitente coincida con una fuente de confianza.
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
Se deben analizar incluso los mensajes a través del evento runtime.onMessage desde la extensión para garantizar que MessageSender no sea de una secuencia de comandos de contenido comprometida.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.allowedAction)
console.log("This is an allowed action.");
});