Перейти к основному содержанию

Настройка target="_blank" для внешних ссылок в Drupal 11

Начиная с 2017–2018 годов, ведущие браузеры (Chrome, Firefox, Edge) и организации по веб-безопасности (включая OWASP) начали рекомендовать всегда использовать rel="noopener" при открытии ссылок в новой вкладке.

  • Это не формальный стандарт HTML, но de facto стандарт безопасности в современной веб-разработке.
  • Если вы разрабатываете сайт в 2025 году — всегда добавляйте rel="noopener" (и, при необходимости, noreferrer).
  1. noopener — защита от window.opener атак
    Когда вы используете target="_blank", новая вкладка получает доступ к объекту window.opener, который ссылается на исходную вкладку.

    Без noopener вредоносный сайт может:

    • вызвать window.opener.location = "https://phishing-site.com" — перенаправить вашу вкладку на фишинговую страницу;
    • считывать или изменять данные в исходной вкладке (если она уязвима).
  2. noreferrer — запрет передачи Referer-заголовка
    Этот параметр:
    • скрывает источник перехода: сайт по ссылке не узнает, откуда пришёл пользователь (не получит заголовок Referer);
    • дополнительно отключает window.opener (как побочный эффект);
    • может нарушать аналитику (например, Google Analytics не узнает, что трафик пришёл с вашего сайта).

Ручное управление внешними ссылками в Drupal 11.

В Drupal 11 существует готовый модуль, позволяющий добавлять атрибуты к ссылкам, но он требует ручного ввода rel="noopener noreferrer" каждый раз. Это не масштабируется и нарушает принцип «безопасность по умолчанию».

editor_advanced_link


Решение: автоматическое добавление атрибутов через Drupal behavior в кастомном модуле.

modules/custom/external_link_target/external_link_target.info.yml

name: 'External Link Target'
type: module
description: 'Automatically adds target="_blank" and rel="noopener noreferrer" to external links.'
core_version_requirement: ^11
package: Custom

modules/custom/external_link_target/external_link_target.libraries.yml

external_link_behavior:
  js:
    js/external-link-behavior.js: { preprocess: false, minified: false }
  dependencies:
    - core/drupal

modules/custom/external_link_target/external_link_target.module

<?php

/**
 * Implements hook_page_attachments().
 */
function external_link_target_page_attachments(array &$attachments) {
  $attachments['#attached']['library'][] = 'external_link_target/external_link_behavior';
}

modules/custom/external_link_target/js/external-link-behavior.js

/**
 * @file
 * Adds target="_blank" and rel="noopener noreferrer" to all external links.
 */

(function (Drupal, window, document) {
  'use strict';

  /**
   * Attaches behavior to add attributes to external links.
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.externalLinkTarget = {
    attach: function (context, settings) {
      // Get the current site's hostname (without port).
      const siteHost = window.location.hostname;

      // Select all links that:
      // - start with http:// or https:// (absolute URLs),
      // - are not already processed (to avoid double-processing on AJAX),
      // - are not internal (host differs from current site).
      const externalLinks = context.querySelectorAll('a[href^="http"]:not([data-external-processed])');

      externalLinks.forEach(function (link) {
        try {
          const url = new URL(link.href);
          if (url.hostname !== siteHost) {
            link.target = '_blank';
            link.rel = 'noopener noreferrer';
            // Mark as processed to avoid re-applying in AJAX scenarios.
            link.setAttribute('data-external-processed', '1');
          }
        } catch (e) {
          // Invalid URL — skip.
          console.warn('Invalid URL in external link detection:', link.href);
        }
      });
    }
  };

})(Drupal, window, document);