Dbaj o bezpieczeństwo

Rozszerzenia mają dostęp do specjalnych uprawnień w przeglądarce, co czyni je atrakcyjnym celem dla atakujących. Jeśli rozszerzenie zostanie naruszone, każdy jego użytkownik będzie narażony na złośliwe i niechciane ingerencje. Aby zapewnić bezpieczeństwo rozszerzenia i ochronę jego użytkowników, stosuj te praktyki.

Ochrona kont deweloperów

Kod rozszerzenia jest przesyłany i aktualizowany za pomocą kont Google. Jeśli konta deweloperów zostaną naruszone, atakujący może przesłać złośliwy kod bezpośrednio do wszystkich użytkowników. Chroń te konta, włączając uwierzytelnianie dwuskładnikowe, najlepiej za pomocą klucza bezpieczeństwa.

Używanie odpowiednich ról członków

Jeśli wydawca ma kilku członków, upewnij się, że rola przyznana każdemu użytkownikowi jest odpowiednia.

Nigdy nie używaj protokołu HTTP

Podczas wysyłania i odbierania danych unikaj połączenia HTTP. Załóż, że wszystkie połączenia HTTP będą podsłuchiwane lub zmodyfikowane. Zawsze preferuj protokół HTTPS, ponieważ ma on wbudowane zabezpieczenia, które pozwalają uniknąć większości ataków typu „man-in-the-middle”.

Wymagaj minimalnych uprawnień

Przeglądarka Chrome ogranicza dostęp rozszerzenia do uprawnień, które zostały wyraźnie określone w pliku manifestu. Rozszerzenia powinny ograniczać swoje uprawnienia, rejestrując tylko te interfejsy API i witryny, od których zależą.

Ograniczenie uprawnień rozszerzenia ogranicza to, co może wykorzystać potencjalny atakujący.

Wczytywanie z innych domen

Rozszerzenie może używać funkcji fetch() i XMLHttpRequest() tylko do pobierania zasobów z rozszerzenia i z domen określonych w uprawnieniach. Pamiętaj, że wywołania obu tych funkcji są przechwytywane przez moduł obsługi wczytywania w skrypcie 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
}

To rozszerzenie w powyższym przykładzie wymaga dostępu do wszystkich treści w witrynie developer.chrome.com i subdomenach Google, ponieważ w uprawnieniach znajdują się wpisy "https://developer.chrome.com/*" i "https://*.google.com/*". Jeśli rozszerzenie zostanie naruszone, nadal będzie mieć uprawnienia tylko do interakcji z witrynami, które pasują do wzorca . Atakujący będzie mieć ograniczony dostęp do witryny "https://user_bank_info.com" lub możliwość interakcji z witryną "https://malicious_website.com".

Ogranicz pola manifestu

Umieszczenie w pliku manifestu niepotrzebnych kluczy i uprawnień stwarza luki w zabezpieczeniach i zwiększa widoczność rozszerzenia. Ogranicz pola manifestu do tych, od których zależy rozszerzenie.

Możliwość łączenia się z zewnątrz

Użyj pola "externally_connectable", aby zadeklarować, z którymi rozszerzeniami zewnętrznymi i stronami internetowymi rozszerzenie będzie wymieniać informacje. Ogranicz możliwość łączenia się rozszerzenia z zewnątrz do zaufanych źródeł.

{
  "name": "Super Safe Extension",
  "externally_connectable": {
    "ids": [
      "iamafriendlyextensionhereisdatas"
    ],
    "matches": [
      "https://developer.chrome.com/*",
      "https://*.google.com/*"
    ],
    "accepts_tls_channel_id": false
  },
  ...
}

Zasoby dostępne w internecie

Udostępnienie zasobów w internecie za pomocą pola "web_accessible_resources" sprawi, że rozszerzenie będzie wykrywalne przez witryny i atakujących.

{
  ...
  "web_accessible_resources": [
    {
      "resources": [ "test1.png", "test2.png" ],
      "matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
    }
  ]
  ...
}

Im więcej zasobów dostępnych w internecie, tym więcej możliwości wykorzystania przez potencjalnego atakującego. Ogranicz liczbę tych plików do minimum.

Uwzględnij wyraźną politykę bezpieczeństwa treści

