Las extensiones tienen acceso a privilegios especiales dentro del navegador, lo que las convierte en un objetivo atractivo para los atacantes. Si se vulnera una extensión, 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 proteger a sus usuarios.
Protege las cuentas de desarrollador
El código de la extensión se sube y se actualiza a través de las Cuentas de Google. Si las cuentas de los desarrolladores están vulneradas, un atacante podría enviar código malicioso directamente a todos los usuarios. Para proteger estas cuentas, habilita la autenticación de dos factores, preferiblemente con una llave de seguridad.
Mantén la selectividad de los grupos
Si usas la publicación de grupos, mantén el grupo limitado a desarrolladores de confianza. No aceptes solicitudes de membresía de personas desconocidas.
Nunca uses 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 tiene 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 de forma explícita en el manifest. Las extensiones deben minimizar sus permisos y solo 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 aprovechar.
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 de recuperación en el trabajador de servicio intercepta las llamadas a ambos.
{
"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 del ejemplo anterior solicita acceso a todo en developer.chrome.com y los subdominios de Google, ya que enumera "https://developer.chrome.com/*"
y "https://*.google.com/*"
en los permisos. Si la extensión se viera comprometida, solo tendría permiso para interactuar con sitios web que cumplan con el patrón de coincidencia. El atacante solo tendría la capacidad limitada de acceder a "https://user_bank_info.com"
o interactuar con "https://malicious_website.com"
.
Limita los campos del manifiesto
Si incluyes claves y permisos innecesarios en el manifiesto, se crean vulnerabilidades y se hace que una extensión sea más visible. Limita los campos del manifiesto a aquellos en los que se basa la extensión.
Se puede conectar de forma externa
Usa el campo "externally_connectable"
para declarar con qué extensiones y páginas web externas intercambiará información la extensión. Restringe con quién puede conectarse externamente la extensión 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 a través de la Web
Si permites que la Web acceda a los recursos, en "web_accessible_resources"
, los sitios web y los atacantes podrán detectar la extensión.
{
...
"web_accessible_resources": [
{
"resources": [ "test1.png", "test2.png" ],
"matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
}
]
...
}
Cuantos más recursos accesibles a la Web haya disponibles, más posibilidades tendrá un posible atacante de aprovecharse de ellos. Mantén estos archivos al mínimo.
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 para evitar ataques de secuencias de comandos entre sitios. Si la extensión solo carga recursos de 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 ensamblado web o aumentar las restricciones en las páginas en zona de pruebas, se pueden agregar los siguientes elementos:
{
"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 innerHTML
Si bien puede ser más sencillo crear elementos HTML de forma dinámica con document.write()
y innerHTML
, deja la extensión y las páginas web de las que depende la extensión abiertas a los atacantes que insertan secuencias de comandos maliciosas. En su lugar, crea nodos DOM de forma manual y usa innerText
para insertar contenido dinámico.
function constructDOM() {
let newTitle = document.createElement('h1');
newTitle.innerText = host;
document.appendChild(newTitle);
}
Usa las secuencias de comandos del contenido con cuidado
Si bien las secuencias de comandos de contenido viven en un mundo aislado, no están exentas de 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 de las que depende la secuencia de comandos de contenido o aprovechar un comportamiento estándar web inesperado, como los elementos con nombre.
- Para interactuar con el DOM de las páginas web, las secuencias de comandos de contenido deben ejecutarse en el mismo proceso de renderización que la página web. Esto hace que las secuencias de comandos de contenido sean vulnerables a la filtración de datos a través de ataques de canal lateral (p.ej., Spectre) y a que un atacante se apodere de él si una página web maliciosa vulnera el proceso de renderización.
Las operaciones que usan datos sensibles (como la información privada de un usuario) o las APIs de Chrome con acceso a las funciones del navegador deben realizarse en el trabajador del servicio de las extensiones. Evita exponer accidentalmente los privilegios de la extensión a las secuencias de comandos de contenido:
- Supongamos que un atacante pudo 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 la secuencia de comandos entre sitios).
- Supongamos que los datos que se envían a la secuencia de comandos de contenido podrían 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 las secuencias de comandos de contenido.
- Limita 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 permitas 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 solo a lo que espera la extensión, valida a los remitentes de los datos entrantes y limpia todas las entradas.
Una extensión solo debe registrarse en runtime.onMessageExternal
si espera una comunicación de un sitio web o una extensión externos. Siempre valida que el remitente coincida con una fuente confiable.
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
Incluso los mensajes a través del evento runtime.onMessage de la extensión deben analizarse para asegurarse de que MessageSender no provenga 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.");
});