网站禁止js跳转非本站域名代码

1、下载文件后解压到本地,其中包含一个js文件夹和放跳转的js文件,按照自己的需求上传到服务器。

如果你的网站根目录有js文件夹,那么直接把里面的js文件上传到js文件夹里,如果根目录没有js文件夹,那么连同js文件夹一起上传到网站根目录。

2、打开并编辑js文件,把白名单域名改成自己的域名,建议填www网址和手机版网址,如果不需要,把下面两行删除,//当前域名前的逗号也删除。

3、把这段js代码引入网站模板,一般是在head.html或include.html文件里,找到</script>标签,把这段代码放在</script>最上面,一定要让这个js文件最先加载,它才能有效拦截跳转。

代码全部:

// 设置允许的域名白名单(包括主域名及其子域名)
const allowedDomains = [
    location.hostname, // 当前域名
    'aaa', // 其他可信域名
    'bbb',
    'ccc'// 子域名
];

// 监听所有链接点击事件
document.addEventListener('click', function(event) {
    // 向上查找最近的<a>标签
    let target = event.target;
    while (target && target.tagName !== 'A') {
        target = target.parentElement;
        if (!target) return;
    }

    const href = target.getAttribute('href');
    
    // 只处理带有href属性的链接
    if (!href || href.startsWith('javascript:')) return;

    try {
        // 解析完整URL
        const url = new URL(href, document.baseURI);
        
        // 检查域名是否在允许列表
        const isAllowed = allowedDomains.some(domain => 
            url.hostname === domain || url.hostname.endsWith('.' + domain)
        );
        
        // 阻止非允许域名的跳转
        if (!isAllowed) {
            event.preventDefault();
            console.warn('禁止跳转到外部域名:', url.hostname);
            alert('为了您的安全,已阻止跳转到外部网站');
            // 这里可以替换为自定义处理逻辑
        }
    } catch (e) {
        // 处理无效URL
        console.error('链接解析错误:', e);
    }
});

// 防止通过修改location跳转
const originalLocation = window.location;
Object.defineProperty(window, 'location', {
    get: () => originalLocation,
    set: value => {
        try {
            const url = new URL(value, document.baseURI);
            if (!allowedDomains.some(d => url.hostname.endsWith(d))) {
                console.warn('已阻止location跳转到:', url.hostname);
                return;
            }
        } catch(e) {}
        originalLocation.href = value;
    },
    configurable: false
});

或前往文章来源处下载文件获取。

根据原作者的内容我改了一份可以拦截window.open的版本,理论上会更强大。

完整代码(anti-redirect.js):

