Update Nginx rules

Prevent disclosure of secure assets
This commit is contained in:
Damian Mooyman 2016-01-13 18:17:45 +13:00
parent 037467beae
commit 738e1db756
5 changed files with 55 additions and 14 deletions

View File

@ -37,6 +37,9 @@ But enough of the disclaimer, on to the actual configuration — typically in `n
error_page 500 /assets/error-500.html;
location ^~ /assets/ {
location ~ /\. {
deny all;
}
sendfile on;
try_files $uri /framework/main.php?url=$uri&$query_string;
}

View File

@ -27,8 +27,8 @@ config option:
## User access control
Access for files is granted on a per-session basis, rather than on a per-member basis, via a
whitelist action. This means that access to any protected asset must be made prior to the user
Access for files is granted on a per-session basis, rather than on a per-member basis, via
whitelisting accessed assets. This means that access to any protected asset must be made prior to the user
actually attempting to download that asset. This is normally done in the PHP request that generated
the response containing the link to that file.

View File

@ -5,12 +5,13 @@ namespace SilverStripe\Filesystem\Flysystem;
use Config;
use Generator;
use Injector;
use League\Flysystem\Directory;
use Session;
use Flushable;
use InvalidArgumentException;
use League\Flysystem\Directory;
use League\Flysystem\Exception;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\Util;
use SilverStripe\Filesystem\Storage\AssetNameGenerator;
use SilverStripe\Filesystem\Storage\AssetStore;
@ -61,6 +62,24 @@ class FlysystemAssetStore implements AssetStore, AssetStoreRouter, Flushable {
*/
private static $keep_empty_dirs = false;
/**
* Set HTTP error code for requests to secure denied assets.
* Note that this defaults to 404 to prevent information disclosure
* of secure files
*
* @config
* @var int
*/
private static $denied_response_code = 404;
/**
* Set HTTP error code to use for missing secure assets
*
* @config
* @var int
*/
private static $missing_response_code = 404;
/**
* Custom headers to add to all custom file responses
*
@ -401,7 +420,7 @@ class FlysystemAssetStore implements AssetStore, AssetStoreRouter, Flushable {
// Since permissions are applied to the non-variant only,
// map back to the original file before checking
$originalID = $this->removeVariant($fileID);
$granted = Session::get('AssetStore_Grants') ?: array();
$granted = Session::get(self::GRANTS_SESSION) ?: array();
return !empty($granted[$originalID]);
}
@ -758,7 +777,7 @@ class FlysystemAssetStore implements AssetStore, AssetStoreRouter, Flushable {
// Check if file exists
$filesystem = $this->getFilesystemFor($asset);
if(!$filesystem) {
return $this->createInvalidResponse();
return $this->createMissingResponse();
}
// Block directory access
@ -777,11 +796,11 @@ class FlysystemAssetStore implements AssetStore, AssetStoreRouter, Flushable {
/**
* Generate an {@see SS_HTTPResponse} for the given file from the source filesystem
* @param Filesystem $flysystem
* @param FilesystemInterface $flysystem
* @param string $fileID
* @return SS_HTTPResponse
*/
protected function createResponseFor(Filesystem $flysystem, $fileID) {
protected function createResponseFor(FilesystemInterface $flysystem, $fileID) {
// Build response body
// @todo: gzip / buffer response?
$body = $flysystem->read($fileID);
@ -798,22 +817,33 @@ class FlysystemAssetStore implements AssetStore, AssetStoreRouter, Flushable {
}
/**
* Generate a 403 response for the given file
* Generate a response for requests to a denied protected file
*
* @return SS_HTTPResponse
*/
protected function createDeniedResponse() {
$response = new SS_HTTPResponse(null, 403);
return $response;
$code = (int)Config::inst()->get(get_class($this), 'denied_response_code');
return $this->createErrorResponse($code);
}
/**
* Generate 404 response for missing file requests
* Generate a response for missing file requests
*
* @return SS_HTTPResponse
*/
protected function createInvalidResponse() {
$response = new SS_HTTPResponse('', 404);
protected function createMissingResponse() {
$code = (int)Config::inst()->get(get_class($this), 'missing_response_code');
return $this->createErrorResponse($code);
}
/**
* Create a response with the given error code
*
* @param int $code
* @return SS_HTTPResponse
*/
protected function createErrorResponse($code) {
$response = new SS_HTTPResponse('', $code);
// Show message in dev
if(!\Director::isLive()) {

View File

@ -511,6 +511,14 @@ class AssetStoreTest extends SapphireTest {
*/
class AssetStoreTest_SpyStore extends FlysystemAssetStore {
/**
* Enable disclosure of secure assets
*
* @config
* @var int
*/
private static $denied_response_code = 403;
/**
* Set to true|false to override all isSeekableStream calls
*

View File

@ -75,7 +75,7 @@ class ProtectedFileControllerTest extends FunctionalTest {
/**
* Test that certain requests are denied
*/
public function testRequestDenied() {
public function testInvalidRequest() {
$result = $this->get('assets/.protected/file.jpg');
$this->assertResponseEquals(400, null, $result);
}