代客密钥模式

使用令牌为客户提供特定资源的受限的直接访问权限,以便从应用程序卸载数据传输。这对于在云上托管存储系统和队列的应用及其有用,并且可以最小化成本并最大化可伸缩性和性能。

背景和问题

客户端程序和Web浏览器经常需要读取和写入应用程序存储中的文件或数据流。通常情况下,应用程序将处理数据的移动-从存储中获取数据并将其传输到客户端,或者通过读取客户端上传的数据流并将其保存在数据存储中。但是,这种方式消耗了宝贵的服务器资源,如计算,内存和带宽。

数据存储能够直接处理数据的上传和下载,不需要应用程序执行任何处理来移动这些数据。但是,这通常要求客户端有权访问数据存储的安全凭证。这可能是一个有用的技术,来最大限度地减少数据传输成本和扩展应用程序的要求,并最大限度地提高性能。这同时意味着应用程序不再能够管理数据的安全性。客户端连接到数据存储以进行直接访问后,应用程序不能充当守门人。它不再控制流程,也不能防止后续上传或从数据存储下载。

在分布式系统中为不可信的客户端提供服务不是一个现实的方法。相反,应用程序必须能够以细粒度的方式安全地控制对数据的访问,但通过设置此连接,然后允许客户端直接与数据存储进行通信以执行所需的读取或写入操作,仍然可以减少服务器上的负载。

解决方案

需要解决数据存储的访问控制问题,存储无法管理客户端的身份验证和授权。一种典型的解决方案是限制对数据存储的公共连接的访问​​,并为客户端提供数据存储可以验证的密钥或令牌。

这个密钥或令牌通常称为代客密钥。它提供对特定资源的限定时间访问,并只允许预定义的操作,如读取和写入存储或队列,或在Web浏览器中上传和下载。应用程序可以快速方便地创建和发布客户端设备和Web浏览器的代客密钥,从而允许客户端执行所需的操作,而无需应用程序直接处理数据传输。这消除了应用程序和服务器的处理开销以及对性能和可伸缩性的影响。

客户端使用此令牌在限定时间内访问数据存储中的特定资源,访问权限也有特定的限制,如下图所示。在指定的时间段之后,密钥变无效,并且不允许访问资源。

也可以配置具有其它依赖的密钥,如数据的范围。例如,根据数据存储能力,密钥可以在数据存储中指定一个完整的表,或者只在表中指定特定的行。在云存储系统中,密钥可以指定一个容器,或者只是一个容器中的特定项目。

应用程序可以废止密钥。这是一个有用的方法,如果客户端通知服务器数据传输操作完成。服务器可以使该密钥无效以阻止进一步的操作。

使用此模式可以简化对资源的访问管理,因为不需要创建和验证用户,授予权限,然后再删除用户。它还可以很容易地限制位置,权限和有效期-只需在运行时生成密钥即可。比较重要的是尽可能严格地限制资源的有效期,尤其是资源的位置,使得接收方只能将其用于预期的目的。

问题和注意事项

在决定如何实现这种模式时,请考虑以下几点:

管理密钥的有效状态和期限。如果被泄露或破解,密钥有效地解锁目标项目,并使其在有效期内被恶意使用。通常可以撤销或禁用密钥,具体取决于密钥的发放方式。服务器端策略可以更改,或者可以使其签名的服务器密钥失效。指定一个短的有效期限,以尽可能减少对数据存储进行未经授权的操作的风险。但是,如果有效期太短,客户可能无法在密钥过期之前完成操作。如果需要多次访问受保护资源,允许授权用户在有效期到期前更新密钥。

控制密钥将提供的访问级别。通常,密钥应允许用户仅执行完成操作所必需的操作,例如,如果客户端不能将数据上载到数据存储区,则只读访问。对于文件上传,通常指定提供只写权限的密钥以及位置和有效期限。准确地指定密钥适用的资源或资源集合至关重要。

考虑如何控制用户的行为。实现这种模式意味着某些对用户授权访问的资源的控制权的丧失。可以施加的控制级别受限于可用于服务或目标数据存储的策略和权限的能力。例如,通常不可能创建一个限制要写入存储的数据大小的密钥,或者可以使用该密钥访问文件的次数。这可能会导致数据传输的巨大的意外成本,即使是由预期的客户端使用,也可能是由于导致重复上传或下载的代码错误引起的。要限制文件上传的次数,在可能的情况下强制客户端在一个操作完成时通知应用程序。例如,一些数据存储会引发应用程序代码可以用来监视操作和控制用户行为的事件。但是,在一个租户的所有用户使用相同密钥的多租户方案中,很难为单个用户强制执行配额。

验证所有上传的数据并进行选择性清理。有权访问密钥的恶意用户可以上传危害系统的数据。或者,授权用户可能会上传无效的数据,处理后可能会导致错误或系统故障。为了防止这种情况,请确保所有上传的数据在使用前都经过验证并检查是否有恶意内容。

审计所有操作。许多基于密钥的机制都可以记录上传,下载和失败等操作。这些日志通常可以包含在审计过程中,如果用户根据文件大小或数据量收费,也可以用于计费。使用日志来检测可能由密钥提供者的问题导致的身份验证失败,或者意外删除存储的访问策略。

安全地传送密钥。它可以嵌入到用户在网页中激活的URL中,也可以在服务器重定向操作中使用,以便自动下载。始终使用HTTPS通过安全通道传送密钥。

保护传送中的敏感数据。通过应用程序传递的敏感数据通常会使用SSL或TLS进行传输,并且应通过安全传输加强客户端执行直接访问数据存储。

