Элементы, которые нельзя удалить даже при открытой консоли, фронтенд пугает

JavaScript HTML

В солнечный день мне вдруг захотелось запустить кусок кода, и тогда я открыл консоль. В этот момент он оказывается на странице. Однако, как только я открыл консоль, мое внимание привлекло кое-что, что на самом деле было водяным знаком на этой странице.

Любопытство, вызванное ОКР

После запуска моего кода я вернулся к разделу элементов и хотел его удалить (кто сказал вам быть таким большим, я присматривался). Нажмите, чтобы выбрать div, затем нажмите «Удалить».

"Кряк!", должно быть, я не нажимал. Опять "Кряк!", да? див мерцает? "Кряк!", не могу удалить! ?

Что ж, я изменю стиль. display:none, устроило!Почему я проиграл, div снова замигал, а изменения только сейчас исчезли

В этот момент вскоре появился объект подозрения — MutationObserver.

MutationObserver: предоставляет возможность отслеживать изменения, внесенные в дерево DOM. Он был разработан как замена старой функции Mutation Events, которая была частью спецификации DOM3 Events. Подробности можно посмотретьmdn

Затем общая логика заключается в том, что MutationObserver отслеживает изменения этого водяного знака, такие как удаление, модификация attr, добавление дочерних узлов, а затем напрямую перерисовывает элемент, точно такой же, как исходный, понимая, что «вы не можете измените этот узел, даже если вы откроете консоль" Эффект

Поисковые исследования в исходном коде

В разделе исходного кода я нашел файл js, относящийся к странице, искал MutationObserver и, наконец, нашел такую ​​функцию:

  function observeSelector(e) {
    if (e) {
      var t = e.cloneNode(!0)
        , n = e.parentNode || document.body;
      new MutationObserver(function (r) {
        e && r.forEach(function (r) {
          var o = r.target
            , i = Array.prototype.slice.call(r.removedNodes)[0];
          if (o === e) {
            var a = t.cloneNode(!0);
            n.replaceChild(a, e),
              e = a
          } else
            i === e && (e = e.cloneNode(!0),
              n.appendChild(e))
        })
      }
      ).observe(document.body, {
        attributes: !0,
        childList: !0,
        subtree: !0
      })
    }
  }

Измените его, чтобы улучшить читаемость:

  function observeSelector(element) {
    if (element) {
      const parentNode = element.parentNode || document.body;
      // 为什么这么做?因为这是最原始的节点了
      // 如果直接拿element去replace只能拿到具有最新属性的节点
      const newClonedNode = element.cloneNode(true);
      new MutationObserver(mutations => {
        mutations.forEach(mutationRecord => {
          const currentTarget = mutationRecord.target;
          const removedNode = mutationRecord.removedNodes[0];
          // 修改属性的时候,target就是当前元素
          if (currentTarget === element) {
            const replaceNode = newClonedNode.cloneNode(true);
            parentNode.replaceChild(replaceNode, element);
            element = replaceNode;
          } else {
            // 删除元素的时候,removedNodes是一个数组,只删它一个,那第一个就是当前元素
            if (removedNode === element) {
              element = element.cloneNode(true);
              parentNode.appendChild(element);
            }
          }
        });
      }).observe(document.body, {
        attributes: true,
        childList: true,
        subtree: true, // 监听后代节点变化
      });
    }
  }
  • При изменении атрибутов (когда атрибуты имеют значение true, изменение атрибутов узла может инициировать этот обратный вызов) в это время целью под мутациейRecord каждого элемента мутаций является текущий узел. Идея такова: изменить его и заменить его

  • При удалении узла массив removeNodes в MutationRecord представляет собой массив всех узлов, которые в настоящее время удалены. Конечно, здесь мы удалили только один узел, поэтому узел только один. Идея такова: удалить один и добавить его обратно

Эту функцию можно напрямую использовать в «защите элементов», добавляя MutationObserver к элементу, чтобы другие люди с техническим образованием не могли открыть консоль, чтобы изменить этот элемент, чтобы сделать некоторые другие скрытые секретные вещи (поддельные скриншоты, перекрестные разрешения, открытые данные, но с водяными знаками). )

Эту функцию можно использовать для защиты элементов, чтобы некоторые внешние интерфейсы не открывали консоль для изменения элементов, а затем делали снимки экрана. Конечно, если вам нужно использовать его в своих требованиях, вам нужно учитывать вещи: очистку обозревателя по времени, масштабируемость и совместимость.

