Protecting files behind a firewall
Whenever you upload a file to your content folder and then access this file via its URL in the browser, a copy of the file is created in the media folder for public access. Additionally, the Panel creates thumbs for display in sections and fields or in the file view. This approach has several advantages, one of which is that you can move your content folder out of the web root for an additional layer of security.
However, if we want to restrict access to certain pages of a site as explained in our Restricting access to your site recipe, any files attached to these pages will still be accessible to anyone who can guess their URL.
In this recipe, we will create a simple downloads
page, where registered users can download files. The example will be based on Kirby's Starterkit.
Prerequisites
- A fresh Kirby Starterkit running on your local computer
- A code editor
- Apache web server (or other web server with a configuration that makes sure that requests to the content folder are sent to Kirby's router)
Preps
Downloads.yml
blueprint
For the new downloads page, we create a new page blueprint. It can have any content your like, but for our purposes, all we want is a files section:
All files we upload to this section get a template protected
assigned to it that we can later use to filter files or create conditions.
Now modify the pages
section in the site.yml
file so that it looks like this:
We add the downloads
template to the allowed templates and remove the existing create: default
option.
Now open the Panel and create a new page with the downloads
template (or create it manually in the file system if you prefer). Then upload some files (images and other) to this newly created page via the files section.
Make sure to upload the files via the Panel so that the protected
template is assigned to the files. If you just put some files into the downloads page manually, you would also have to manually add the metadata file with the template information.
downloads.php
template
We also want a downloads.php
template to list the uploaded files.
When you now visit this page in the frontend and inspect the file URLs in your browser's dev tools, you can see how these point to the media folder.
And if you click on the links while watching the media folder, you can see how it fills up with copies of those files.
Let's prevent that.
file::url
component
The first step to protecting the files in the downloads folder is a custom File::url
component.
In your /site/plugins/
folder (create this folder if it doesn't exist), create a new folder files-firewall
and add the obligatory index.php
file inside it.
In this index.php
file, add the component like this:
Inside the component we check the file's template, and if it has the protected
template assigned, we change the URL of the file to a location of our liking, otherwise we return the default mediaUrl()
.
If you delete the media folder now, and click on the file links again, you will see that this time no file copies will be generated anymore.
However, the files will still be accessible via their standard URL (in this case http://localhost/downloads/filename.ext
). A route to the rescue.
Route
Let's add a route to the plugin that sends users trying to access downloads/filename.ext
to the error page:
With this route in place—and if our web server is an Apache server using our default .htaccess
—our file is now fully protected, because a rewrite rule in our .htaccess
file prevents direct access to the /content
folder.
In other environments, where calls to files in the /content
folder are not routed through Kirby's router or where the original rules from the Starterkit's .htaccess
file have not been copied 1:1, files might still be accessible via their direct file path, e.g. http://localhost/content/downloads/myfile.pdf
. So make sure that your configure your server correctly.
If you now you click on a file link, the file will no longer be accessible to anyone, and we can start opening up our configuration to authorized users.
Allowing authorized users back in
We can now adapt our route so that logged-in users would be able to download the files, while all other visitors are sent to the error page:
Of course, instead of allowing access to logged-in users, your conditions here can be different. You could, for example, check if users send a specific token or if they are authorized in some other way.
Taking care of thumbs created via the Panel
The above already works very well for non-image files. However, the Panel automatically creates previews and thumbs of image files which will end up in the media folder despite our efforts from above.
The Kirby component responsible for thumbs is the File::version
component. Let's modify this component in our plugin:
Again we check the file template and return the original file if the file has the protected
template, otherwise return the original component with its options.
Complete index.php
To finish this up, here is the complete code again:
Conclusion
With a few lines of code, we were able to set up a basic files firewall where authorized users can download files while access to these file is prohibited for all other users.
As always, there are many ways to refine this basic setup with more sophisticated conditions or make it configurable via the Panel, but you now know where to start from. Happy coding!