Drupal security - ben600324/wiki GitHub Wiki

Is Drupal secure?

Drupal has a very good track record in terms of security, and has an organized process for investigation, verifying and publishing possible security problems.

Your most important protection is keeping Drupal up to date whenever a security advisory is issued for Drupal core or the contributed code you are using.

Professional security audits of Drupal sites have generally found that the vast majority of security holes (90% or more) are present in the custom theme or modules written by that site's developers. That code did not get the same public scrutiny that all code on drupal.org receives.

https://www.drupal.org/documentation/is-drupal-secure

Securing your site

https://www.drupal.org/security/secure-configuration

Writing secure code for Drupal

https://www.drupal.org/docs/security-in-drupal/writing-secure-code-for-drupal

Use Twig templates

When rendering attributes in Twig, make sure that you wrap them with double or single quotes. For example, class="{{ class }}" is safe, class={{ class }} is not safe.

Output with placeholders

@variable: When the placeholder replacement value is a string or a MarkupInterface object %variable: When the placeholder replacement value is to be wrapped in em tags. :variable: When the placeholder replacement value is a URL to be used in the "href" attribute

Email

The security of your email content is strongly tied with the mail service that you choose to use. Remember, the same best practices of outputting text for HTML consumption should be considered here.

Javascript (jQuery) and Drupal.checkPlain()

Bad Practice: var rawInputText = $('#form-input').text(); Good Practice: var rawInputText = $('#form-input').text(); var escapedInputText = Drupal.checkPlain(rawInputText);

Use the database abstraction layer to avoid SQL injection attacks

Bad practice: \Database::getConnection()->query('SELECT foo FROM {table} t WHERE t.name = '. $_GET['user']); Good practice: \Database::getConnection()->query('SELECT foo FROM {table} t WHERE t.name = :name', [':name' => $_GET['user']]); $users = ['joe', 'poe', $_GET['user']]; $result = \Database::getConnection()->select('foo', 'f') ->fields('f', ['bar']) ->condition('f.bar', $users) ->execute();

  • Keep the CMS, add-ons, server and software up to date
  • Implement a firewall
  • Use encryption (TLS)
  • Protect against malicious user inputs (SQLi, XSS)
  • Use strong password for authentication
  • Implement Two Factor Authentication (2FA)
  • Remove default credentials
  • Backup your CMS