Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  IntegrityPolicyService.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "IntegrityPolicyService.h"

#include "mozilla/BasePrincipal.h"
#include "mozilla/Logging.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/IntegrityPolicy.h"
#include "mozilla/dom/IntegrityViolationReportBody.h"
#include "mozilla/dom/PolicyContainer.h"
#include "mozilla/dom/ReportingUtils.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/SRIMetadata.h"
#include "mozilla/net/SFVService.h"
#include "nsContentSecurityManager.h"
#include "nsContentSecurityUtils.h"
#include "nsContentUtils.h"
#include "nsILoadInfo.h"
#include "nsString.h"

using namespace mozilla;

static LazyLogModule sIntegrityPolicyServiceLogModule("IntegrityPolicy");
#define LOG(fmt, ...)                                                 \
  MOZ_LOG_FMT(sIntegrityPolicyServiceLogModule, LogLevel::Debug, fmt, \
              ##__VA_ARGS__)

namespace mozilla::dom {

IntegrityPolicyService::~IntegrityPolicyService() = default;

/* nsIContentPolicy implementation */
NS_IMETHODIMP
IntegrityPolicyService::ShouldLoad(nsIURI* aContentLocation,
                                   nsILoadInfo* aLoadInfo, int16_t* aDecision) {
  LOG("ShouldLoad: [{}] Entered ShouldLoad", static_cast<void*>(aLoadInfo));

  *aDecision = nsIContentPolicy::ACCEPT;

  if (!StaticPrefs::security_integrity_policy_enabled()) {
    LOG("ShouldLoad: [{}] Integrity policy is disabled",
        static_cast<void*>(aLoadInfo));
    return NS_OK;
  }

  if (!aContentLocation) {
    LOG("ShouldLoad: [{}] No content location", static_cast<void*>(aLoadInfo));
    return NS_ERROR_FAILURE;
  }

  bool block = ShouldRequestBeBlocked(aContentLocation, aLoadInfo);
  *aDecision =
      block ? nsIContentPolicy::REJECT_SERVER : nsIContentPolicy::ACCEPT;
  return NS_OK;
}

NS_IMETHODIMP IntegrityPolicyService::ShouldProcess(nsIURI* aContentLocation,
                                                    nsILoadInfo* aLoadInfo,
                                                    int16_t* aDecision) {
  *aDecision = nsIContentPolicy::ACCEPT;
  return NS_OK;
}

// https://w3c.github.io/webappsec-subresource-integrity/#should-request-be-blocked-by-integrity-policy-section
bool IntegrityPolicyService::ShouldRequestBeBlocked(nsIURI* aContentLocation,
                                                    nsILoadInfo* aLoadInfo) {
  // Efficiency check: if we don't care about this type, we can skip.
  auto destination = IntegrityPolicy::ContentTypeToDestinationType(
      aLoadInfo->InternalContentPolicyType());
  if (destination.isNothing()) {
    LOG("ShouldLoad: [{}] Integrity policy doesn't handle this type={}",
        static_cast<void*>(aLoadInfo),
        static_cast<uint8_t>(aLoadInfo->InternalContentPolicyType()));
    return false;
  }

  // Exempt addons from integrity policy checks.
  // Top level document loads have null LoadingPrincipal, but we don't apply
  // integrity policy to top level document loads right now.
  if (BasePrincipal::Cast(aLoadInfo->TriggeringPrincipal())
          ->OverridesCSP(aLoadInfo->GetLoadingPrincipal())) {
    LOG("ShouldLoad: [{}] Got a request from an addon, allowing it.",
        static_cast<void*>(aLoadInfo));
    return false;
  }

  // 2. Let parsedMetadata be the result of calling parse metadata with
  // request’s integrity metadata.
  // In our case, parsedMetadata is in loadInfo.
  Maybe<RequestMode> maybeRequestMode;
  aLoadInfo->GetRequestMode(&maybeRequestMode);
  if (maybeRequestMode.isNothing()) {
    // We don't have a request mode set explicitly, get it from the secFlags.
    // Just make sure that we aren't trying to get it from a
    // nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK loadInfo. In those
    // cases, we have to set the requestMode explicitly.
    MOZ_ASSERT(aLoadInfo->GetSecurityFlags() !=
               nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK);

    maybeRequestMode = Some(nsContentSecurityManager::SecurityModeToRequestMode(
        aLoadInfo->GetSecurityMode()));
  }

  RequestMode requestMode = *maybeRequestMode;

  if (MOZ_LOG_TEST(sIntegrityPolicyServiceLogModule, LogLevel::Debug)) {
    nsAutoString integrityMetadata;
    aLoadInfo->GetIntegrityMetadata(integrityMetadata);

    LOG("ShouldLoad: [{}] uri={} destination={} "
        "requestMode={} integrityMetadata={}",
        static_cast<void*>(aLoadInfo), aContentLocation->GetSpecOrDefault(),
        static_cast<uint8_t>(*destination), static_cast<uint8_t>(requestMode),
        NS_ConvertUTF16toUTF8(integrityMetadata).get());
  }

  // 3. If parsedMetadata is not the empty set and request’s mode is either
  // "cors" or "same-origin", return "Allowed".
  if (requestMode == RequestMode::Cors ||
      requestMode == RequestMode::Same_origin) {
    nsAutoString integrityMetadata;
    aLoadInfo->GetIntegrityMetadata(integrityMetadata);

    SRIMetadata outMetadata;
    dom::SRICheck::IntegrityMetadata(integrityMetadata,
                                     aContentLocation->GetSpecOrDefault(),
                                     nullptr, &outMetadata);

    if (outMetadata.IsValid()) {
      LOG("ShouldLoad: [{}] Allowed because we have valid a integrity.",
          static_cast<void*>(aLoadInfo));
      return false;
    }
  }

  // 4. If request's url is local, return "Allowed".
  if (aContentLocation->SchemeIs("data") ||
      aContentLocation->SchemeIs("blob") ||
      aContentLocation->SchemeIs("about")) {
    LOG("ShouldLoad: [{}] Allowed because we have data or blob.",
        static_cast<void*>(aLoadInfo));
    return false;
  }

  // We only support integrity policy for documents so far.
  nsCOMPtr<nsIPolicyContainer> policyContainer =
      aLoadInfo->GetPolicyContainer();
  if (!policyContainer) {
    LOG("ShouldLoad: [{}] No policy container", static_cast<void*>(aLoadInfo));
    return false;
  }

  // 5. Let policy be policyContainer’s integrity policy.
  // 6. Let reportPolicy be policyContainer’s report only integrity policy.
  // Our IntegrityPolicy struct contains both the enforcement and
  // report-only policies.
  RefPtr<IntegrityPolicy> policy = IntegrityPolicy::Cast(
      PolicyContainer::Cast(policyContainer)->GetIntegrityPolicy());
  if (!policy) {
    // 7. If both policy and reportPolicy are empty integrity policy structs,
    // return "Allowed".
    LOG("ShouldLoad: [{}] No integrity policy", static_cast<void*>(aLoadInfo));
    return false;
  }

  // TODO: 8. Let global be request’s client’s global object.
  // TODO: 9. If global is not a Window nor a WorkerGlobalScope, return
  // "Allowed".

  // Steps 10-13 in policy->PolicyContains(...)
  bool contains = false;
  bool roContains = false;
  policy->PolicyContains(*destination, &contains, &roContains);

  // 14. If block is true or reportBlock is true, then report violation
  // with request, block, reportBlock, policy and reportPolicy.
  if (contains || roContains) {
    ReportToConsole(aContentLocation, aLoadInfo, *destination, contains,
                    roContains);
    ReportViolation(aContentLocation, aLoadInfo, *destination, policy, contains,
                    roContains);
  }

  // 15. If block is true, then return "Blocked"; otherwise "Allowed".
  return contains;
}

const char* GetReportMessageKey(bool aEnforcing,
                                IntegrityPolicy::DestinationType aDestination) {
  // If we are not enforcing, we are reporting only.
  switch (aDestination) {
    case IntegrityPolicy::DestinationType::Script:
      return aEnforcing ? "IntegrityPolicyEnforceBlockedScript"
                        : "IntegrityPolicyReportOnlyBlockedScript";
    case IntegrityPolicy::DestinationType::Style:
      return aEnforcing ? "IntegrityPolicyEnforceBlockedStylesheet"
                        : "IntegrityPolicyReportOnlyBlockedStylesheet";
    default:
      MOZ_ASSERT_UNREACHABLE("Unhandled destination type");
      return nullptr;
  }
}

void IntegrityPolicyService::ReportToConsole(
    nsIURI* aContentLocation, nsILoadInfo* aLoadInfo,
    IntegrityPolicy::DestinationType aDestination, bool aEnforce,
    bool aReportOnly) const {
  if (nsContentUtils::IsPreloadType(aLoadInfo->InternalContentPolicyType())) {
    return;  // Don't report for preloads.
  }

  const char* messageKey = GetReportMessageKey(aEnforce, aDestination);
  NS_ENSURE_TRUE_VOID(messageKey);

  // We just report to the console for now. We should use the reporting API
  // in the future.
  AutoTArray<nsString, 1> params = {
      NS_ConvertUTF8toUTF16(aContentLocation->GetSpecOrDefault())};
  nsAutoString localizedMsg;
  nsresult rv = nsContentUtils::FormatLocalizedString(
      PropertiesFile::SECURITY_PROPERTIES, messageKey, params, localizedMsg);
  NS_ENSURE_SUCCESS_VOID(rv);

  uint64_t windowID = aLoadInfo->GetInnerWindowID();

  nsContentUtils::ReportToConsoleByWindowID(
      localizedMsg,
      aEnforce ? nsIScriptError::errorFlag : nsIScriptError::warningFlag,
      "Security"_ns, windowID);
}

// https://w3c.github.io/webappsec-subresource-integrity/#report-violation
void dom::IntegrityPolicyService::ReportViolation(
    nsIURI* aContentLocation, nsILoadInfo* aLoadInfo,
    IntegrityPolicy::DestinationType aDestination,
    const IntegrityPolicy* aPolicy, bool aEnforce, bool aReportOnly) const {
  // 1. Assert: request’s client is not null.
  // 2. Let settingsObject be request’s client.
  // 3. Let global be settingsObject’s global object.
  nsCOMPtr<nsISupports> loadingContext = aLoadInfo->GetLoadingContext();
  RefPtr<Document> doc;
  if (nsCOMPtr<nsINode> node = do_QueryInterface(loadingContext)) {
    doc = node->OwnerDoc();
  } else if (nsCOMPtr<nsPIDOMWindowOuter> window =
                 do_QueryInterface(loadingContext)) {
    doc = window->GetDoc();
  }

  if (NS_WARN_IF(!doc)) {
    return;
  }

  nsPIDOMWindowInner* window = doc->GetInnerWindow();
  if (NS_WARN_IF(!window)) {
    return;
  }
  nsCOMPtr<nsIGlobalObject> global = window->AsGlobal();

  // 4. Assert: global is a Window or a WorkerGlobalScope.

  // 5. Let url be null.
  // 6. If global is a Window, set url to global’s associated Document’s URL.
  nsCOMPtr<nsIURI> uri = doc->GetDocumentURI();  // XXX Maybe not the right URL?

  // 7. If global is a WorkerGlobalScope, set url to global’s URL.
  // TODO(bug 1969279): Worker support.

  // 8. Assert: url is a URL.
  if (NS_WARN_IF(!uri)) {
    return;
  }

  // 9. Let documentURL be the result of strip URL for use in reports on url.
  nsAutoCString documentURL;
  ReportingUtils::StripURL(uri, documentURL);
  NS_ConvertUTF8toUTF16 documentURLUTF16(documentURL);

  // 10. Let blockedURL be the result of strip URL for use in reports on
  // request’s URL.
  nsAutoCString blockedURL;
  ReportingUtils::StripURL(aContentLocation, blockedURL);

  nsAutoCString destination;
  switch (aDestination) {
    case IntegrityPolicy::DestinationType::Script:
      destination = "script"_ns;
      break;
    case IntegrityPolicy::DestinationType::Style:
      destination = "style"_ns;
      break;
    case IntegrityPolicy::DestinationType::Image:
      destination = "image"_ns;
      break;
  }

  nsTArray<nsCString> enforcementEndpoints;
  nsTArray<nsCString> reportOnlyEndpoints;
  aPolicy->Endpoints(enforcementEndpoints, reportOnlyEndpoints);

  // 11. If block is true, for each endpoint in policy’s endpoints:
  if (aEnforce) {
    for (const nsCString& endpoint : enforcementEndpoints) {
      // 11.1. Let body be a new IntegrityViolationReportBody, initialized as
      // follows:
      //
      // documentURL
      //     documentURL
      // blockedURL
      //     blockedURL
      // destination
      //    request’s destination
      // reportOnly
      //    false
      RefPtr<IntegrityViolationReportBody> body =
          new IntegrityViolationReportBody(global, documentURL, blockedURL,
                                           destination, false);

      // 11.2. Generate and queue a report with the following arguments:
      //
      // context
      //      settingsObject
      // type
      //      "integrity-violation"
      // destination
      //      endpoint
      // data
      //      body
      ReportingUtils::Report(global, nsGkAtoms::integrity_violation,
                             NS_ConvertUTF8toUTF16(endpoint), documentURLUTF16,
                             body);
    }
  }

  // 11. If reportBlock is true, for each endpoint in reportPolicy’s endpoints:
  if (aReportOnly) {
    for (const nsCString& endpoint : reportOnlyEndpoints) {
      // 11.1. Let reportBody be a new IntegrityViolationReportBody, initialized
      // as follows:
      //
      // documentURL
      //     documentURL
      // blockedURL
      //     blockedURL
      // destination
      //    request’s destination
      // reportOnly
      //    true
      RefPtr<IntegrityViolationReportBody> reportBody =
          new IntegrityViolationReportBody(global, documentURL, blockedURL,
                                           destination, true);

      // 11.2. Generate and queue a report with the following arguments:
      //
      // context
      //      settingsObject
      // type
      //      "integrity-violation"
      // destination
      //      endpoint
      // data
      //      reportBody
      ReportingUtils::Report(global, nsGkAtoms::integrity_violation,
                             NS_ConvertUTF8toUTF16(endpoint), documentURLUTF16,
                             reportBody);
    }
  }
}

NS_IMPL_ISUPPORTS(IntegrityPolicyService, nsIContentPolicy)

}  // namespace mozilla::dom

#undef LOG

Messung V0.5 in Prozent
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002