You are here

class Field in Security Review 8

Checks for Javascript and PHP in submitted content.

Hierarchy

Expanded class hierarchy of Field

1 file declares its use of Field
security_review.module in ./security_review.module
Site security review and reporting Drupal module.

File

src/Checks/Field.php, line 14

Namespace

Drupal\security_review\Checks
View source
class Field extends Check {

  /**
   * {@inheritdoc}
   */
  public function getNamespace() {
    return 'Security Review';
  }

  /**
   * {@inheritdoc}
   */
  public function getTitle() {
    return 'Content';
  }

  /**
   * {@inheritdoc}
   */
  public function getMachineTitle() {
    return 'field';
  }

  /**
   * {@inheritdoc}
   */
  public function run() {
    $result = CheckResult::SUCCESS;
    $findings = [];
    $field_types = [
      'text_with_summary',
      'text_long',
    ];
    $tags = [
      'Javascript' => 'script',
      'PHP' => '?php',
    ];

    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    $entity_type_manager = \Drupal::service('entity_type.manager');

    /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
    $field_manager = \Drupal::service('entity_field.manager');
    foreach ($field_manager
      ->getFieldMap() as $entity_type_id => $fields) {
      $field_storage_definitions = $field_manager
        ->getFieldStorageDefinitions($entity_type_id);
      foreach ($fields as $field_name => $field) {
        if (!isset($field_storage_definitions[$field_name])) {
          continue;
        }
        $field_storage_definition = $field_storage_definitions[$field_name];
        if (in_array($field_storage_definition
          ->getType(), $field_types)) {
          if ($field_storage_definition instanceof FieldStorageConfig) {
            $table = $entity_type_id . '__' . $field_name;
            $separator = '_';
            $id = 'entity_id';
          }
          else {
            $entity = $entity_type_manager
              ->getStorage($entity_type_id)
              ->getEntityType();
            $translatable = $entity
              ->isTranslatable();
            $table = '';
            if ($translatable) {
              $table = $entity
                ->getDataTable() ?: $entity_type_id . '_field_data';
            }
            else {
              $table = $entity
                ->getBaseTable() ?: $entity_type_id;
            }
            $separator = '__';
            $id = $entity
              ->getKey('id');
          }
          $rows = \Drupal::database()
            ->select($table, 't')
            ->fields('t')
            ->execute()
            ->fetchAll();
          foreach ($rows as $row) {
            foreach (array_keys($field_storage_definition
              ->getSchema()['columns']) as $column) {
              $column_name = $field_name . $separator . $column;
              foreach ($tags as $vulnerability => $tag) {
                if (strpos($row->{$column_name}, '<' . $tag) !== FALSE) {

                  // Vulnerability found.
                  $findings[$entity_type_id][$row->{$id}][$field_name][] = $vulnerability;
                }
              }
            }
          }
        }
      }
    }
    if (!empty($findings)) {
      $result = CheckResult::FAIL;
    }
    return $this
      ->createResult($result, $findings);
  }

