织梦下载附件改名防止盗链

织梦DedeCMS站点的下载附件常被其他站点盗链,盗链者直接引用附件 URL 消耗本站带宽资源,却不带来任何流量。通过附件改名和防盗链配置,可有效防止资源被恶意引用。本文讲解附件防盗链的完整实施方案。

一、附件盗链的原理与危害

1. 盗链原理

盗链者获取附件真实 URL 后,在其站点直接嵌入该 URL。用户访问盗链站点时,浏览器从本站服务器下载附件,消耗本站带宽。

2. 主要危害

带宽被大量消耗,服务器成本增加;附件被外部站点免费使用,削弱本站内容独占性;附件 URL 公开后可被搜索引擎索引,导致流量直接流向文件而非页面。

二、附件目录改名防盗链

1. 修改默认附件目录

织梦默认附件目录为 /uploads/soft/,被猜测的风险高。修改为不可预测的目录名:

// 后台 - 系统基本参数 - 附件设置
// 附件目录改为随机命名
$cfg_soft_dir='/uploads/dl_'.substr(md5('salt'), 0, 8).'/';
// 实际目录如:/uploads/dl_a3f5b2c1/

// 修改后需同步更新已有附件路径
UPDATE dede_addonsoft SET softlinks=REPLACE(softlinks, '/uploads/soft/', '/uploads/dl_a3f5b2c1/');

2. 定期更换附件目录

// 定期改名脚本 rename_attach_dir.php
<?php
require_once(dirname(__FILE__).'/include/common.inc.php');

// 生成新目录名
$new_dir='dl_'.substr(md5(time().mt_rand()), 0, 8);
$old_dir=$cfg_soft_dir; // 当前目录

// 重命名物理目录
rename(DEDEROT.'/uploads/'.$old_dir, 
       DEDEROOT.'/uploads/'.$new_dir);

// 更新配置
$dsql->ExecuteNoneQuery(
  "UPDATE dede_sysconfig SET value='/uploads/$new_dir/' 
   WHERE varname='cfg_soft_dir'"
);

// 更新所有附件路径
$dsql->ExecuteNoneQuery(
  "UPDATE dede_addonsoft SET softlinks=REPLACE(softlinks, '$old_dir', '/uploads/$new_dir/')"
);

echo "附件目录已从 $old_dir 更改为 /uploads/$new_dir/";
?>
定期改名会导致旧附件 URL 失效,已分享出去的链接将 404。改名频率建议每月一次,或仅在发现盗链后执行。改名后需重新生成相关页面。

三、Referer 防盗链配置

1. Nginx 防盗链

# nginx.conf
location ~* \.(zip|rar|exe|doc|pdf|mp4|mp3)$ {
  valid_referers none blocked server_names 
    *.example.com example.com;
  
  if($invalid_referer){
    return 403;
    # 或重定向到提示页
    # return 302 https://www.example.com/403.html;
  }
}

# 允许空 Referer(直接访问)可选
# blocked 允许防火墙修改过的 Referer
# none 允许空 Referer

2. Apache 防盗链

# .htaccess
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?example\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^https://(www\.)?baidu\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^https://(www\.)?google\.com/ [NC]
RewriteRule \.(zip|rar|exe|pdf)$ - [F,L]

# 允许搜索引擎 Referer,避免影响图片搜索

四、动态下载链接防盗链

静态附件 URL 容易被盗链,改为动态生成的临时下载链接,链接含时效和签名验证:

1. 生成带签名的下载链接

// /plus/download.php 修改下载逻辑
function generateDownloadUrl($aid, $filename){
  $secret='your_secret_key';  // 签名密钥
  $expire=time() + 3600;      // 1小时过期
  
  // 生成签名
  $sign=md5($aid.$filename.$expire.$secret);
  
  // 返回动态 URL
  return "/plus/download.php?aid={$aid}&expire={$expire}&sign={$sign}";
}

// 文章模板中调用动态链接
{dede:field name='softlinks' runphp='yes'}
  @me=generateDownloadUrl($GLOBALS['aid'], @me);
{/dede:field}

2. 下载时验证签名

// /plus/download.php
$aid=intval($_GET['aid']);
$expire=intval($_GET['expire']);
$sign=$_GET['sign'];
$secret='your_secret_key';

// 验证签名
$expected_sign=md5($aid.$filename.$expire.$secret);
if($sign !==$expected_sign){
  ShowMsg('下载链接无效', 'javascript:;');
  exit();
}

// 验证是否过期
if(time() > $expire){
  ShowMsg('下载链接已过期,请刷新页面', 'javascript:;');
  exit();
}

// 验证 Referer
if(strpos($_SERVER['HTTP_REFERER'], 'example.com')===false){
  ShowMsg('请从本站页面下载', 'javascript:;');
  exit();
}

// 通过验证,输出文件
$file=DEDEROOT.$realpath;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Length: '.filesize($file));
readfile($file);
exit();

五、下载权限控制

1. 会员等级限制

// download.php 中检查会员权限
if($cfg_ml->IsLogin()){
  $userrank=$cfg_ml->M_Rank;
  if($userrank < $need_rank){
    ShowMsg('会员等级不足,无法下载', 'javascript:;');
    exit();
  }
} else {
  ShowMsg('请先登录', '/member/login.php');
  exit();
}

// 扣除下载积分
$dsql->ExecuteNoneQuery(
  "UPDATE dede_member SET scores=scores-{$need_scores} 
   WHERE mid='".$cfg_ml->M_ID."'"
);

2. 下载次数限制

// 检查当日下载次数
$today=strtotime(date('Y-m-d'));
$count=$dsql->GetOne(
  "SELECT COUNT(*) as c FROM dede_down_log 
   WHERE mid='".$cfg_ml->M_ID."' AND time > $today"
);
if($count['c'] >=10){
  ShowMsg('今日下载次数已达上限', 'javascript:;');
  exit();
}

// 记录下载日志
$dsql->ExecuteNoneQuery(
  "INSERT INTO dede_down_log(mid,aid,time,ip) 
   VALUES('".$cfg_ml->M_ID."','$aid','".time()."','".GetIP()."')"
);

六、宝塔面板防盗链配置

宝塔面板 - 网站 - 设置 - 防盗链:
- 开启防盗链:开启
- 允许的域名:*.example.com
- 授权域名:baidu.com, google.com
- 防盗链文件类型:zip,rar,exe,doc,pdf,mp4
- 防盗链提示:/403.html

// 配置后自动生成 Nginx 规则,无需手动编辑配置文件

七、注意事项

防盗链配置可能影响搜索引擎对附件的抓取,需在允许列表中加入搜索引擎域名。动态下载链接需考虑缓存问题,生成的页面静态化后链接过期时间需合理设置。签名密钥需定期更换,密钥泄露后所有链接失效需重新生成。下载日志表需定期清理,避免数据量过大影响查询性能。CDN 环境下 Referer 可能被修改,需配合 CDN 的防盗链功能使用。

附件防盗链是织梦站点资源保护的重要措施,单一手段难以彻底杜绝盗链。建议采用「目录改名+动态签名链接+Referer 校验」的组合策略,多层面阻断盗链行为。同时通过下载日志分析盗链来源,针对性加强防护。在保护资源的同时注意合法用户的下载体验,让验证流程尽可能无感,既守护站点带宽成本,又保障正常用户的下载顺畅。