You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制JavaScript文件仅授权站点可访问?ASP.NET MVC/Core方案

嘿,这个场景我之前帮朋友处理过,刚好能给你一些实用的方案。核心思路就是只让你授权的站点通过合法请求拿到这个JS文件,咱们分ASP.NET MVC和ASP.NET Core两种环境来具体说:

在ASP.NET MVC中的实现方式

方案1:检查Referer请求头(快速入门)

这个方案适合对安全性要求不是极高的场景,利用请求的Referer头判断来源是否合法——这个头会告诉服务器请求是从哪个站点发起的。

你可以自定义一个Action过滤器,拦截返回JS文件的请求:

public class AuthorizeReferrerAttribute : ActionFilterAttribute
{
    // 这里放你的授权站点名单
    private readonly List<string> _allowedHosts = new List<string> { "your-allowed-site1.com", "your-allowed-site2.com" };

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var referrer = filterContext.HttpContext.Request.UrlReferrer;
        // 没有Referer或者不在授权列表里,直接返回403
        if (referrer == null || !_allowedHosts.Contains(referrer.Host, StringComparer.OrdinalIgnoreCase))
        {
            filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
            return;
        }
        base.OnActionExecuting(filterContext);
    }
}

然后把你的JS文件从静态目录移出来,通过控制器Action返回,给这个Action加上过滤器:

public class JsController : Controller
{
    [AuthorizeReferrer]
    public ActionResult ProtectedScript()
    {
        // 读取JS文件内容,路径根据你的实际存储位置调整
        var jsContent = System.IO.File.ReadAllText(Server.MapPath("~/PrivateScripts/MyProtected.js"));
        return Content(jsContent, "application/javascript");
    }
}

授权站点就可以通过https://your-server.com/Js/ProtectedScript来引用这个JS了。

方案2:签名验证(防伪造,更安全)

Referer头是可以被伪造的,如果你需要更高的安全性,就用签名验证:让授权站点请求时带上用密钥生成的签名,服务器端验证签名合法性。

示例控制器代码:

public class JsController : Controller
{
    // 存储授权站点的ID和对应密钥
    private readonly Dictionary<string, string> _allowedSites = new Dictionary<string, string>
    {
        {"site1", "your-strong-secret-key-1"},
        {"site2", "your-strong-secret-key-2"}
    };

    public ActionResult ProtectedScript(string siteId, string timestamp, string signature)
    {
        // 先验证站点是否在授权列表里
        if (!_allowedSites.TryGetValue(siteId, out var secretKey))
        {
            return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
        }

        // 验证时间戳,防止重放攻击(这里限制5分钟内的请求有效)
        if (!long.TryParse(timestamp, out var requestTime) || 
            DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds - requestTime > 300)
        {
            return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
        }

        // 生成预期签名并对比
        var expectedSignature = GenerateSignature($"{siteId}{timestamp}", secretKey);
        if (!string.Equals(signature, expectedSignature, StringComparison.OrdinalIgnoreCase))
        {
            return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
        }

        // 返回JS内容
        var jsContent = System.IO.File.ReadAllText(Server.MapPath("~/PrivateScripts/MyProtected.js"));
        return Content(jsContent, "application/javascript");
    }

    // 生成HMAC签名的方法
    private string GenerateSignature(string data, string secretKey)
    {
        using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey)))
        {
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

授权站点需要用自己的siteId和密钥生成签名,拼在请求URL里,比如:
https://your-server.com/Js/ProtectedScript?siteId=site1&timestamp=1700000000&signature=abcdef123456...

在ASP.NET Core中的实现方式

方案1:Referer验证中间件

Core里用中间件拦截静态文件请求更灵活,先写一个中间件:

public class ReferrerValidationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly List<string> _allowedHosts = new List<string> { "your-allowed-site1.com", "your-allowed-site2.com" };
    // 要保护的JS文件路径
    private readonly string _protectedJsPath = "/js/my-protected.js";

    public ReferrerValidationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 只拦截目标JS文件的请求
        if (context.Request.Path.Equals(_protectedJsPath, StringComparison.OrdinalIgnoreCase))
        {
            if (!context.Request.Headers.TryGetValue("Referer", out var referrerValue))
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                await context.Response.WriteAsync("Forbidden: No referrer provided");
                return;
            }

            if (!Uri.TryCreate(referrerValue, UriKind.Absolute, out var referrerUri) || 
                !_allowedHosts.Contains(referrerUri.Host, StringComparer.OrdinalIgnoreCase))
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                await context.Response.WriteAsync("Forbidden: Unauthorized referrer");
                return;
            }
        }

        // 验证通过,继续处理请求
        await _next(context);
    }
}

// 扩展方法,方便注册中间件
public static class ReferrerValidationMiddlewareExtensions
{
    public static IApplicationBuilder UseReferrerValidation(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ReferrerValidationMiddleware>();
    }
}

然后在Program.cs里注册这个中间件,一定要放在UseStaticFiles之前:

var app = builder.Build();

// 先验证Referrer,再处理静态文件
app.UseReferrerValidation();
app.UseStaticFiles();

// ...其他中间件

方案2:签名验证控制器

和MVC的思路一致,Core里可以结合配置文件存储密钥,示例代码:

[ApiController]
[Route("api/js")]
public class JsController : ControllerBase
{
    private readonly IConfiguration _config;

    public JsController(IConfiguration config)
    {
        _config = config;
    }

    [HttpGet("protected")]
    public IActionResult GetProtectedJs(string siteId, string timestamp, string signature)
    {
        // 从配置文件读取对应站点的密钥
        var secretKey = _config.GetValue<string>($"AllowedSites:{siteId}:SecretKey");
        if (string.IsNullOrEmpty(secretKey))
        {
            return Forbid();
        }

        // 验证时间戳
        if (!long.TryParse(timestamp, out var requestTime) || 
            DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds - requestTime > 300)
        {
            return Forbid();
        }

        // 验证签名
        var expectedSignature = GenerateSignature($"{siteId}{timestamp}", secretKey);
        if (!string.Equals(signature, expectedSignature, StringComparison.OrdinalIgnoreCase))
        {
            return Forbid();
        }

        // 读取JS文件内容
        var jsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "js", "my-protected.js");
        var jsContent = System.IO.File.ReadAllText(jsPath);
        return Content(jsContent, "application/javascript");
    }

    private string GenerateSignature(string data, string secretKey)
    {
        using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey)))
        {
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

配置文件appsettings.json里添加授权站点信息:

"AllowedSites": {
  "site1": {
    "SecretKey": "your-strong-secret-key-1"
  },
  "site2": {
    "SecretKey": "your-strong-secret-key-2"
  }
}
关键注意事项
  • Referer头的局限性:部分浏览器或代理会屏蔽Referer头,且这个头可以被伪造,所以只适合作为基础防护。
  • 签名方案的安全性:一定要保管好密钥,绝对不能泄露给第三方;时间戳验证能有效防止重放攻击。
  • 静态文件处理:受保护的JS不能直接放在静态目录(比如wwwroot),必须通过控制器或中间件拦截返回,否则验证逻辑会失效。
  • 强制HTTPS:所有请求都要使用HTTPS,防止请求参数被窃听或篡改。

内容的提问来源于stack exchange,提问作者Ian Vink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:11:21