(function () {
  var _original = {
    open: window.open,
    assign: window.location.assign.bind(window.location),
    replace: window.location.replace.bind(window.location),
    setTimeout: window.setTimeout.bind(window),
    setInterval: window.setInterval.bind(window)
  };

  var _hooksInstalled = false;
  var _config = null;

  function init(options) {
    if (_hooksInstalled) return;
    _config = normalizeConfig(options);
    hookWindowOpen();
    hookLocationMethods();
    interceptLinkClicks();
    interceptFormSubmissions();
    hookTimeouts();
    _hooksInstalled = true;
  }

  function disable() {
    if (!_hooksInstalled) return;
    window.open = _original.open;
    window.location.assign = _original.assign;
    window.location.replace = _original.replace;
    window.setTimeout = _original.setTimeout;
    window.setInterval = _original.setInterval;
    _hooksInstalled = false;
    _config = null;
  }

  function normalizeConfig(options) {
    var cfg = options || {};
    var whitelist = Array.isArray(cfg.whitelist) ? cfg.whitelist.slice() : ['self'];
    var allowRelative = cfg.allowRelative !== false;
    var allowNonHttp = cfg.allowNonHttp !== false;
    var blockProtocols = Array.isArray(cfg.blockProtocols) ? cfg.blockProtocols.map(function (p) { return String(p).toLowerCase(); }) : ['javascript', 'data'];
    var onBlocked = typeof cfg.onBlocked === 'function'
      ? cfg.onBlocked
      : function (method, url) {
          console.warn('[AntiRedirect] 已阻止跳转:', method, url);
          try { alert('已阻止跳转到非本站域名: ' + url); } catch (e) {}
        };
    return { whitelist: whitelist, allowRelative: allowRelative, allowNonHttp: allowNonHttp, blockProtocols: blockProtocols, onBlocked: onBlocked };
  }

  function isAllowedUrl(target) {
    try {
      var urlObj = target instanceof URL ? target : new URL(String(target), window.location.href);
      var protocol = urlObj.protocol.toLowerCase();
      var protoName = protocol.replace(':', '');
      if (protoName !== 'http' && protoName !== 'https') {
        if (_config.blockProtocols.indexOf(protoName) !== -1) return false;
        return !!_config && _config.allowNonHttp;
      }
      if (!urlObj.hostname || urlObj.origin === 'null') {
        return !!_config && _config.allowRelative;
      }
      if (urlObj.origin === window.location.origin) return true;
      if (!_config || !_config.whitelist || _config.whitelist.length === 0) return false;
      var host = urlObj.hostname.toLowerCase();
      var origin = (urlObj.origin || (urlObj.protocol + '//' + urlObj.host)).toLowerCase();
      for (var i = 0; i < _config.whitelist.length; i++) {
        var rule = String(_config.whitelist[i]).toLowerCase();
        if (rule === 'self') {
          if (origin === window.location.origin.toLowerCase()) return true;
          continue;
        }
        if (rule.indexOf('://') !== -1) {
          if (origin === rule) return true;
          continue;
        }
        if (rule.startsWith('*.')) {
          var base = rule.slice(2);
          if (host === base || host.endsWith('.' + base)) return true;
          continue;
        }
        if (host === rule || host.endsWith('.' + rule)) return true;
      }
      return false;
    } catch (e) {
      return false;
    }
  }

  function hookWindowOpen() {
    window.open = function (url) {
      if (!isAllowedUrl(url)) {
        _config.onBlocked('window.open', url);
        return null;
      }
      return _original.open.apply(window, arguments);
    };
  }

  function hookLocationMethods() {
    window.location.assign = function (url) {
      if (!isAllowedUrl(url)) {
        _config.onBlocked('location.assign', url);
        return;
      }
      return _original.assign(url);
    };

    window.location.replace = function (url) {
      if (!isAllowedUrl(url)) {
        _config.onBlocked('location.replace', url);
        return;
      }
      return _original.replace(url);
    };
  }

  function interceptLinkClicks() {
    document.addEventListener(
      'click',
      function (ev) {
        try {
          var a = ev.target && ev.target.closest ? ev.target.closest('a[href]') : null;
          if (!a) return;
          var href = a.href || a.getAttribute('href') || '';
          if (!href) return;
          if (!isAllowedUrl(href)) {
            ev.preventDefault();
            ev.stopPropagation();
            _config.onBlocked('link.click', href);
          }
        } catch (e) {}
      },
      true
    );
  }

  function interceptFormSubmissions() {
    document.addEventListener(
      'submit',
      function (ev) {
        try {
          var form = ev.target;
          if (!form || !form.action) return;
          var action = form.action;
          if (!isAllowedUrl(action)) {
            ev.preventDefault();
            ev.stopPropagation();
            _config.onBlocked('form.submit', action);
          }
        } catch (e) {}
      },
      true
    );
  }

  function hookTimeouts() {
    window.setTimeout = function (handler, timeout) {
      if (typeof handler === 'string') {
        var url = extractUrlFromCode(handler);
        if (url && !isAllowedUrl(url)) {
          _config.onBlocked('setTimeout.string', url);
          return 0;
        }
      }
      return _original.setTimeout.apply(window, arguments);
    };

    window.setInterval = function (handler, timeout) {
      if (typeof handler === 'string') {
        var url = extractUrlFromCode(handler);
        if (url && !isAllowedUrl(url)) {
          _config.onBlocked('setInterval.string', url);
          return 0;
        }
      }
      return _original.setInterval.apply(window, arguments);
    };
  }

  function extractUrlFromCode(code) {
    try {
      var patterns = [
        /location\s*\.\s*href\s*=\s*['"]([^'"]+)['"]/i,
        /location\s*\.\s*assign\s*\(\s*['"]([^'"]+)['"]\s*\)/i,
        /location\s*\.\s*replace\s*\(\s*['"]([^'"]+)['"]\s*\)/i,
        /window\s*\.\s*open\s*\(\s*['"]([^'"]+)['"]\s*,/i
      ];
      for (var i = 0; i < patterns.length; i++) {
        var m = code.match(patterns[i]);
        if (m && m[1]) return m[1];
      }
      return null;
    } catch (e) {
      return null;
    }
  }

  window.AntiRedirect = {
    init: init,
    disable: disable,
    isAllowed: function (url) { return isAllowedUrl(url); }
  };
})();

适用类型:

  • 恶意跳转到其它网站
  • 手机上首次访问网站时被劫持跳转到外部站点

本脚本通过拦截常见的 JS 跳转入口,阻止页面“导航到非白名单域名”,并支持白名单与协议策略配置。脚本仅对“导航行为”做域名检测,不拦截外部 JS、IMG、CSS 等资源的加载。

将js文件引入到页面的 <head> 或 <body>  使用方法和前面的版本差不多。

但需要在引入的代码下面再新加一段代码,用<script></script>包裹:

AntiRedirect.init({
    // 白名单支持:'self'(同源)、纯域名、通配子域名、完整源(含协议)
    whitelist: ['self', '*.example.com', 'https://trusted.partner.com'],
    // 是否允许相对链接(站内链接通常是相对路径)
    allowRelative: true,
    // 协议策略:仅对 http/https 导航做域名检测
    // 非 http/https 协议默认允许(满足“只做域名检测”),但可指定需阻止的协议
    allowNonHttp: true,
    blockProtocols: ['javascript', 'data'],
    // 拦截回调(可选):自行处理提示或上报
    onBlocked(method, url) {
      console.warn('已阻止跳转', method, url);
    }
  });
  // 需要时可调用 AntiRedirect.disable() 关闭拦截
  // 也可单独使用 AntiRedirect.isAllowed(url) 做判断

  • All rights reserved.
  • No part of this website, including text and images, may be reproduced, modified, distributed, or transmitted in any form or by any means, without the prior written permission of the author.
  • Unauthorized commercial use is strictly prohibited.
  • Unauthorized personal use is strictly prohibited.