使用 PHP/Apache 限制对静态文件(html、css、img 等)的访问
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2187200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using PHP/Apache to restrict access to static files (html, css, img, etc)
提问by Bart
Lets say you have lots of html, css, js, img and etc files within a directory on your server. Normally, any user in internet-land could access those files by simply typing in the full URL like so: http://example.com/static-files/sub/index.html
假设您的服务器上的目录中有很多 html、css、js、img 等文件。通常,互联网上的任何用户都可以通过简单地输入完整的 URL 来访问这些文件,如下所示:http: //example.com/static-files/sub/index.html
Now, what if you only want authorized users to be able to load those files? For this example, lets say your users log in first from a URL like this: http://example.com/login.php
现在,如果您只希望授权用户能够加载这些文件怎么办?在本例中,假设您的用户首先从这样的 URL 登录:http: //example.com/login.php
How would you allow the logged in user to view the index.html file (or any of the files under "static-files"), but restrict the file to everyone else?
您如何允许登录用户查看 index.html 文件(或“静态文件”下的任何文件),但将文件限制为其他人?
I have come up with two possible solutions thus far:
到目前为止,我提出了两种可能的解决方案:
Solution 1
Create the following .htaccess file under "static-files":
解决方案 1
在“静态文件”下创建以下 .htaccess 文件:
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^(.*)$ ../authorize.php?file= [NC]
And then in authorize.php...
然后在authorize.php ...
if (isLoggedInUser()) readfile('static-files/'.$_REQUEST['file']);
else echo 'denied';
This authorize.php file is grossly over simplified, but you get the idea.
这个 authorize.php 文件过于简化了,但你明白了。
Solution 2
Create the following .htaccess file under "static-files":
解决方案 2
在“静态文件”下创建以下 .htaccess 文件:
Order Deny,Allow
Deny from all
Allow from 000.000.000.000
And then my login page could append that .htaccess file with an IP for each user that logs in. Obviously this would also need to have some kind of cleanup routine to purge out old or no longer used IPs.
然后我的登录页面可以为每个登录的用户附加一个带有 IP 的 .htaccess 文件。显然,这也需要某种清理程序来清除旧的或不再使用的 IP。
我担心随着他们访问的用户和文件数量的增加,我的第一个解决方案在服务器上可能会变得非常昂贵。我认为我的第二个解决方案会便宜得多,但由于 IP 欺骗等原因也不太安全。我还担心如果有很多同时用户,将这些 IP 地址写入 htaccess 文件可能会成为应用程序的瓶颈。
Which of these solutions sounds better, and why? Alternatively, can you think of a completely different solution that would be better than either of these?
这些解决方案中哪一个听起来更好,为什么?或者,你能想出一个完全不同的解决方案,比这两者都更好吗?
采纳答案by Shane
I would consider using a PHP loader to handle authentication and then return the files you need. For example instead of doing <img src='picture.jpg' />Do something like <img src='load_image.php?image=picture.jpg' />.
我会考虑使用 PHP 加载程序来处理身份验证,然后返回您需要的文件。例如,而不是做<img src='picture.jpg' />类似的事情<img src='load_image.php?image=picture.jpg' />。
Your image loader can verify sessions, check credentials, etc. and then decide whether or not to return the requested file to the browser. This will allow you to store all of your secure files outside of the web accessible root so nobody is going to just WGET them or browse there 'accidentally'.
您的图像加载器可以验证会话、检查凭据等,然后决定是否将请求的文件返回给浏览器。这将允许您将所有安全文件存储在 Web 可访问的根目录之外,因此没有人会只是 WGET 它们或“意外”浏览那里。
Just remember to return the right headers in PHP and do something like readfile() in php and that will return the file contents to the browser.
只需记住在 PHP 中返回正确的标头并在 php 中执行类似 readfile() 的操作,这会将文件内容返回到浏览器。
I have used this very setup on several large scale secure website and it works like a charm.
我已经在几个大型安全网站上使用了这个设置,它的工作原理非常棒。
Edit: The system I am currently building uses this method to load Javascript, Images, and Video but CSS we aren't very worried with securing.
编辑:我目前正在构建的系统使用这种方法来加载 Javascript、图像和视频,但我们对安全性并不十分担心。
回答by DenisS
X-Sendfile
X-发送文件
There's a module for Apache (and other HTTP servers) which lets you tell the HTTP server to serve the file you specify in a header in your php code: So your php script should look like:
有一个用于 Apache(和其他 HTTP 服务器)的模块,它可以让您告诉 HTTP 服务器为您在 php 代码的标头中指定的文件提供服务: 所以您的 php 脚本应该如下所示:
// 1) Check access rights code
// 2) If OK, tell Apache to serve the file
header("X-Sendfile: $filename");
2 possible problems:
2个可能的问题:
- You need access to rewrite rules (.htaccess enabled or direct access to config files)
- You need mod_xsendfile module added to your Apache installed
- 您需要访问重写规则(启用 .htaccess 或直接访问配置文件)
- 您需要将 mod_xsendfile 模块添加到已安装的 Apache 中
Here's a good answer in another thread: https://stackoverflow.com/a/3731639/2088061
这是另一个线程中的一个很好的答案:https: //stackoverflow.com/a/3731639/2088061
回答by Pekka
I have been thinking a lot about the same issue. I am equally unhappy with the PHP engine running for every small resource that is served out. I asked a question in the same vein a few months ago here, though with a different focus.
我一直在思考同样的问题。我同样不满意 PHP 引擎为每个提供的小资源运行。几个月前,我在这里提出了同样的问题,但重点不同。
But I just had an awfullyinteresting idea that mightwork.
但我只是有一个非常有趣的想法可能会奏效。
Maintain a directory called
/sessionssomewhere on your web server.Whenever a user logs in, create an empty text file with the session ID in
/sessions. E.g.123456In your PHP app, serve out images like this:
/sessions/123456/images/test.jpgIn your htaccess file, have two redirect commands.
One that translates
/sessions/123456/images/test.jpginto/sessions/123456?filename=images/test.jpgA second one that catches any calls to
//sessions/(.*)and checks whether the specified file exists using the-fflag. If/sessions/123456doesn't exist, it means the user has logged out or their session has expired. In that case, Apache sends a 403 or redirects to an error page - the resource is no longer available.
/sessions在您的 Web 服务器上维护一个名为某处的目录。每当用户登录时,创建一个会话 ID 为
/sessions. 例如123456在您的 PHP 应用程序中,提供如下图像:
/sessions/123456/images/test.jpg在您的 htaccess 文件中,有两个重定向命令。
一个翻译
/sessions/123456/images/test.jpg成/sessions/123456?filename=images/test.jpg第二个捕获任何调用
//sessions/(.*)并使用-f标志检查指定文件是否存在。如果/sessions/123456不存在,则表示用户已注销或他们的会话已过期。在这种情况下,Apache 会发送 403 或重定向到错误页面 - 资源不再可用。
That way, we have quasi-session authentication in mod_rewrite doing just one "file exists" check!
这样,我们在 mod_rewrite 中有准会话身份验证,只需进行一次“文件存在”检查!
I don't have enough routine to build the mod_rewrite statements on the fly, but they should be easy enough to write. (I'm looking hopefully in your direction @Gumbo :)
我没有足够的例程来即时构建 mod_rewrite 语句,但它们应该很容易编写。(我期待着你的方向@Gumbo :)
Notes and caveats:
注意事项和注意事项:
Expired session files would have to be deleted quickly using a cron job, unless it's possible to check for a file's mtime in .htaccess (which may well be possible).
The image / resource is available to any clientas long as the session exists, so no 100% protection. You could maybe work around this by adding the client IP into the equation (= the file name you create) and do an additional check for %{REMOTE_ADDR}. This is advanced .htaccess mastery but I'm quite sure it's doable.
Resource URLs are not static, and have to be retrieved every time on log-in, so no caching.
必须使用 cron 作业快速删除过期的会话文件,除非可以在 .htaccess 中检查文件的 mtime(这很有可能)。
只要会话存在,任何客户端都可以使用图像/资源,因此没有 100% 的保护。您可以通过将客户端 IP 添加到等式(= 您创建的文件名)并额外检查 %{REMOTE_ADDR} 来解决此问题。这是高级 .htaccess 精通,但我很确定它是可行的。
资源 URL 不是静态的,每次登录时都必须检索,因此没有缓存。
I'm veryinterested in feedback on this, any shortfalls or impossibilities I may have overlooked, and any successful implementations (I don't have the time right now to set up a test myself).
我对对此的反馈非常感兴趣,我可能忽略的任何不足或不可能的地方,以及任何成功的实现(我现在没有时间自己设置测试)。
回答by Ignacio Vazquez-Abrams
Create a rewrite mapthat verifies the user's credentials and either redirects them to the appropriate resource or to an "access denied" page.
创建一个重写映射来验证用户的凭据并将它们重定向到适当的资源或“访问被拒绝”页面。
回答by symcbean
Maintaining the contents of the htaccess files looks to be a nightmare. Also, your stated objective is to prevent non-authenticated usersnot non-authenticated client ip addressesfrom accessing this content - so the approach is not fit for purpose:
维护 htaccess 文件的内容看起来是一场噩梦。此外,您声明的目标是防止未经身份验证的用户而不是未经身份验证的客户端 IP 地址访问此内容 - 因此该方法不适合目的:
Multiple users can appear to come from the same IP address
多个用户可能看起来来自同一个 IP 地址
A single users session may appear to come from multiple addresses.
单个用户会话可能看起来来自多个地址。
I worry that my first solution could get pretty expensive on the server as the number of users and files they are accessing increases
我担心随着他们访问的用户和文件数量的增加,我的第一个解决方案在服务器上可能会变得非常昂贵
If you want to prevent your content from leaching and don't want to use HTTP authenitcation then wrapping all file access in an additional layer of logic is the only sensible choice. Also, you don't know that using PHP for this isa problem - have you tested it? I think you'd be surprised just how much throughput it could deliver, particularly if you use an opcode cache.
如果您想防止您的内容泄露并且不想使用 HTTP 身份验证,那么将所有文件访问权限包装在额外的逻辑层中是唯一明智的选择。另外,您不知道为此使用 PHP是一个问题-您是否对其进行了测试?我想你会惊讶于它可以提供多少吞吐量,特别是如果你使用操作码缓存。
I'm guessing your 'simplification' of the wrapper addresses issues like mime type and caching.
我猜你对包装器的“简化”解决了 mime 类型和缓存等问题。
C.
C。
回答by GG.
I wrote a dynamic web application and deployed it on Webshere Application Server, and here is the way how I secured my static files :
我编写了一个动态 Web 应用程序并将其部署在 Webshere Application Server 上,这是我保护静态文件的方式:
I first added
我先加了
<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>
in web.xml which will tell your webserver to use form based authentication(code to use login is given below).
在 web.xml 中,它会告诉您的网络服务器使用基于表单的身份验证(下面给出了使用登录的代码)。
code to login page :
登录页面的代码:
<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>
To make form based login happen you have to configure your webserver to use a particular user registory which can be LDAP or database.
要进行基于表单的登录,您必须配置您的网络服务器以使用特定的用户注册表,该注册表可以是 LDAP 或数据库。
You can declare your secure resources and whenever a user tries to access those resources container automatically checks that whether user is authenticated or not. Even you can attach roles also with the secure resources. To do this I have added following code in my web.xml
您可以声明您的安全资源,每当用户尝试访问这些资源时,容器会自动检查用户是否已通过身份验证。即使您也可以使用安全资源附加角色。为此,我在 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>
So this code will not let user see any static file( since /*) until he is logged in under role role1 and role2. So by this way you can protect your resources.
所以这段代码不会让用户看到任何静态文件(因为/*),直到他以角色role1和role2登录。因此,通过这种方式,您可以保护您的资源。
回答by Hieu Phan
If you are using apache, you can configure, as below, in either .htaccess or httpd.conf file. Below is an example to prevent access to *.inc file. It greatly works for me.
如果您使用的是 apache,您可以在 .htaccess 或 httpd.conf 文件中进行如下配置。下面是一个防止访问 *.inc 文件的示例。它对我很有用。
<Files ~ "\.inc$">
Order allow,deny
Deny from all
</Files>
Please refer for more detail at: http://www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/.
有关更多详细信息,请参阅:http: //www.ducea.com/2006/07/21/apache-tips-tricks-deny-access-to-certain-file-types/。
回答by Andreas Dyballa
Assume you want to protect all your static filesand you have to server them from inside your webroot, you can protect all HTTP-Methods except HEAD. If you are authorized, you make a head request pass through the headers and send the filecontent as body. Sure this is expensive, but you are protected and you have the same behaviour.
假设您想保护所有静态文件,并且必须从webroot 内部为它们提供服务,您可以保护除 HEAD 之外的所有 HTTP 方法。如果您获得授权,您可以通过标头发送头部请求并将文件内容作为正文发送。当然这很昂贵,但是您受到保护并且您具有相同的行为。
回答by RafaSashi
I might have a suggestion based on iframeand HTTP_REFERERbut its not bullet proof and it will depend on what exactly you want to protect with this access.
我可能有一个建议,基于iframe和HTTP_REFERER,但它不是防弹,这将取决于你想要保护这个访问什么。
But in the case of preventing a full static page to be displayed without authentication you can do as follow:
但是在阻止在没有身份验证的情况下显示完整的静态页面的情况下,您可以执行以下操作:
1 - use a PHP page to authenticate the user
1 - 使用 PHP 页面来验证用户
2 - redirect to another PHP page containing a key in the URL and an iframe linking to your static content in the body:
2 - 重定向到另一个包含 URL 键和链接到正文中静态内容的 iframe 的 PHP 页面:
<iframe src="static/content.html" />
3 - Then in your htaccess you could check the key inside the HTTP_REFERER like that:
3 - 然后在您的 htaccess 中,您可以像这样检查 HTTP_REFERER 中的密钥:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !AUTH_KEY
RewriteCond %{REQUEST_URI} ^/path/to/protected/page$
RewriteRule . - [F]
4 - Finally if you want to make it more dynamic and not use the same KEY every time you could use rewrite mapas suggested by Ignacio Vazquez-Abrams' answer or create a file using the user IP as filename and check if file exists using REMOTE_ADDRthen remove the file after a while.
4 - 最后,如果你想让它更加动态并且每次你可以rewrite map按照 Ignacio Vazquez-Abrams 的回答的建议使用时不使用相同的 KEY,或者使用用户 IP 作为文件名创建一个文件并检查文件是否存在,REMOTE_ADDR然后删除一段时间后存档。
But keep in mind that iframe + HTTP_REFERER behavior might vary from one browser session to another as well as REMOTE_ADDR so its limited...
但请记住,iframe + HTTP_REFERER 行为可能因一个浏览器会话以及 REMOTE_ADDR 而异,因此其有限...

