使用PHP / Apache来限制对静态文件(html,css,img等)的访问
比方说,你有很多的HTML,CSS,JS,IMG等文件在您的服务器上的目录。 通常,互联网用户可以通过input完整的URL来访问这些文件,例如http://example.com/static-files/sub/index.html
现在,如果您只希望授权用户能够加载这些文件呢? 对于这个例子,可以说你的用户首先从这样的URLlogin: http : //example.com/login.php
你将如何让login的用户查看index.html文件(或“静态文件”下的任何文件),但将文件限制在其他人?
到目前为止,我已经提出了两个可能的解决scheme:
解决scheme1
在“静态文件”下创build以下.htaccess文件:
Options +FollowSymLinks RewriteEngine on RewriteRule ^(.*)$ ../authorize.php?file=$1 [NC]
然后在authorize.php …
if (isLoggedInUser()) readfile('static-files/'.$_REQUEST['file']); else echo 'denied';
这个authorize.php文件非常简单,但你明白了。
解决scheme2
在“静态文件”下创build以下.htaccess文件:
Order Deny,Allow Deny from all Allow from 000.000.000.000
然后,我的login页面可以为每个login的用户附加.htaccess文件。显然,这也需要有一些清理例程来清除旧的或不再使用的IP。
我担心我的第一个解决scheme可能会在服务器上变得相当昂贵,因为他们正在访问的用户数量和文件数量会增加。 我认为我的第二个解决scheme将会更便宜,但是由于IP欺骗等原因,它也不太安全。我担心,如果同时存在许多用户,将这些IP地址写入htaccess文件可能会成为应用程序的瓶颈。
哪个解决scheme听起来更好,为什么? 另外,你能想到一个完全不同的解决scheme,比这两个都好吗?
我会考虑使用PHP加载器来处理身份validation,然后返回您需要的文件。 例如,而不是做<img src='picture.jpg' />
做一些像<img src='load_image.php?image=picture.jpg' />
。
您的图像加载器可以validation会话,检查凭证等,然后决定是否将所请求的文件返回给浏览器。 这将允许您将所有安全文件存储在Web可访问的根目录之外,因此没有人会仅仅将其设置为“打乱”或“偶然”浏览。
只要记得在PHP中返回正确的头文件,并在PHP中做一些像readfile(),并将文件内容返回到浏览器。
我已经在几个大型安全网站上使用了这个设置,它就像一个魅力。
编辑:我目前正在build设的系统使用这种方法来加载Javascript,图像和video,但CSS我们并不是非常担心的安全。
X-SENDFILE
有一个Apache的模块(和其他HTTP服务器),它可以让你告诉HTTP服务器在你的PHP代码中的头文件中指定的文件:所以你的PHP脚本应该是这样的:
// 1) Check access rights code // 2) If OK, tell Apache to serve the file header("X-Sendfile: $filename");
2个可能的问题:
- 您需要访问重写规则(启用.htaccess或直接访问configuration文件)
- 你需要将mod_xsendfile模块添加到你安装的Apache中
这是另一个线程中的一个很好的答案: https : //stackoverflow.com/a/3731639/2088061
我一直在思考同样的问题。 我同样对PHP引擎运行的每个小资源都感到不满。 几个月前,我在同一个问题上提出了一个问题,虽然重点不同。
但我只是有一个非常有趣的想法, 可能工作。
-
在Web服务器上维护一个名为
/sessions
的目录。 -
无论何时用户login,在
/sessions
创build一个带有会话ID的空文本文件。 例如123456
-
在你的PHP应用程序中,发布像这样的图像:
/sessions/123456http://img.dovov.comtest.jpg
-
在你的htaccess文件中,有两个redirect命令。
-
把
/sessions/123456http://img.dovov.comtest.jpg
翻译成/sessions/123456?filename=images/test.jpg
-
第二个捕获任何对
//sessions/(.*)
调用,并使用-f
标志检查指定的文件是否存在。 如果/sessions/123456
不存在,则意味着用户已经注销或者他们的会话已经过期。 在这种情况下,Apache发送403或redirect到错误页面 – 资源不再可用。
这样,我们在mod_rewrite中进行准会话authentication,只做一个“文件存在”检查!
我没有足够的例程来dynamic构buildmod_rewrite语句,但它们应该很容易编写。 (我正望着你的方向@Gumbo 🙂
注意和注意事项:
-
过期的会话文件必须使用cron作业快速删除,除非可以在.htaccess中检查文件的mtime(这很可能)。
-
只要会话存在, 任何客户端都可以使用映像/资源,因此不会有100%的保护。 您也许可以通过将客户端IP添加到公式中(=您创build的文件名)来解决此问题,并对%{REMOTE_ADDR}进行额外的检查。 这是先进的。htaccess掌握,但我相当确定这是可行的。
-
资源URL不是静态的,每次login时都必须检索,所以不需要caching。
我对这方面的反馈非常感兴趣,我可能忽略了任何不足或不可能的事情,以及任何成功的实现(我现在没有时间自己来设置testing)。
创build一个重写映射 ,validation用户的凭据,并将其redirect到适当的资源或“访问被拒绝”页面。
维护htaccess文件的内容看起来是一场噩梦。 此外,您所声明的目标是防止未经身份validation的用户而不是未经身份validation的客户端IP地址访问此内容 – 所以这种方法不适合用途:
多个用户可能看起来来自相同的IP地址
单个用户会话可能看起来来自多个地址。
我担心我的第一个解决scheme可能会在服务器上变得相当昂贵,因为他们访问的用户和文件数量会增加
如果你想阻止你的内容泄露,不想使用HTTPauthentication,那么将所有的文件访问包装在一个额外的逻辑层是唯一明智的select。 此外,你不知道使用PHP这是一个问题 – 你testing了吗? 我想你会惊讶它可以提供多less吞吐量,特别是如果你使用操作码caching。
我猜你的“简化”的包装解决了像MIMEtypes和caching问题。
C。
我写了一个dynamicWeb应用程序,并将其部署到Webshere Application Server上,这里是我如何保护我的静态文件:
我第一次补充说
<login-config id="LoginConfig_1"> <auth-method>FORM</auth-method> <realm-name>Form-Based Authentication</realm-name> <form-login-config> <form-login-page>/login.html</form-login-page> <form-error-page>/login_error.html</form-error-page> </form-login-config> </login-config>
在web.xml中,它会告诉你的web服务器使用基于表单的身份validation(下面给出使用login的代码)。
代码login页面:
<form id="form1" name="form1" method="post" action="j_security_check" style="padding: 0px 0px 0px 12px;"> Username: <label> <input name="j_username" type="text" class="font2" /> </label> <br /> <br /> Password: <span class="font2" > <label> <input name="j_password" type="password" class="font2" /> </label> </span> <br /> <br /> <label> <input type="submit" class="isc-login-button" name="Login" value="Login" /> </label> </form></td>
要使基于表单的login发生,您必须将您的Web服务器configuration为使用可以是LDAP或数据库的特定用户registry。
您可以声明安全资源,并且每当用户尝试访问这些资源时,容器都会自动检查用户是否经过身份validation。 即使您也可以将angular色附加到安全资源。 为此,我在web.xml中添加了以下代码
<security-constraint> <display-name>Authenticated</display-name> <web-resource-collection> <web-resource-name>/*</web-resource-name> <url-pattern>/*</url-pattern> <http-method>GET</http-method> <http-method>PUT</http-method> <http-method>HEAD</http-method> <http-method>TRACE</http-method> <http-method>POST</http-method> <http-method>DELETE</http-method> <http-method>OPTIONS</http-method> </web-resource-collection> <auth-constraint> <description>Auth Roles</description> <role-name>role1</role-name> <role-name>role2</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>role1</role-name> </security-role> <security-role> <role-name>role2</role-name> </security-role>
所以这段代码不会让用户看到任何静态文件(因为/ *),直到他在angular色role1和role2下login。 所以通过这种方式你可以保护你的资源。
如果您使用的是Apache,您可以在.htaccess或httpd.conf文件中configuration如下。 以下是防止访问* .inc文件的示例。 它非常适合我。
<Files ~ "\.inc$"> Order allow,deny Deny from all </Files>
请参考: http : //www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/ 。
假设你想保护所有的静态文件 ,你必须从你的webroot内部服务它们,你可以保护除HEAD之外的所有HTTP-Methods。 如果您已获得授权,您可以通过标头进行头部请求并将文件内容作为主体发送。 当然,这是昂贵的,但你是受保护的,你有相同的行为。
我可能有一个基于iframe
和HTTP_REFERER
的build议,但它不是防弹的,它取决于你想要用这个访问来保护什么。
但是在防止全部静态页面被显示而没有validation的情况下,您可以按如下方式进行:
1 – 使用PHP页面来authentication用户
2 – redirect到另一个包含URL中的关键字的PHP页面,以及一个链接到您的静态内容的iframe:
<iframe src="static/content.html" />
3 – 然后在你的htaccess中,你可以像这样检查HTTP_REFERER中的密钥:
RewriteEngine On RewriteCond %{HTTP_REFERER} !AUTH_KEY RewriteCond %{REQUEST_URI} ^/path/to/protected/page$ RewriteRule . - [F]
4 – 最后,如果您希望使其更具dynamic性,并且每次使用Ignacio Vazquez-Abrams的答案build议的rewrite map
都不要使用相同的KEY,或者使用用户IP作为文件名创build文件,并使用REMOTE_ADDR
检查文件是否存在然后在一段时间后删除文件。
但请记住,iframe + HTTP_REFERER行为可能会有所不同,从一个浏览器会话到另一个以及REMOTE_ADDR,因此它的有限…