  /**
   * {@inheritdoc}
   */
  public function help() {
    $paragraphs = [];
    $paragraphs[] = $this
      ->t('Script and PHP code in content does not align with Drupal best practices and may be a vulnerability if an untrusted user is allowed to edit such content. It is recommended you remove such contents.');
    return [
      '#theme' => 'check_help',
      '#title' => $this
        ->t('Dangerous tags in content'),
      '#paragraphs' => $paragraphs,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function evaluate(CheckResult $result) {
    $findings = $result
      ->findings();
    if (empty($findings)) {
      return [];
    }
    $paragraphs = [];
    $paragraphs[] = $this
      ->t('The following items potentially have dangerous tags.');
    $items = [];
    foreach ($findings as $entity_type_id => $entities) {
      foreach ($entities as $entity_id => $fields) {
        $entity = $this
          ->entityTypeManager()
          ->getStorage($entity_type_id)
          ->load($entity_id);
        foreach ($fields as $field => $finding) {
          $items[] = $this
            ->t('@vulnerabilities found in <em>@field</em> field of <a href=":url">@label</a>', [
            '@vulnerabilities' => implode(' and ', $finding),
            '@field' => $field,
            '@label' => $entity
              ->label(),
            ':url' => $this
              ->getEntityLink($entity),
          ]);
        }
      }
    }
    return [
      '#theme' => 'check_evaluation',
      '#paragraphs' => $paragraphs,
      '#items' => $items,
    ];
  }

  /**
   * Attempt to get a good link for the given entity.
   *
   * Falls back on a string with entity type id and id if no good link can
   * be found.
   *
   * @param \Drupal\Core\Entity\EntityBase $entity
   *   The entity.
   *
   * @return string
   */
  protected function getEntityLink(EntityInterface $entity) {
    try {
      $url = $entity
        ->toUrl('edit-form');
    } catch (UndefinedLinkTemplateException $e) {
      $url = NULL;
    }
    if ($url === NULL) {
      try {
        $url = $entity
          ->toUrl();
      } catch (UndefinedLinkTemplateException $e) {
        $url = NULL;
      }
    }
    return $url !== NULL ? $url
      ->toString() : $entity
      ->getEntityTypeId() . ':' . $entity
      ->id();
  }

  /**
   * {@inheritdoc}
   */
  public function evaluatePlain(CheckResult $result) {
    $findings = $result
      ->findings();
    if (empty($findings)) {
      return '';
    }
    $output = '';
    foreach ($findings as $entity_type_id => $entities) {
      foreach ($entities as $entity_id => $fields) {
        $entity = $this
          ->entityTypeManager()
          ->getStorage($entity_type_id)
          ->load($entity_id);
        foreach ($fields as $field => $finding) {
          $output .= "\t" . $this
            ->t('@vulnerabilities in @field of :link', [
            '@vulnerabilities' => implode(' and ', $finding),
            '@field' => $field,
            ':link' => $this
              ->getEntityLink($entity),
          ]) . "\n";
        }
      }
    }
    return $output;
  }

  /**
   * {@inheritdoc}
   */
  public function getMessage($result_const) {
    switch ($result_const) {
      case CheckResult::SUCCESS:
        return $this
          ->t('Dangerous tags were not found in any submitted content (fields).');
      case CheckResult::FAIL:
        return $this
          ->t('Dangerous tags were found in submitted content (fields).');
      default:
        return $this
          ->t('Unexpected result.');
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Check::$config protected property The configuration storage for this check.
Check::$container protected property The service container.
Check::$settings protected property Settings handler for this check.
Check::$state protected property The State system.
Check::$statePrefix protected property The check's prefix in the State system.
Check::checklist protected function Returns the Security Review Checklist service.
Check::configFactory protected function Returns the Config factory.
Check::container protected function Returns the service container.
Check::createResult public function Creates a new CheckResult for this Check.
Check::currentUser protected function Returns the current Drupal user.
Check::database protected function Returns the database connection.
Check::enable public function Enables the check. Has no effect if the check was not skipped.
Check::entityTypeManager protected function Returns the entity type manager.
Check::getMachineNamespace public function Returns the namespace of the check.
Check::id final public function Returns the identifier constructed using the namespace and title values.
Check::isSkipped public function Returns whether the check is skipped. Checks are not skipped by default.
Check::kernel protected function Returns the Drupal Kernel.
Check::lastResult public function Returns the last stored result of the check.
Check::lastRun public function Returns the timestamp the check was last run.
Check::moduleHandler protected function Returns the module handler.
Check::runCli public function Same as run(), but used in CLI context such as Drush. 2
Check::security protected function Returns the Security Review Security service.
Check::securityReview protected function Returns the Security Review service.
Check::settings public function Returns the check-specific settings' handler.
Check::skip public function Marks the check as skipped.
Check::skippedBy public function Returns the user the check was skipped by.
Check::skippedOn public function Returns the timestamp the check was last skipped on.
Check::storeResult public function Stores a result in the state system.
Check::storesFindings public function Returns whether the findings should be stored or reproduced when needed. 2
Check::__construct public function Initializes the configuration storage and the settings handler. 2
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
Field::evaluate public function Returns the evaluation page of a result. Overrides Check::evaluate
Field::evaluatePlain public function Evaluates a CheckResult and returns a plaintext output. Overrides Check::evaluatePlain
Field::getEntityLink protected function Attempt to get a good link for the given entity.
Field::getMachineTitle public function Returns the machine name of the check. Overrides Check::getMachineTitle
Field::getMessage public function Converts a result integer to a human-readable result message. Overrides Check::getMessage
Field::getNamespace public function Returns the namespace of the check. Overrides Check::getNamespace
Field::getTitle public function Returns the human-readable title of the check. Overrides Check::getTitle
Field::help public function Returns the check-specific help page. Overrides Check::help
Field::run public function The actual procedure of carrying out the check. Overrides Check::run
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.