You are here

function security_review_check_field in Security Review 7

1 call to security_review_check_field()
SecurityReviewTestCase::testCheckResults in tests/security_review.test
1 string reference to 'security_review_check_field'
_security_review_security_checks in ./security_review.inc
Core Security Review's checks.

File

./security_review.inc, line 487
Stand-alone security checks and review system.

Code

function security_review_check_field($last_check = NULL) {
  $check_result = TRUE;
  $check_result_value = $tables = $found = array();
  $timestamp = NULL;
  $instances = field_info_instances();

  // Loop through instances checking for fields of type text.
  foreach ($instances as $entity_type => $type_bundles) {
    foreach ($type_bundles as $bundle => $bundle_instances) {
      foreach ($bundle_instances as $field_name => $instance) {
        $field = field_info_field($field_name);

        // Check into text fields that are stored in SQL.
        if ($field['module'] == 'text' && $field['storage']['module'] == 'field_sql_storage') {

          // Build array of tables and columns to search.
          $current_table = key($field['storage']['details']['sql'][FIELD_LOAD_CURRENT]);
          $revision_table = key($field['storage']['details']['sql'][FIELD_LOAD_REVISION]);
          if (!array_key_exists($current_table, $tables)) {
            $tables[$current_table] = array(
              'column' => $field['storage']['details']['sql'][FIELD_LOAD_CURRENT][$current_table]['value'],
              'name' => $field['field_name'],
            );
          }
          if (!array_key_exists($revision_table, $tables)) {
            $tables[$revision_table] = array(
              'column' => $field['storage']['details']['sql'][FIELD_LOAD_REVISION][$revision_table]['value'],
              'name' => $field['field_name'],
            );
          }
        }
      }
    }
  }
  if (empty($tables)) {
    return array(
      'result' => $check_result,
      'value' => $check_result_value,
    );
  }

  // Search for PHP or Javascript tags in text columns.
  $known_risky_fields = explode(',', variable_get('security_review_known_risky_fields', ''));
  foreach ($tables as $table => $info) {

    // Column & table come from field definitions & are safe to use in a query.
    $sql = "SELECT DISTINCT entity_id, entity_type, " . $info['column'] . " AS field_text FROM {" . $table . "} WHERE " . $info['column'] . " LIKE :text";

    // Handle changed? @todo
    foreach (array(
      'Javascript' => '%<script%',
      'PHP' => '%<?php%',
    ) as $vuln_type => $comparison) {
      $results = db_query($sql, array(
        ':text' => $comparison,
      ));

      // @pager query?
      foreach ($results as $result) {
        if (!isset($check_result_value[$result->entity_type]) || !array_key_exists($result->entity_id, $check_result_value[$result->entity_type])) {

          // Only alert on values that are not known to be safe.
          $hash = hash('sha256', implode((array) $result));
          if (!in_array($hash, $known_risky_fields)) {
            $check_result = FALSE;
            $check_result_value[$result->entity_type][$result->entity_id] = array(
              'type' => $vuln_type,
              'field' => $info['name'],
              'hash' => $hash,
            );
          }
        }
      }
    }
  }
  return array(
    'result' => $check_result,
    'value' => $check_result_value,
  );
}