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

Azure Storage账户:带SAS Url的文件上传仍遭防火墙拦截

问题:Azure Blob Storage SAS URL在受限网络下的403权限问题

我开发了一个文件共享Web应用,上传流程如下:

  • 用户选择本地文件并点击上传按钮
  • 向Azure VM上的后端服务发送请求,后端生成带SAS密钥的URL并返回
  • 前端通过该SAS URL发送PUT请求完成文件上传

生成SAS URL的代码如下:

export function generate_AzureBlob_signed_url(CONTAINER_NAME, BLOB_NAME) {
  
  const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME as string;
  const ACCOUNT_KEY = process.env.AZURE_BLOB_STORAGE_ACCOUNT_KEY as string;

  // TODO: 按安全最佳实践,需改用用户委托SAS而非访问密钥
  const sharedKeyCredential = new StorageSharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)
    
  // URL有效期1小时
  const expDate = new Date(new Date().valueOf() + 3600 * 1000);

  // 生成Blob级别的服务SAS
  const blobSAS = generateBlobSASQueryParameters({
    containerName: CONTAINER_NAME, // 必填
    blobName: BLOB_NAME, // 必填
    permissions: BlobSASPermissions.parse("racwd"), // 必填 // TODO: 可进一步细化权限,比如限定HTTP方法
    startsOn: new Date(), // 可选
    expiresOn: expDate, // 必填,日期类型
    cacheControl: "cache-control-override", // 可选
    contentDisposition: "content-disposition-override", // 可选
    contentEncoding: "content-encoding-override", // 可选
    contentLanguage: "content-language-override", // 可选
    contentType: "content-type-override", // 可选
    ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, // 可选
    protocol: SASProtocol.HttpsAndHttp, // 可选
    version: "2019-12-12" // 可选
  },
  sharedKeyCredential 
  ).toString();

  const SaSURL = `https://${ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}/${BLOB_NAME}?${blobSAS}`;
  console.log(`SAS URL for blob is: ${SaSURL}`);
  return SaSURL;
}

生成的SAS URL示例(解析后):

https://myapp.blob.core.windows.net/issues/issues/src-HosE/dst-HosX/2023-08-31-18-44/b01e7dd3cb2ea333/raw/BJFC00272274T500_006.dcm?sv=2019-12-12 &spr=https%2Chttp &st=2023-08-31T09%3A44%3A28Z &se=2023-08-31T10%3A44%3A28Z &sip=0.0.0.0-255.255.255.255 &sr=b &sp=racwd &sig=JIAZVvddUI5FQ1DGNIMhJQUajxOxHduzfLNq%2F4OhlIA%3D &rscc=cache-control-override &rscd=content-disposition-override &rsce=content-encoding-override &rscl=content-language-override &rsct=content-type-override

但前端发送PUT请求时返回403错误:

PUT https://myapp.blob.core.windows.net/issues/issues/src-HosE/dst-HosX/2023-08-31-18-44/b01e7dd3cb2ea333/raw/BJFC00272274T500_006.dcm?sv=2019-12-12&spr=https%2Chttp&st=2023-08-31T09%3A44%3A28Z&se=2023-08-31T10%3A44%3A28Z&sip=0.0.0.0-255.255.255.255&sr=b&sp=racwd&sig=JIAZVvddUI5FQ1DGNIMhJQUajxOxHduzfLNq%2F4OhlIA%3D&rscc=cache-control-override&rscd=content-disposition-override&rsce=content-encoding-override&rscl=content-language-override&rsct=content-type-override 

403 (This request is not authorized to perform this operation.)

当前存储账户网络设置为仅允许选定虚拟网络和IP地址访问,将用户IP添加到防火墙规则后上传成功,说明SAS URL请求仍被网络防火墙拦截。需要实现:无需改为“允许全部网络访问”,让公网任意用户通过SAS URL上传文件,达到类似AWS S3预签名URL的效果。


解决方案

方案1:启用“允许受信任的Microsoft服务访问”例外

在存储账户的防火墙和虚拟网络设置中,找到“例外”区域,勾选允许受信任的Microsoft服务访问此存储账户。该选项允许通过SAS授权的请求绕过网络防火墙限制,即使请求来源IP不在允许列表内。

方案2:改用用户委托SAS(User Delegation SAS)

当前代码使用的是基于存储账户密钥的服务SAS,而用户委托SAS通过Azure AD令牌生成,安全性更高,且在网络受限场景下,用户委托SAS的请求默认可绕过存储账户防火墙限制(需确保SAS权限、有效期配置正确)。

修改后的用户委托SAS生成代码示例:

import { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions, SASProtocol } from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

export async function generate_AzureBlob_user_delegation_sas(CONTAINER_NAME, BLOB_NAME) {
  const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME as string;
  const blobServiceClient = new BlobServiceClient(
    `https://${ACCOUNT_NAME}.blob.core.windows.net`,
    new DefaultAzureCredential()
  );

  // 获取用户委托密钥,有效期最长7天
  const userDelegationKey = await blobServiceClient.getUserDelegationKey(
    new Date(),
    new Date(new Date().valueOf() + 7 * 24 * 3600 * 1000)
  );

  // SAS有效期1小时
  const expDate = new Date(new Date().valueOf() + 3600 * 1000);

  const blobSAS = generateBlobSASQueryParameters({
    containerName: CONTAINER_NAME,
    blobName: BLOB_NAME,
    permissions: BlobSASPermissions.parse("cwd"), // 上传仅需创建、写入、删除权限,按需调整
    startsOn: new Date(),
    expiresOn: expDate,
    protocol: SASProtocol.Https, // 建议仅允许HTTPS
    version: "2021-06-08" // 使用支持用户委托SAS的最新版本
  },
  userDelegationKey,
  ACCOUNT_NAME
  ).toString();

  const sasUrl = `https://${ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}/${BLOB_NAME}?${blobSAS}`;
  console.log(`User Delegation SAS URL: ${sasUrl}`);
  return sasUrl;
}

方案3:配置VNet服务端点或专用链接(适合后端在Azure VNet内的场景)

如果后端服务部署在Azure虚拟网络中,可为存储账户配置VNet服务端点或Azure专用链接。后端可在VNet内生成SAS URL,公网用户通过SAS URL上传时,请求会被正确路由,同时存储账户的网络限制依然生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 08:05:53