как это победить

магический стиль

Изменение стиля родительского узла может решить проблему, но родительским водяным знаком этой страницы является тело, и изменение тела повлияет на просмотр страницы. Мы можем изменить угол и добавить прозрачный стиль фона к псевдоэлементу перед водяным знаком, чтобы он был похож на цвет водяного знака.

// 137是canvas的getimagedata知道的
    var str = `.水印div的class::before {
      content: '';
      width: 100vw;
      height: 100vh;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10000;
      background-color: rgba(137, 137, 137, 0.95);
      pointer-events: none;
    }`;

    var style = document.createElement('style');
    style.textContent = str;
    document.head.appendChild(style);
    // 酌情微调一下fliter,如对比度、亮度、饱和度等
    document.body.style.filter = 'contrast(6.5)'

Однако это сделает страницу мутной и покроется слоем

Удалить основной контент

Мы знаем, что им можно управлять, вмешиваясь в стиль его родительского узла, но мы боимся непредумышленного уничтожения содержимого. Итак, почему бы нам не удалить содержимое и не скрыть тело (appendChild имеет эффект «высасывания»)

// 控制台选中主内容, 即document.querySelector('水印元素选择器')
document.documentElement.appendChild($0)

Затем добавьте в тело display: none, и появится белая страница без водяных знаков!

document.body.style.display = 'none';

Владею клюшкой, но целюсь во двор. На самом деле, если вы снова используете MutationObserver для мониторинга document.documentElement и обнаружите, что добавлен новый элемент водяного знака, добавьте его обратно в тело и предотвратите это:

    ((targetNode) => {
      new MutationObserver((mutations) => {
        mutations.forEach(({ addedNodes }) => {
          addedNodes.forEach(node => {
            if (node === targetNode) {
              document.body.appendChild(targetNode)
            }
          })
        });
      }).observe(document.documentElement, {
        childList: true,
      });
    })(document.querySelector('水印元素选择器'));

эм... Вы когда-нибудь задумывались о том, что происходит с матрешкой, наблюдайте за новым целевым узлом под html, а затем перемещайте его в тело, наблюдайте за новым целевым узлом под телом, затем перемещайте его в html и затем добавьте новый узел в html

    ((targetNode) => {
      new MutationObserver((mutations) => {
        mutations.forEach(({ addedNodes }) => {
          addedNodes.forEach(node => {
            if (node === targetNode) {
              document.body.appendChild(targetNode)
            }
          })
        });
      }).observe(document.documentElement, {
        childList: true,
      });
    })(document.querySelector('水印元素选择器'));
    // 新增body的observe
    ((targetNode) => {
      new MutationObserver((mutations) => {
        mutations.forEach(({ addedNodes }) => {
          addedNodes.forEach(node => {
            if (node === targetNode) {
              document.documentElement.appendChild(targetNode)
            }
          })
        });
      }).observe(document.body, {
        childList: true,
      });
    })(document.querySelector('水印元素选择器'));

Не говорите этого, мой компьютер сильно нагревается, предполагается, что его код работоспособности стал красным, и его нужно изолировать от меня. Бывает бесконечный цикл, нужно быть внимательным при его использовании

Если вы хотите решить проблему, связанную с тем, что MutationObserver отслеживает document.documentElement, чтобы предотвратить перемещение элемента водяного знака, все еще есть способ: добавьте элемент div в элемент documentElement и переместите элемент водяного знака в элемент div.

Поскольку div добавляется, чтобы выйти за рамки этого шага, предотвращение также может быть усилено. MutationObserver — это универсальный подход, запрещающий выполнение всех дочерних списков и поддеревьев. Если это не элемент водяного знака, удалите его и если это элемент водяного знака, поместите его обратно в тело.

Это все так бессердечно, тогда я напишу скрипт инъекций плагина для браузера Google, напрямую модифицирую глобальный MutationObserver, чтобы посмотреть, как вы играете... Давайте закончим, вещи всегда выше дьявола, давайте поговорим об этом. на сервер для борьбы с остроумием

Обратите внимание на официальный аккаунт «Другой интерфейс», изучите интерфейс с другой точки зрения, быстро развивайтесь, играйте с новейшими технологиями, изучайте различные черные технологии и делайте что-то вместе.