如何防止反代盗站

反向代理可以轻松地镜像一个网站,但像是博客这种知识产权很重要的网站,我们不希望有人建立镜像站,如何处理呢?

其实很简单,前端js检测当前的域名,不符合我们的网站就跳转回来,这样镜像站反而帮我们引流了。

下面就是一个这样的js的示例。

/**
 * 域名跳转脚本
 * 功能:如果当前访问的hostname不在允许的域名数组中,则随机跳转到数组中的一个域名并保留URL参数
 * 避免回环地址和局域网地址跳转
 */

// 允许的域名数组
const allowedDomains = [
    'example.com',
    'domain1.com',
    'domain2.com',
    'yourwebsite.com'
];

/**
 * 检查是否为回环地址或局域网地址
 * @param {string} hostname - 要检查的主机名
 * @returns {boolean} - 如果是回环或局域网地址返回true,否则返回false
 */
function isLoopbackOrLocalNetwork(hostname) {
    // 回环地址
    const loopbackPatterns = [
        /^localhost$/,
        /^127(\.\d{1,3}){3}$/
    ];
    
    // 局域网地址
    const localNetworkPatterns = [
        /^10(\.\d{1,3}){3}$/,  // 10.0.0.0/8
        /^172\.(?:1[6-9]|2[0-9]|3[01])(\.\d{1,3}){2}$/,  // 172.16.0.0/12
        /^192\.168(\.\d{1,3}){2}$/,  // 192.168.0.0/16
        /^169\.254(\.\d{1,3}){2}$/,  // 169.254.0.0/16 (链路本地地址)
        /^fc00:/,  // IPv6唯一本地地址
        /^fe80:/   // IPv6链路本地地址
    ];
    
    // 检查是否匹配回环地址模式
    for (const pattern of loopbackPatterns) {
        if (pattern.test(hostname)) {
            return true;
        }
    }
    
    // 检查是否匹配局域网地址模式
    for (const pattern of localNetworkPatterns) {
        if (pattern.test(hostname)) {
            return true;
        }
    }
    
    return false;
}

/**
 * 从URL中提取主机名(这种处理方法得到的URL不包含端口号)
 * @param {string} url - 完整URL
 * @returns {string} - 主机名
 */
function extractHostname(url) {
    // 创建一个临时元素来解析URL
    const a = document.createElement('a');
    a.href = url;
    return a.hostname;
}

/**
 * 从允许的域名数组中随机选择一个域名(不包括当前域名)
 * @param {string} currentHostname - 当前主机名
 * @returns {string|null} - 选中的域名或null(如果没有其他可用域名)
 */
function getRandomAllowedDomain(currentHostname) {
    // 过滤出不等于当前主机名且不是回环/局域网地址的域名
    const availableDomains = allowedDomains.filter(domain => 
        domain !== currentHostname && !isLoopbackOrLocalNetwork(domain)
    );
    
    if (availableDomains.length === 0) {
        return null;
    }
    
    // 随机选择一个域名
    const randomIndex = Math.floor(Math.random() * availableDomains.length);
    return availableDomains[randomIndex];
}

/**
 * 执行域名跳转逻辑
 */
function handleDomainRedirect() {
    const currentUrl = window.location.href;
    const currentHostname = extractHostname(currentUrl);
    
    // 检查当前主机名是否在允许的域名数组中
    if (!allowedDomains.includes(currentHostname)) {
        // 检查是否为回环或局域网地址(这些地址不执行跳转)
        if (isLoopbackOrLocalNetwork(currentHostname)) {
            console.log('在回环地址或局域网地址上,不执行跳转');
            return;
        }
        
        // 获取一个随机的允许域名
        const targetDomain = getRandomAllowedDomain(currentHostname);
        
        if (targetDomain) {
            // 构建新的URL,保留协议、路径和查询参数
            const protocol = window.location.protocol;
            const path = window.location.pathname;
            const search = window.location.search;
            const hash = window.location.hash;
            
            const newUrl = `${protocol}//${targetDomain}${path}${search}${hash}`;
            
            console.log(`从 ${currentHostname} 跳转到 ${targetDomain}`);
            window.location.href = newUrl;
        } else {
            console.log('没有可用的目标域名进行跳转');
        }
    } else {
        console.log('当前域名在允许列表中,无需跳转');
    }
}

// 执行跳转逻辑
// 可以根据需要调整执行时机,这里直接执行
// 为了避免页面闪烁,可以考虑在DOMContentLoaded之前执行
if (typeof window !== 'undefined') {
    handleDomainRedirect();
}

当然,如果搭建镜像的人设置了文本替换,我们的引用js文件的地址、js内的地址都可能被替换,真正在使用时候需要进行混淆加密、以文本形式加在页面上

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容