其它需要注意的问题包括:

  • 如果客户端没有或不能通知服务器完成操作,且唯一的限制是密钥的有效期限,则应用程序将不能执行审计操作,例如计数上传或下载,或防止多次上传或下载。
  • 密钥生成的策略的灵活性可能是有限的。例如,有些机制只允许使用定时到期。其他人无法指定足够的读/写权限的粒度。
  • 如果指定了密钥或令牌有效期的开始时间,请确保它比当前服务器时间稍早,以允许可能略微不同步的客户端时钟。如果未指定,则默认通常是当前服务器时间。
  • 包含密钥的URL将被记录在服务器日志文件中。密钥通常会在日志文件用于分析之前过期,但请确保限制访问。如果日志数据传输到监控系统或存储在其它位置,请考虑实施延迟以防止密钥泄漏,直到其有效期到期。
  • 如果客户端代码在Web浏览器中运行,则浏览器可能需要支持跨源资源共享(CORS),以便在Web浏览器中执行的代码能够访问与服务页面不同的域中的数据。一些较旧的浏览器和某些数据存储不支持CORS,而在这些浏览器中运行的代码可能能够使用代客密钥来访问不同域中的数据(例如云存储帐户)。

何时使用该模式

该模式适用于以下场景:

  • 最大限度地减少资源负载并使性能和可伸缩性最大化。使用代客密钥不需要锁定资源,不需要远程服务器调用,可以发出的代客密钥数量没有限制,并且避免了应用程序代码通过执行数据传输而导致的单点故障。创建代客密钥通常是一个使用密钥对字符串进行签名的简单密码操作。
  • 尽量减少运维成本。启用直接访问存储和队列的资源和成本性价比比较高,可以减少网络往返次数,并可能减少所需的计算资源数量。
  • 客户定期上传或下载数据时,特别是在卷数量较大或每次操作涉及大型文件的情况下。
  • 当应用程序可用计算资源有限时,无论是由于主机限制还是成本考虑。在这种情况下,如果存在许多并发数据上传或下载,则该模式更有帮助,因为它可以减轻应用程序处理数据传输的负担。
  • 数据存储在远程数据存储或其它数据中心时。如果要求应用程序充当守门人,在数据中心之间或在客户端与应用程序之间的公共或专用网络之间,然后在应用程序与数据存储区之间需要传输数据的附加带宽。

该模式可能不适用于以下场景:

  • 如果应用程序必须在数据存储之前或在将数据发送到客户端之前对数据执行一些任务。例如,如果应用程序需要执行验证,则记录成功访问或对数据执行转换。但是,一些数据存储和客户端能够协商并进行简单的转换,例如压缩和解压缩(例如,网页浏览器通常可以处理GZip格式)。
  • 如果现有应用程序的设计难以集成模式。使用这种模式通常需要采用不同的架构方法来发送和接收数据。
  • 如果需要维护审计跟踪或控制执行数据传输操作的次数,并且正在使用的代客密钥机制不支持服务器可用来管理这些操作的通知。
  • 如果有必要限制数据的大小,特别是在上传时。唯一的解决办法是让应用程序在操作完成后检查数据大小,或者在指定的时间段或按照预定的时间检查上传的大小。

案例

Azure支持Azure存储上的共享访问签名,用于对Blob,表和队列中的数据以及Service Bus队列和主题进行细粒度访问控制。共享访问签名令牌可以配置为向特定表提供特定的访问权限,例如读取,写入,更新和删除;表格中的键范围;一个队列;一个blob;或一个blob容器。有效期可以是指定的时间段,也可以是没有时间限制。

Azure共享访问签名还支持服务器存储的访问策略,这些访问策略可以与特定的资源(如表或Blob)相关联。与应用程序生成的共享访问签名令牌相比,此功能提供了额外的控制和灵活性,应尽可能使用。在服务器存储的策略中定义的设置可以更改并反映在令牌中,不需要发出新的令牌,但是令牌中定义的设置不会在未发出新令牌的情况下更改。这种方法还可以在有效的共享访问签名令牌过期之前撤消。

详细内容请参阅在MSDN上引入表SAS(共享访问签名),队列SAS和更新BlobSAS和使用共享访问签名

以下代码显示如何创建有效时间为五分钟的共享访问签名令牌。 GetSharedAccessReferenceForUpload方法返回可用于将文件上传到Azure Blob存储的共享访问签名标记。

public class ValuesController : ApiController
{
  private readonly CloudStorageAccount account;
  private readonly string blobContainer;
  ...
  /// <summary>
  /// Return a limited access key that allows the caller to upload a file
  /// to this specific destination for a defined period of time.
  /// </summary>
  private StorageEntitySas GetSharedAccessReferenceForUpload(string blobName)
  {
    var blobClient = this.account.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference(this.blobContainer);

    var blob = container.GetBlockBlobReference(blobName);

    var policy = new SharedAccessBlobPolicy
    {
      Permissions = SharedAccessBlobPermissions.Write,

      // Specify a start time five minutes earlier to allow for client clock skew.
      SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),

      // Specify a validity period of five minutes starting from now.
      SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5)
    };

    // Create the signature.
    var sas = blob.GetSharedAccessSignature(policy);

    return new StorageEntitySas
    {
      BlobUri = blob.Uri,
      Credentials = sas,
      Name = blobName
    };
  }

  public struct StorageEntitySas
  {
    public string Credentials;
    public Uri BlobUri;
    public string Name;
  }
}

ValetKey解决方案的完整的示例可从GitHubhttps://github.com/mspnp/cloud-design-patterns/tree/master/valet-key下载 此解决方案中的ValetKey.Web项目包含上面显示的ValuesController类的Web应用程序。 使用此Web应用程序检索共享访问签名密钥并将文件上传到Blob存储的样本客户端应用程序可在ValetKey.Client项目中找到。

相关的模式和指南

以下模式和指南在实施这种模式时可能是相关的:

results matching ""

    No results matching ""