5 * Contains \Drupal\security_review\Checks\InputFormats.
8 namespace Drupal\security_review\Checks;
11 use Drupal\security_review\Check;
12 use Drupal\security_review\CheckResult;
15 * Checks for vulnerabilities related to input formats.
17 * Checks for formats that either do not have HTML filter that can be used by
18 * untrusted users, or if they do check if unsafe tags are allowed.
20 class InputFormats extends Check {
25 public function getNamespace() {
26 return 'Security Review';
32 public function getTitle() {
33 return 'Text formats';
39 public function getMachineTitle() {
40 return 'input_formats';
46 public function run() {
47 // If filter is not enabled return with INFO.
48 if (!$this->moduleHandler()->moduleExists('filter')) {
49 return $this->createResult(CheckResult::INFO);
52 $result = CheckResult::SUCCESS;
55 $formats = filter_formats();
56 $untrusted_roles = $this->security()->untrustedRoles();
57 $unsafe_tags = $this->security()->unsafeTags();
59 foreach ($formats as $format) {
60 $format_roles = array_keys(filter_get_roles_by_format($format));
61 $intersect = array_intersect($format_roles, $untrusted_roles);
63 if (!empty($intersect)) {
64 // Untrusted users can use this format.
65 // Check format for enabled HTML filter.
66 $filter_html_enabled = FALSE;
67 if ($format->filters()->has('filter_html')) {
68 $filter_html_enabled = $format->filters('filter_html')
69 ->getConfiguration()['status'];
71 $filter_html_escape_enabled = FALSE;
72 if ($format->filters()->has('filter_html_escape')) {
73 $filter_html_escape_enabled = $format->filters('filter_html_escape')
74 ->getConfiguration()['status'];
77 if ($filter_html_enabled) {
78 $filter = $format->filters('filter_html');
80 // Check for unsafe tags in allowed tags.
81 $allowed_tags = array_keys($filter->getHTMLRestrictions()['allowed']);
82 foreach (array_intersect($allowed_tags, $unsafe_tags) as $tag) {
83 // Found an unsafe tag.
84 $findings['tags'][$format->id()] = $tag;
87 elseif (!$filter_html_escape_enabled) {
88 // Format is usable by untrusted users but does not contain the HTML
89 // Filter or the HTML escape.
90 $findings['formats'][$format->id()] = $format->label();
95 if (!empty($findings)) {
96 $result = CheckResult::FAIL;
98 return $this->createResult($result, $findings);
104 public function help() {
106 $paragraphs[] = $this->t("Certain HTML tags can allow an attacker to take control of your site. Drupal's input format system makes use of a set filters to run on incoming text. The 'HTML Filter' strips out harmful tags and Javascript events and should be used on all formats accessible by untrusted users.");
107 $paragraphs[] = $this->l(
108 $this->t("Read more about Drupal's input formats in the handbooks."),
109 Url::fromUri('http://drupal.org/node/224921')
113 '#theme' => 'check_help',
114 '#title' => $this->t('Allowed HTML tags in text formats'),
115 '#paragraphs' => $paragraphs,
122 public function evaluate(CheckResult $result) {
125 if (!empty($result->findings()['tags'])) {
127 $paragraphs[] = $this->l(
128 $this->t('Review your text formats.'),
129 Url::fromRoute('filter.admin_overview')
131 $paragraphs[] = $this->t('It is recommended you remove the following tags from roles accessible by untrusted users.');
133 '#theme' => 'check_evaluation',
134 '#paragraphs' => $paragraphs,
135 '#items' => $result->findings()['tags'],
139 if (!empty($result->findings()['formats'])) {
141 $paragraphs[] = $this->t('The following formats are usable by untrusted roles and do not filter or escape allowed HTML tags.');
143 '#theme' => 'check_evaluation',
144 '#paragraphs' => $paragraphs,
145 '#items' => $result->findings()['formats'],
155 public function evaluatePlain(CheckResult $result) {
158 if (!empty($result->findings()['tags'])) {
159 $output .= $this->t('Tags') . "\n";
160 foreach ($result->findings()['tags'] as $tag) {
161 $output .= "\t$tag\n";
165 if (!empty($result->findings()['formats'])) {
166 $output .= $this->t('Formats') . "\n";
167 foreach ($result->findings()['formats'] as $format) {
168 $output .= "\t$format\n";
178 public function getMessage($result_const) {
179 switch ($result_const) {
180 case CheckResult::SUCCESS:
181 return $this->t('Untrusted users are not allowed to input dangerous HTML tags.');
183 case CheckResult::FAIL:
184 return $this->t('Untrusted users are allowed to input dangerous HTML tags.');
186 case CheckResult::INFO:
187 return $this->t('Module filter is not enabled.');
190 return $this->t('Unexpected result.');