Projet

Général

Profil

Paste
Télécharger (23,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / security_review / security_review.help.inc @ bb746689

1
<?php
2

    
3
/**
4
 * @file
5
 * Main help definition.
6
 */
7

    
8
function _security_review_help() {
9
  drupal_add_js(drupal_get_path('module', 'security_review') . '/security_review.js');
10
  $output = '';
11
  $output .= '<p>';
12
  $output .= t('You should take the security of your site very seriously.
13
    Fortunately, Drupal is fairly secure by default.
14
    The Security Review module automates many of the easy-to-make mistakes that render your site insecure, however it does not automatically make your site impenetrable.
15
    You should give care to what modules you install and how you configure your site and server.
16
    Be mindful of who visits your site and what features you expose for their use.');
17
  $output .= '</p>';
18
  $output .= '<p>';
19
  $output .= t('You can read more about securing your site in the <a href="!do">drupal.org handbooks</a> and on <a href="!cd">CrackingDrupal.com</a>.
20
    There are also additional modules you can install to secure or protect your site. Be aware though that the more modules you have running on your site the greater (usually) attack area you expose.',
21
    array('!do' => 'http://drupal.org/security/secure-configuration', '!cd' => 'http://crackingdrupal.com'));
22
  $output .= '</p>';
23
  $output .= '<p>' . l(t('Drupal.org Handbook: Introduction to security-related contrib modules'), 'http://drupal.org/node/382752') . '</p>';
24
  /*$output .= '<h3>' . t('Contrib modules for additional security and strength') . '</h3>';
25
   $output .= '<p>' . t('There are a wealth of modules on drupal.org.') . '</p>';
26
   $items[] = _security_review_help_ssl();
27
   $items[] = _security_review_help_spam();
28
   $output .= theme('item_list', $items);*/
29
  return $output;
30
}
31

    
32
function _security_review_help_ssl() {
33
  $description = t('The transfer of data between the visitor on your site and you Drupal installation can be secured through encryption.');
34
  $element = array(
35
    'problem' => t("Secure and private communication"),
36
    'type' => 'ssl',
37
    'description' => $description,
38
    'options' => array(
39
      array(
40
        'name' => 'Secure Pages',
41
        'href' => 'http://drupal.org/project/securepages',
42
      ),
43
    ),
44
  );
45
  return theme('security_review_help_options', array('element' => $element));
46
}
47

    
48
function _security_review_help_spam() {
49
  $element = array(
50
    'problem' => t("Spammers and spam content"),
51
    'type' => 'spam',
52
    'description' => t('Spammers use automated tools and systems to bombarge your site with unsollicited content. You can use modules to prevent the submission of such content.'),
53
    'options' => array(
54
      array(
55
        'name' => 'CAPTCHA',
56
        'href' => 'http://drupal.org/project/captcha',
57
      ),
58
    ),
59
  );
60
  return theme('security_review_help_options', array('element' => $element));
61
}
62

    
63
function theme_security_review_help_options($element) {
64
  $output .= '<div class="sec-rev-help-option">';
65
  $output .= l($element['problem'], 'admin/reports/security-review/help', array('fragment' => $element['type'], 'attributes' => array('class' => 'sec-rev-help-dyn')));
66
  $output .= '<div class="sec-rev-help-content">';
67
  $output .= '<p>' . $element['description'] . '</p>';
68
  foreach ($element['options'] as $option) {
69
    $items[] = l($option['name'], $option['href']);
70
  }
71
  $output .= theme('item_list', array('items' => $items));
72
  $output .= '</div>';
73
  $output .= '</div>';
74
  return $output;
75
}
76

    
77
function security_review_check_file_perms_help($check = NULL, $skipped_message = NULL) {
78
  $element['title'] =  t("Web server file system permissions");
79
  $element['descriptions'][] = t("It is dangerous to allow the web server to write to files inside the document root of your server. Doing so could allow Drupal to write files that could then be executed. An attacker might use such a vulnerability to take control of your site. An exception is the Drupal files, private files, and temporary directories which Drupal needs permission to write to in order to provide features like file attachments.");
80
  $element['descriptions'][] = t("In addition to inspecting existing directories, this test attempts to create and write to your file system. Look in your security_review module directory on the server for files named file_write_test.YYYYMMDDHHMMSS and for a file called IGNOREME.txt which gets a timestamp appended to it if it is writeable.</p>");
81
  $element['descriptions'][] = t("<a href='!link'>Read more about file system permissions in the handbooks.</a>", array('!link' => url('http://drupal.org/node/244924')));
82

    
83
  if ($skipped_message) {
84
    $element['findings']['descriptions'][] = $skipped_message;
85
  }
86
  elseif ($check && $check['result'] == FALSE) {
87
    $element['findings']['descriptions'][] = t('The following files and directories appear to be writeable by your web server. In most cases you can fix this by simply altering the file permissions or ownership. If you have command-line access to your host try running "chmod 644 [file path]" where [file path] is one of the following paths (relative to your webroot). For more information consult the <a href="!link">Drupal.org handbooks on file permissions</a>.', array('!link' => url('http://drupal.org/node/244924')));
88
    foreach ($check['value'] as $file) {
89
      $element['findings']['items'][] = array(
90
        'safe' => check_plain($file),
91
        'raw' => $file,
92
      );
93
    }
94
  }
95
  return $element;
96
}
97

    
98
function security_review_check_input_formats_help($check = NULL, $skipped_message = NULL) {
99
  $element['title'] = t('Allowed HTML tags in text formats');
100
  $element['descriptions'][] = 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.");
101
  $element['descriptions'][] = t("<a href='!link'>Read more about Drupal's input formats in the handbooks.</a>", array('!link' => url('http://drupal.org/node/224921')));
102

    
103
  if ($skipped_message) {
104
    $element['findings']['descriptions'][] = $skipped_message;
105
  }
106
  elseif ($check && $check['result'] == FALSE) {
107
    if (!empty($check['value']['tags'])) {
108
      $element['findings']['descriptions'][] = t('<a href="!link">Review your text formats.</a>', array('!link' => url('admin/config/content/formats')));
109
      $element['findings']['descriptions'][] = t('It is recommended you remove the following tags from roles accessible by untrusted users.');
110
      foreach ($check['value']['tags'] as $tag) {
111
        $element['findings']['items'][] = array(
112
          'safe' => $tag, // Tag doesn't need filtering cause it's not user-defined.
113
          'raw' => $tag,
114
        );
115
      }
116
    }
117
    elseif (!empty($check['value']['formats'])) {
118
      $element['findings']['descriptions'][] = t('The following formats are usable by untrusted roles and do not filter or escape allowed HTML tags.');
119
      foreach ($check['value']['formats'] as $id => $format) {
120
        $element['findings']['items'][] = array(
121
          'html' => l($format->name, 'admin/config/content/formats/' . $format->format),
122
          'safe' => check_plain($format->name),
123
          'raw' => $format->name,
124
        );
125
      }
126
    }
127
  }
128
  return $element;
129
}
130

    
131
function security_review_check_php_filter_help($check = NULL, $skipped_message = NULL) {
132
  $element['title'] = t('PHP Input Format');
133
  $element['descriptions'][] = t("Drupal's PHP Text Format allows for the interpretation and execution of PHP code via user-supplied input. Because this input runs in the context of Drupal itself it has access to everything Drupal does.");
134

    
135
  if (!empty($skipped_message)) {
136
    $element['findings']['descriptions'][] = $skipped_message;
137
  }
138
  elseif ($check && $check['result'] == FALSE) {
139
    if (!empty($check['value']['formats'])) {
140
      $element['findings']['descriptions'][] = t('The following formats are usable by untrusted roles and allow use of the PHP evaluator. You should edit the format to remove PHP use.');
141
      foreach ($check['value']['formats'] as $id => $format) {
142
        $element['findings']['items'][] = array(
143
          'html' => l($format->name, 'admin/config/content/formats/' . $format->format),
144
          'safe' => check_plain($format->name),
145
          'raw' => $format->name,
146
        );
147
      }
148
    }
149
  }
150
  return $element;
151
}
152

    
153
function security_review_check_error_reporting_help($check = NULL, $skipped_message = NULL) {
154
  $element['title'] = t('Error reporting');
155
  $element['descriptions'][] = t('As a form of hardening your site you should avoid information disclosure. Drupal by default prints errors to the screen and writes them to the log. Error messages disclose the full path to the file where the error occured.');
156

    
157
  if (!empty($skipped_message)) {
158
    $element['findings']['descriptions'][] = $skipped_message;
159
  }
160
  elseif ($check && $check['result'] == FALSE) {
161
    $element['findings']['descriptions'][] = t('You have error reporting set to both the screen and the log.');
162
    $element['findings']['descriptions'][] = t('<a href="!link">Alter error reporting settings.</a>', array('!link' => url('admin/config/development/logging')));
163
  }
164
  return $element;
165
}
166

    
167
function security_review_check_private_files_help($check = NULL, $skipped_message = NULL) {
168
  $element['title'] = t('Private files');
169
  $element['descriptions'][] = t("If you have Drupal's private files feature enabled you should move the files directory outside of the web server's document root. Drupal will secure access to files that it renders the link to, but if a user knows the actual system path they can circumvent Drupal's private files feature. You can protect against this by specifying a files directory outside of the webserver root.");
170

    
171
  if (!empty($skipped_message)) {
172
    $element['findings']['descriptions'][] = $skipped_message;
173
  }
174
  elseif ($check && $check['result'] == FALSE) {
175
    $element['findings']['descriptions'][] = t('Your files directory is not outside of the server root.');
176
    $element['findings']['descriptions'][] = t('<a href="!link">Edit the files directory path.</a>', array('!link' => url('admin/config/media/file-system')));
177
    $element['findings']['items'][] = array(
178
      'safe' => t('Private files directory: @value', array('@value' => $check['value'])),
179
      'raw' => 'Directory: ' . $check['value'],
180
    );
181
  }
182
  return $element;
183
}
184

    
185
function security_review_check_query_errors_help($check = NULL, $skipped_message = NULL) {
186
  $element['title'] = t('Abundant query errors from the same IP');
187
  $element['descriptions'][] = t("Database errors triggered from the same IP may be an artifact of a malicious user attempting to probe the system for weaknesses like SQL injection or information disclosure.");
188

    
189
  if (!empty($skipped_message)) {
190
    $element['findings']['descriptions'][] = $skipped_message;
191
  }
192
  elseif ($check && $check['result'] == FALSE) {
193
    $element['findings']['descriptions'][] = t('The following IPs were observed with an abundance of query errors.');
194
    foreach ($check['value'] as $ip) {
195
      $element['findings']['items'][] = array(
196
        'safe' => check_plain($ip),
197
        'raw' => $ip,
198
      );
199
    }
200
  }
201
  return $element;
202
}
203

    
204
function security_review_check_failed_logins_help($check = NULL, $skipped_message = NULL) {
205
  $element['title'] = t('Abundant failed logins from the same IP');
206
  $element['descriptions'][] = t("Failed login attempts from the same IP may be an artifact of a malicous user attempting to brute-force their way onto your site as an authenticated user to carry out nefarious deeds. ");
207

    
208
  if (!empty($skipped_message)) {
209
    $element['findings']['descriptions'][] = $skipped_message;
210
  }
211
  elseif ($check && $check['result'] == FALSE) {
212
    $element['findings']['descriptions'][] = t('The following IPs were observed with an abundanced of failed login attempts.');
213
    foreach ($check['value'] as $ip) {
214
      $element['findings']['items'][] = array(
215
        'safe' => check_plain($ip),
216
        'raw' => $ip,
217
      );
218
    }
219
  }
220
  return $element;
221
}
222

    
223
function security_review_check_admin_permissions_help($check = NULL, $skipped_message = NULL) {
224
  $element['title'] = t('Admin and trusted Drupal permissions');
225
  $element['descriptions'][] = t("Drupal's permission system is extensive and allows for varying degrees of control. Certain permissions would allow a user total control, or the ability to escalate their control, over your site and should only be granted to trusted users.");
226
  $element['descriptions'][] = t('<a href="!link">Read more about trusted vs. untrusted roles and permissions on DrupalScout.com.</a>', array('!link' => url('http://drupalscout.com/knowledge-base/importance-user-roles-and-permissions-site-security')));
227

    
228
  if (!empty($skipped_message)) {
229
    $element['findings']['descriptions'][] = $skipped_message;
230
  }
231
  elseif ($check && $check['result'] == FALSE) {
232
    $roles = user_roles();
233
    $element['findings']['descriptions'][] = t('You have granted untrusted roles the following permissions that you should revoke.');
234
    foreach ($check['value'] as $rid => $permissions) {
235
      $permissions = implode(', ', $permissions);
236
      $html = t('<a href="!link">@name</a> has %permissions', array('!link' => url('admin/people/permissions/' . $rid), '@name' => $roles[$rid], '%permissions' => $permissions));
237
      $safe = t('@name has %permissions', array('@name' => $roles[$rid], $permissions));
238
      $element['findings']['items'][] = array(
239
        'html' => $html,
240
        'safe' => $safe,
241
        'raw' => $roles[$rid] . ':' . $permissions,
242
      );
243
    }
244
  }
245
  return $element;
246
}
247

    
248
function security_review_check_field_help($check = NULL, $skipped_message = NULL) {
249
  $element['title'] = t('Dangerous tags in content');
250
  $element['descriptions'][] = 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.');
251

    
252
  if (!empty($skipped_message)) {
253
    $element['findings']['descriptions'][] = $skipped_message;
254
  }
255
  elseif ($check && $check['result'] == FALSE) {
256
    $element['findings']['descriptions'][] = t('The following items potentially have dangerous tags.  ');
257
    foreach ($check['value'] as $entity_type => $value) {
258
      $ids = array_keys($value);
259
      $entity_info = entity_get_info($entity_type);
260
      $id = $entity_info['entity keys']['id'];
261
      $label = isset($entity_info['entity keys']['label']) ? $entity_info['entity keys']['label'] : $id;
262
      $uri_callback = FALSE;
263
      if (isset($entity_info['uri callback'])) {
264
        $uri_callback = $entity_info['uri callback'];
265
      }
266
      // There is no access checking. We state that the use of this module should be granted to trusted users only.
267
      $entities = entity_load($entity_type, $ids);
268
      foreach ($entities as $entity) {
269
        $uri = '#';
270
        if ($uri_callback && function_exists($uri_callback)) {
271
          $uri = $uri_callback($entity);
272
          $uri = url($uri['path'] . '/edit'); // @todo can this assumption be made?
273
        }
274
        $html = t('@description found in @field field of <a href="!link">@title</a>', array('@field' => $value[$entity->{$id}]['field'], '@description' => $value[$entity->{$id}]['type'], '!link' => $uri, '@title' => $entity->{$label}));
275
        $element['findings']['items'][] = array(
276
          'html' => $html,
277
          'safe' => t('@description in @field field of !url', array('@field' => $value[$entity->{$id}]['field'], '@description' => $value[$entity->{$id}], '!url' => $uri)),
278
          'raw' => $value[$entity->{$id}] . ':' . $uri,
279
        );
280
      }
281
    }
282
    //$element['findings']['pager'] = theme('pager', array('tags' => NULL));
283
  }
284

    
285
  return $element;
286
}
287

    
288
function security_review_check_upload_extensions_help($check = NULL, $skipped_message = NULL) {
289
  $element['title'] = t('Allowed upload extensions');
290
  $element['descriptions'][] = t('File and image fields allow for uploaded files. Some extensions are considered dangerous because the files can be evaluated and then executued in the browser. A malicious user could use this opening to gain control of your site. Review <a href="@fields_report">all fields on your site</a>.', array('@fields_report' => url('admin/reports/fields')));
291

    
292
  if (!empty($skipped_message)) {
293
    $element['findings']['descriptions'][] = $skipped_message;
294
  }
295
  elseif ($check && $check['result'] == FALSE) {
296
    $element['findings']['descriptions'][] = t('The following extensions are considered unsafe and should be removed or limited from use. Or, be sure you are not granting untrusted users the ability to upload files.');
297
    foreach ($check['value'] as $field_name => $extensions) {
298
      foreach ($extensions as $bundle => $extension) {
299
        $element['findings']['items'][] = array(
300
          'raw' => $extension,
301
          'safe' => check_plain($extension),
302
          'html' => l(t('Review @type in @name field on @bundle', array('@type' => $extension, '@name' => $field_name, '@bundle' => $bundle)), 'admin/structure/types/manage/' . $bundle . '/fields/' . $field_name),
303
        );
304
      }
305
    }
306
  }
307
  return $element;
308
}
309

    
310
function security_review_check_views_access_help($check = NULL, $skipped_message = NULL) {
311
  $element['title'] = t('Views access');
312
  $element['descriptions'][] = t("Views can check if the user is allowed access to the content. It is recommended that all Views implement some amount of access control, at a minimum checking for the permission 'access content'.");
313

    
314
  if (!empty($skipped_message)) {
315
    $element['findings']['descriptions'][] = $skipped_message;
316
  }
317
  elseif ($check && $check['result'] == FALSE) {
318
    $element['findings']['descriptions'][] = t('The following View displays do not check access.');
319
    foreach ($check['value'] as $view => $displays) {
320
      $url = 'admin/structure/views/view/' . $view . '/edit/';
321
      foreach ($displays as $display) {
322
        $item = $view . ': ' . $display;
323
        $element['findings']['items'][] = array(
324
          'html' => l($item, $url . $display),
325
          'safe' => $item, // View names are safe.
326
          'raw' => $item,
327
        );
328
      }
329
    }
330
  }
331

    
332
  return $element;
333
}
334

    
335
function security_review_check_name_passwords_help($check = NULL, $skipped_message = NULL) {
336
  $element['title'] = t('Username as password');
337
  $element['descriptions'][] = t("Users with elevated access on the site (trusted users) who have a their account password the same as their username. It is recommended you enforce a password strength policy to avoid an attacker easily gaining access to your site.");
338

    
339
  if (!empty($skipped_message)) {
340
    $element['findings']['descriptions'][] = $skipped_message;
341
  }
342
  elseif ($check && $check['result'] == FALSE) {
343
    $element['findings']['descriptions'][] = t('The following users have extremely weak passwords. The links go to the edit page.');
344
    foreach ($check['value'] as $uid => $name) {
345
      $element['findings']['items'][] = array(
346
        'html' => l($name, 'user/' . $uid . '/edit'),
347
        'safe' => check_plain($name),
348
        'raw' => $name,
349
      );
350
    }
351
    $element['findings']['pager'] = theme('pager', NULL, 20);
352
  }
353

    
354
  return $element;
355
}
356

    
357
function security_review_check_executable_php_help($check = NULL, $skipped_message = NULL) {
358
  $element = array();
359
  $element['title'] = t('Executable PHP in files directory');
360
  $element['descriptions'][] = t("The Drupal files directory is for user-uploaded files and by default provides some protection against a malicious user executing arbitrary PHP code against your site.");
361
  $element['descriptions'][] = t('Read more about the <a href="!link">risk of PHP code execution on Drupal.org</a>.', array('!link' => 'https://drupal.org/node/615888'));
362

    
363
  if (!empty($skipped_message)) {
364
    $element['findings']['descriptions'][] = $skipped_message;
365
  }
366
  if (!empty($check['value'])) {
367
    foreach ($check['value'] as $label) {
368
      switch ($label) {
369
        case 'executable_php':
370
          $element['findings']['descriptions'][] = t('Security Review was able to execute a PHP file written to your files directory.');
371
          break;
372
        case 'missing_htaccess':
373
          $directory = variable_get('file_public_path', 'sites/default/files');
374
          $element['findings']['descriptions'][] = t("The .htaccess file is missing from the files directory at !path", array('!path' => $directory));
375
          $element['findings']['descriptions'][] = t("Note, if you are using a webserver other than Apache you should consult your server's documentation on how to limit the execution of PHP scripts in this directory.");
376
          break;
377
        case 'incorrect_htaccess':
378
            $element['findings']['descriptions'][] = t("The .htaccess file exists but does not contain the correct content. It is possible it's been maliciously altered.");
379
            break;
380
        case 'outdated_core':
381
            $element['findings']['descriptions'][] = t("You are running a out-of-date Drupal installation that is vulnerable to arbitrary code execution via weak htaccess protection. Upgrade to the latest version of Drupal. See <a href='https://drupal.org/SA-CORE-2013-003'>SA-CORE-2013-003 - Drupal core - Multiple vulnerabilities</a> for the full report.");
382
            break;
383
        case 'writable_htaccess':
384
          $element['findings']['descriptions'][] = t("The .htaccess file is writeable which poses a risk should a malious user find a way to execute PHP code they could alter the htaccess file to allow further PHP code execution.");
385
          break;
386
      }
387
    }
388
  }
389

    
390
  return $element;
391
}
392

    
393
function security_review_check_base_url_help($check = NULL, $skipped_message = NULL) {
394
  global $base_url;
395
  $element = array();
396
  $element['title'] = t('Drupal base URL');
397
  $element['descriptions'][] = t("Setting Drupal's \$base_url in settings.php can help protect against attackers manipulating links to your site. For example, an attacker could exploit a missing \$base_url setting to carry out a phishing attack that may lead to the theft of your site's private user data.");
398

    
399
  if (!empty($skipped_message)) {
400
    $element['findings']['descriptions'][] = $skipped_message;
401
  }
402
  elseif ($check && $check['result'] == FALSE) {
403
    $element['findings']['descriptions'][] = t('Your site is available at the following URL: !url.', array('!url' => $base_url));
404
    $element['findings']['descriptions'][] = t("If your site should only be available at that URL it is recommended that you set it as the \$base_url variable in the settings.php file at !file", array('!file' => DRUPAL_ROOT . '/' . conf_path() . '/settings.php'));
405
    $element['findings']['descriptions'][] = t("Or, if you are using Drupal's multi-site functionality then you should set the \$base_url variable for the appropriate settings.php for your site.");
406
  }
407

    
408
  return $element;
409
}
410

    
411
function security_review_check_temporary_files_help($check = NULL, $skipped_message = NULL) {
412
  $element = array();
413
  $element['title'] = t('Sensitive temporary files');
414
  $element['descriptions'][] = t("Some file editors create temporary copies of a file that can be left on the file system. A copy of a sensitive file like Drupal's settings.php may be readable by a malicious user who could use that information to further attack a site.");
415

    
416
  if (!empty($skipped_message)) {
417
    $element['findings']['descriptions'][] = $skipped_message;
418
  }
419
  elseif ($check && $check['result'] == FALSE) {
420
    $element['findings']['descriptions'][] = t("The following are extraneous files in your Drupal installation that can probably be removed. You should confirm you have saved any of your work in the original files prior to removing these.");
421
    foreach ($check['value'] as $path) {
422
      $element['findings']['items'][] = array(
423
        'safe' => check_plain($path),
424
        'raw' => $path,
425
      );
426
    }
427
  }
428

    
429
  return $element;
430
}