wwwision / privateresources
一个允许保护持久资源免受未经授权访问的流程包
Requires
- guzzlehttp/psr7: ^1.6 || ^2.0
- neos/flow: ^7.0 || ^8.0 || ^9.0
README
这是一个允许保护持久资源免受未经授权访问的流程包。
默认情况下,Flow会将持久资源发布到网站根目录下的_Resources/Persistent
文件夹,使其对浏览器和其他客户端可用(除非使用不同的PublishingTarget
,见下文)。这意味着,即使是从受保护区域提供的服务器文件也会对知道该资源内部文件名的人开放。通常情况下这不是什么大问题,因为文件名是根据文件的实际内容的哈希值确定的 - 所以如果你知道哈希值,你很可能也知道文件内容。但在某些情况下,你需要对提供的服务器文件有更多控制或希望防止直接链接到文件被共享。在这些情况下,这个包可能会有所帮助。
它提供了一个新的资源发布目标,名为ProtectedResourceTarget
,与其它目标不同,在发布时不会将文件内容复制到公开目录(或CDN)。相反,它将返回一个签名URL,该URL仅对具有与当前用户相同权限的用户有效。这意味着,如果一个图像被渲染给认证用户,图像URL将仅对具有相同角色的用户解析,对其他用户将返回HTTP状态403 Forbidden
。
免责声明
使用此包,用户无法轻松共享受保护资源的URL,因为它们仅适用于具有相同角色的用户。然而,资源显然仍然可以被下载,并且用户可以以其他方式共享它们。此外,提供私有资源消耗更多时间和内存,因为每次点击都会触发PHP请求。结论:此包仅在极少数情况下有用 ;)
版本
下表提供了可用版本的概述。
注意:版本3.4.0与Flow < 6不兼容。
如何使用
- 将包安装到
Packages/Application/Wwwision.PrivateResources
(例如,通过composer require wwwision/privateresources
) - 进行配置(见下文)
- 完成
概念
此包提供了一个自定义的资源发布目标,该目标防止资源被发布到可访问的文件系统。相反,它将生成一个令牌链接,当请求该链接时,将调用一个HTTP中间件,该中间件再根据当前用户是否有权访问该资源来提供相应的资源。
配置
发布目标
首先,您需要在您的Settings.yaml
中激活ProtectedResourceTarget
。您可以选择创建一个新的资源集合
Neos: Flow: resource: collections: 'protectedResources': storage: 'defaultPersistentResourcesStorage' target: 'protectedResourcesTarget'
然后您可以通过将资源上传到“protectedResources”集合来使用此功能,例如使用Fluid和UploadViewHelper
<f:form.upload name="file" collection="protectedResources" />
如果您想为持久资源启用此功能的全局,只需覆盖现有“persistent”集合的目标即可
Neos: Flow: resource: collections: 'persistent': target: 'protectedResourcesTarget'
注意:服务受保护资源会对性能和内存消耗产生负面影响 - 只有在您确实想保护所有持久资源时,才全局激活此功能。
令牌有效期
默认情况下,令牌不会过期。您可以使用tokenLifetime
选项来更改它
Neos: Flow: resource: targets: 'protectedResourcesTarget': targetOptions: tokenLifetime: 86400
在此配置下,令牌将在86400秒(=一天)后过期。
注意:此选项仅适用于“白名单”令牌,这些令牌未绑定到角色或安全上下文哈希
注意:如果资源的发布被缓存,这可能会导致资源损坏(例如,如果您在Neos CMS中在具有比令牌有效期更长的缓存生命周期的节点类型中使用此功能)。
白名单角色
有时您想防止在特定角色认证的情况下保护资源。使用whitelistRoles
选项,您可以禁用对个别角色的令牌强制执行(令牌仍将被生成,但如果指定了其中之一的角色被认证,则不再进行验证)
Neos: Flow: resource: targets: 'protectedResourcesTarget': targetOptions: whitelistRoles: ['Your.Package:SomeRole']
默认情况下,Neos.Neos:Editor
角色被白名单,因此可以在Neos CMS中使用此包而不会出现缓存问题。
特权角色
如果没有激活任何白名单角色(见上文),令牌将绑定到Flow安全上下文。这意味着只有具有相同安全上下文哈希的请求才有权访问资源。安全上下文哈希绑定到当前认证的角色和全局AOP对象。
还可以配置一个始终可以访问给定资源目标所有资源的角色
Neos: Flow: resource: targets: 'protectedResourcesTarget': targetOptions: privilegedRole: 'Your.Package:SomeRole'
注意:使用此选项允许异步创建资源URL或通过CLI,因为它不需要初始化安全上下文
HTTP中间件
实际服务受保护文件使用的是HTTP中间件
,它将在常规路由之前被触发。此ProtectedResourceMiddleware
已经配置好,如果遇到带有“__protectedResource”参数的HTTP请求,它将验证哈希并输出请求的文件,如果有效。
默认情况下,它使用PHP的readfile()
函数从其不可访问的位置流式传输本地文件到客户端,但这有一些缺点,因为它必须将整个文件通过PHP进程传输,这会消耗大量内存,特别是对于大文件。
为了支持外部云存储,请使用以下部分中描述的StreamStrategy
。
为了提高性能和内存占用,您可以配置中间件使用不同的策略来服务文件
X-Sendfile (Apache)
mod_xsendfile是一个小的Apache2
模块,它处理由原始输出处理程序注册的X-SENDFILE头(见https://tn123.org/mod_xsendfile/)。
假设您已安装并配置Apache模块以访问安装的Data/Persistent/Resources
目录中的文件,您可以激活以下设置的XSendfileStrategy
Wwwision: PrivateResources: middleware: serveStrategy: 'Wwwision\PrivateResources\Http\FileServeStrategy\XSendfileStrategy'
然后,而不是使用readfile()
来服务文件,HTTP中间件将发送一个指向内部文件的X-Sendfile
头,让Apache处理下载。
X-Accel-Redirect (Nginx)
类似于X-Sendfile
机制,X-Accel-Redirect
允许在Nginx
环境中进行内部重定向到某个位置(见http://wiki.nginx.org/X-accel)。
它可以激活为:
Wwwision: PrivateResources: middleware: serveStrategy: 'Wwwision\PrivateResources\Http\FileServeStrategy\XAccelRedirectStrategy'
流
此策略使用ResourceManager提供的只读流。它应该与所有StorageInterfaces兼容,并支持外部存储(例如AWS S3、Google Cloud Storage GCS)。但这也存在一些缺点,因为它必须将整个文件通过PHP进程传输,消耗大量内存和CPU时间。
它可以激活为:
Wwwision: PrivateResources: middleware: serveStrategy: 'Wwwision\PrivateResources\Http\FileServeStrategy\StreamStrategy'
自定义策略
您可以为服务文件创建自己的策略,实现FileServeStrategyInterface
。通过这种方式,您可以例如实现受保护的CDN资源。
信号
HTTP中间件在访问受保护资源时触发信号(有关更多信息,请参阅Flow文档中的信号和槽)。您可以使用该信号来统计文件下载量。
use Neos\Flow\Core\Bootstrap; use Neos\Flow\ResourceManagement\PersistentResource; use Psr\Http\Message\ServerRequestInterface as HttpRequestInterface; use Wwwision\PrivateResources\Http\Middleware\ProtectedResourceMiddleware; final class Package extends \Neos\Flow\Package { public function boot(Bootstrap $bootstrap): void { $dispatcher = $bootstrap->getSignalSlotDispatcher(); $dispatcher->connect(ProtectedResourceMiddleware::class, 'resourceServed', function (PersistentResource $resource, HttpRequestInterface $httpRequest) { // increase counter for the given $resource }); } }
以下信号会被发出
ProtectedResourceMiddleware:resourceServed(PersistentResource $resource, HttpRequest $httpRequest)
当一个私有资源被服务时ProtectedResourceMiddleware:accessDenied(array $tokenData, HttpRequest $httpRequest)
以下信号仍然会发出以保持向后兼容,但已被accessDenied
取代
ProtectedResourceMiddleware:invalidSecurityContextHash(array $tokenData, HttpRequest $httpRequest)
Neos CMS
此包与Neos CMS配合良好,但Neos目前没有提供选择资源集合的方式,在上传文件或使用媒体模块时。但是,您可以全局激活受保护资源(见上文),或为受保护文件上传创建自定义编辑器。
身份验证
为了限制对Neos后端用户的访问,必须将请求模式与/__protectedResource?token=<token>
请求匹配,才能使Neos身份验证生效。从版本6.2开始,可以使用controllerObjectName
选项来模拟Neos控制器,例如
Neos: Flow: resource: targets: 'protectedResourcesTarget': targetOptions: # Limit access to Neos editors privilegedRole: 'Neos.Neos:Editor' Wwwision: PrivateResources: middleware: # Simulate the NodeController to be invoked such that the Neos authentication gets activated controllerObjectName: 'Neos\Neos\Controller\Frontend\NodeController'
注意:如果配置了更多请求模式类型,可能需要调整/删除这些模式。
已知问题和限制
- 私有资源目前仅适用于持久性资源。尚不支持静态资源。