Aby zapobiec atakom typu cross-site scripting, uwzględnij w pliku manifestu politykę bezpieczeństwa treści dla rozszerzenia. Jeśli rozszerzenie wczytuje zasoby tylko z siebie, zarejestruj te elementy:

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
   "content_security_policy": {
    "extension_pages": "default-src 'self'"
  },
  "manifest_version": 3
}

Jeśli rozszerzenie musi używać WebAssembly lub zwiększyć ograniczenia na stronach w piaskownicy, można je dodać:

{
  "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
}

Unikaj instrukcji document.write() i innerHTML

Chociaż dynamiczne tworzenie elementów HTML za pomocą instrukcji document.write() i innerHTML może być prostsze, naraża rozszerzenie i strony internetowe, od których zależy rozszerzenie, na wstawianie złośliwych skryptów przez atakujących. Zamiast tego ręcznie twórz węzły DOM i używaj instrukcji innerText do wstawiania dynamicznych treści.

function constructDOM() {
  let newTitle = document.createElement('h1');
  newTitle.innerText = host;
  document.appendChild(newTitle);
}

Ostrożnie używaj skryptów dotyczących zawartości

Chociaż skrypty dotyczące zawartości działają w izolowanym środowisku, nie są odporne na ataki:

  • Skrypty dotyczące zawartości to jedyna część rozszerzenia, która wchodzi w bezpośrednią interakcję ze stroną internetową. Z tego powodu wrogie strony internetowe mogą manipulować częściami DOM, od których zależy skrypt dotyczący zawartości, lub wykorzystywać zaskakujące zachowania standardów internetowych, takie jak elementy nazwane.
  • Aby wchodzić w interakcję z DOM stron internetowych, skrypty dotyczące zawartości muszą być wykonywane w tym samym procesie renderowania co strona internetowa. Sprawia to, że skrypty dotyczące zawartości są podatne na wyciek danych za pomocą ataków typu side-channel (np. Spectre) oraz na przejęcie przez atakującego, jeśli złośliwa strona internetowa naruszy proces renderowania.

Operacje wykorzystujące dane wrażliwe (np. informacje prywatne użytkownika) lub interfejsy API Chrome z dostępem do funkcji przeglądarki powinny być wykonywane w skrypcie service worker rozszerzenia. Unikaj przypadkowego udostępniania uprawnień rozszerzenia skryptom dotyczącym zawartości:

  • Załóż, że wiadomości ze skryptu dotyczącego zawartości mogą być spreparowane przez atakującego (np. sprawdzaj i oczyszczaj wszystkie dane wejściowe oraz chroń skrypty przed atakami typu cross-site scripting).
  • Załóż, że wszystkie dane wysyłane do skryptu dotyczącego zawartości mogą wyciec na stronę internetową. Nie wysyłaj do skryptów dotyczących zawartości danych wrażliwych (np. tajnych informacji z rozszerzenia, danych z innych źródeł internetowych, historii przeglądania).
  • Ogranicz zakres działań z uprawnieniami, które mogą być wywoływane przez skrypty dotyczące zawartości. Nie zezwalaj skryptom dotyczącym zawartości na wywoływanie żądań do dowolnych adresów URL ani na przekazywanie dowolnych argumentów do interfejsów API rozszerzeń (np. nie zezwalaj na przekazywanie dowolnych adresów URL do fetch() lub chrome.tabs.create() metod).

Rejestrowanie i oczyszczanie danych wejściowych

Chroń rozszerzenie przed złośliwymi skryptami, ograniczając odbiorniki tylko do tych, których oczekuje rozszerzenie, sprawdzając nadawców przychodzących danych i oczyszczając wszystkie dane wejściowe.

Rozszerzenie powinno rejestrować się tylko w przypadku zdarzenia runtime.onMessageExternal, jeśli oczekuje komunikacji z zewnętrzną witryną lub rozszerzeniem. Zawsze sprawdzaj, czy nadawca jest zaufanym źródłem.

// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id === kFriendlyExtensionId)
      doSomething();
});

Nawet wiadomości wysyłane przez samo rozszerzenie za pomocą zdarzenia runtime.onMessage należy dokładnie sprawdzić, aby upewnić się, że MessageSender nie pochodzi z naruszonego skryptu dotyczącego zawartości.

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.allowedAction)
    console.log("This is an allowed action.");
});