Move browserSupportsCspV3 to CSPNonceManager
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
parent
d5589a15d5
commit
e351ba56f1
|
@ -380,7 +380,8 @@ class DIContainer extends SimpleContainer implements IAppContainer {
|
||||||
$app->isLoggedIn(),
|
$app->isLoggedIn(),
|
||||||
$app->isAdminUser(),
|
$app->isAdminUser(),
|
||||||
$app->getServer()->getContentSecurityPolicyManager(),
|
$app->getServer()->getContentSecurityPolicyManager(),
|
||||||
$app->getServer()->getCsrfTokenManager()
|
$app->getServer()->getCsrfTokenManager(),
|
||||||
|
$app->getServer()->getContentSecurityPolicyNonceManager()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
|
||||||
use OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException;
|
use OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException;
|
||||||
use OC\AppFramework\Utility\ControllerMethodReflector;
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OC\Security\CSP\ContentSecurityPolicyManager;
|
use OC\Security\CSP\ContentSecurityPolicyManager;
|
||||||
|
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
|
||||||
use OC\Security\CSRF\CsrfTokenManager;
|
use OC\Security\CSRF\CsrfTokenManager;
|
||||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
|
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
|
||||||
|
@ -80,6 +81,8 @@ class SecurityMiddleware extends Middleware {
|
||||||
private $contentSecurityPolicyManager;
|
private $contentSecurityPolicyManager;
|
||||||
/** @var CsrfTokenManager */
|
/** @var CsrfTokenManager */
|
||||||
private $csrfTokenManager;
|
private $csrfTokenManager;
|
||||||
|
/** @var ContentSecurityPolicyNonceManager */
|
||||||
|
private $cspNonceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
|
@ -92,6 +95,7 @@ class SecurityMiddleware extends Middleware {
|
||||||
* @param bool $isAdminUser
|
* @param bool $isAdminUser
|
||||||
* @param ContentSecurityPolicyManager $contentSecurityPolicyManager
|
* @param ContentSecurityPolicyManager $contentSecurityPolicyManager
|
||||||
* @param CSRFTokenManager $csrfTokenManager
|
* @param CSRFTokenManager $csrfTokenManager
|
||||||
|
* @param ContentSecurityPolicyNonceManager $cspNonceManager
|
||||||
*/
|
*/
|
||||||
public function __construct(IRequest $request,
|
public function __construct(IRequest $request,
|
||||||
ControllerMethodReflector $reflector,
|
ControllerMethodReflector $reflector,
|
||||||
|
@ -102,7 +106,8 @@ class SecurityMiddleware extends Middleware {
|
||||||
$isLoggedIn,
|
$isLoggedIn,
|
||||||
$isAdminUser,
|
$isAdminUser,
|
||||||
ContentSecurityPolicyManager $contentSecurityPolicyManager,
|
ContentSecurityPolicyManager $contentSecurityPolicyManager,
|
||||||
CsrfTokenManager $csrfTokenManager) {
|
CsrfTokenManager $csrfTokenManager,
|
||||||
|
ContentSecurityPolicyNonceManager $cspNonceManager) {
|
||||||
$this->navigationManager = $navigationManager;
|
$this->navigationManager = $navigationManager;
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
$this->reflector = $reflector;
|
$this->reflector = $reflector;
|
||||||
|
@ -113,6 +118,7 @@ class SecurityMiddleware extends Middleware {
|
||||||
$this->isAdminUser = $isAdminUser;
|
$this->isAdminUser = $isAdminUser;
|
||||||
$this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
|
$this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
|
||||||
$this->csrfTokenManager = $csrfTokenManager;
|
$this->csrfTokenManager = $csrfTokenManager;
|
||||||
|
$this->cspNonceManager = $cspNonceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,23 +183,6 @@ class SecurityMiddleware extends Middleware {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function browserSupportsCspV3() {
|
|
||||||
$browserWhitelist = [
|
|
||||||
// Chrome 40+
|
|
||||||
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/',
|
|
||||||
// Firefox 45+
|
|
||||||
'/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/',
|
|
||||||
// Safari 10+
|
|
||||||
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/',
|
|
||||||
];
|
|
||||||
|
|
||||||
if($this->request->isUserAgent($browserWhitelist)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the default CSP modifications that may be injected by other
|
* Performs the default CSP modifications that may be injected by other
|
||||||
* applications
|
* applications
|
||||||
|
@ -213,7 +202,7 @@ class SecurityMiddleware extends Middleware {
|
||||||
$defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
|
$defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
|
||||||
$defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);
|
$defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);
|
||||||
|
|
||||||
if($this->browserSupportsCspV3()) {
|
if($this->cspNonceManager->browserSupportsCspV3()) {
|
||||||
$defaultPolicy->useJsNonce($this->csrfTokenManager->getToken()->getEncryptedValue());
|
$defaultPolicy->useJsNonce($this->csrfTokenManager->getToken()->getEncryptedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
namespace OC\Security\CSP;
|
namespace OC\Security\CSP;
|
||||||
|
|
||||||
use OC\Security\CSRF\CsrfTokenManager;
|
use OC\Security\CSRF\CsrfTokenManager;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @package OC\Security\CSP
|
* @package OC\Security\CSP
|
||||||
|
@ -29,14 +30,19 @@ use OC\Security\CSRF\CsrfTokenManager;
|
||||||
class ContentSecurityPolicyNonceManager {
|
class ContentSecurityPolicyNonceManager {
|
||||||
/** @var CsrfTokenManager */
|
/** @var CsrfTokenManager */
|
||||||
private $csrfTokenManager;
|
private $csrfTokenManager;
|
||||||
|
/** @var IRequest */
|
||||||
|
private $request;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $nonce = '';
|
private $nonce = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CsrfTokenManager $csrfTokenManager
|
* @param CsrfTokenManager $csrfTokenManager
|
||||||
|
* @param IRequest $request
|
||||||
*/
|
*/
|
||||||
public function __construct(CsrfTokenManager $csrfTokenManager) {
|
public function __construct(CsrfTokenManager $csrfTokenManager,
|
||||||
|
IRequest $request) {
|
||||||
$this->csrfTokenManager = $csrfTokenManager;
|
$this->csrfTokenManager = $csrfTokenManager;
|
||||||
|
$this->request = $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,4 +57,25 @@ class ContentSecurityPolicyNonceManager {
|
||||||
|
|
||||||
return $this->nonce;
|
return $this->nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the browser supports CSP v3
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function browserSupportsCspV3() {
|
||||||
|
$browserWhitelist = [
|
||||||
|
// Chrome 40+
|
||||||
|
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/',
|
||||||
|
// Firefox 45+
|
||||||
|
'/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/',
|
||||||
|
// Safari 10+
|
||||||
|
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/',
|
||||||
|
];
|
||||||
|
|
||||||
|
if($this->request->isUserAgent($browserWhitelist)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -711,7 +711,8 @@ class Server extends ServerContainer implements IServerContainer {
|
||||||
});
|
});
|
||||||
$this->registerService('ContentSecurityPolicyNonceManager', function(Server $c) {
|
$this->registerService('ContentSecurityPolicyNonceManager', function(Server $c) {
|
||||||
return new ContentSecurityPolicyNonceManager(
|
return new ContentSecurityPolicyNonceManager(
|
||||||
$c->getCsrfTokenManager()
|
$c->getCsrfTokenManager(),
|
||||||
|
$c->getRequest()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
$this->registerService('ShareManager', function(Server $c) {
|
$this->registerService('ShareManager', function(Server $c) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware;
|
||||||
use OC\AppFramework\Utility\ControllerMethodReflector;
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OC\Security\CSP\ContentSecurityPolicy;
|
use OC\Security\CSP\ContentSecurityPolicy;
|
||||||
use OC\Security\CSP\ContentSecurityPolicyManager;
|
use OC\Security\CSP\ContentSecurityPolicyManager;
|
||||||
|
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
|
||||||
use OC\Security\CSRF\CsrfToken;
|
use OC\Security\CSRF\CsrfToken;
|
||||||
use OC\Security\CSRF\CsrfTokenManager;
|
use OC\Security\CSRF\CsrfTokenManager;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
@ -76,6 +77,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
|
||||||
private $contentSecurityPolicyManager;
|
private $contentSecurityPolicyManager;
|
||||||
/** @var CsrfTokenManager|\PHPUnit_Framework_MockObject_MockObject */
|
/** @var CsrfTokenManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
private $csrfTokenManager;
|
private $csrfTokenManager;
|
||||||
|
/** @var ContentSecurityPolicyNonceManager|\PHPUnit_Framework_MockObject_MockObject */
|
||||||
|
private $cspNonceManager;
|
||||||
|
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
@ -88,6 +91,7 @@ class SecurityMiddlewareTest extends \Test\TestCase {
|
||||||
$this->request = $this->createMock(IRequest::class);
|
$this->request = $this->createMock(IRequest::class);
|
||||||
$this->contentSecurityPolicyManager = $this->createMock(ContentSecurityPolicyManager::class);
|
$this->contentSecurityPolicyManager = $this->createMock(ContentSecurityPolicyManager::class);
|
||||||
$this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
|
$this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
|
||||||
|
$this->cspNonceManager = $this->createMock(ContentSecurityPolicyNonceManager::class);
|
||||||
$this->middleware = $this->getMiddleware(true, true);
|
$this->middleware = $this->getMiddleware(true, true);
|
||||||
$this->secException = new SecurityException('hey', false);
|
$this->secException = new SecurityException('hey', false);
|
||||||
$this->secAjaxException = new SecurityException('hey', true);
|
$this->secAjaxException = new SecurityException('hey', true);
|
||||||
|
@ -109,7 +113,8 @@ class SecurityMiddlewareTest extends \Test\TestCase {
|
||||||
$isLoggedIn,
|
$isLoggedIn,
|
||||||
$isAdminUser,
|
$isAdminUser,
|
||||||
$this->contentSecurityPolicyManager,
|
$this->contentSecurityPolicyManager,
|
||||||
$this->csrfTokenManager
|
$this->csrfTokenManager,
|
||||||
|
$this->cspNonceManager
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,9 +564,9 @@ class SecurityMiddlewareTest extends \Test\TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAfterController() {
|
public function testAfterController() {
|
||||||
$this->request
|
$this->cspNonceManager
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('isUserAgent')
|
->method('browserSupportsCspV3')
|
||||||
->willReturn(false);
|
->willReturn(false);
|
||||||
$response = $this->createMock(Response::class);
|
$response = $this->createMock(Response::class);
|
||||||
$defaultPolicy = new ContentSecurityPolicy();
|
$defaultPolicy = new ContentSecurityPolicy();
|
||||||
|
@ -603,9 +608,9 @@ class SecurityMiddlewareTest extends \Test\TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAfterControllerWithContentSecurityPolicy3Support() {
|
public function testAfterControllerWithContentSecurityPolicy3Support() {
|
||||||
$this->request
|
$this->cspNonceManager
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('isUserAgent')
|
->method('browserSupportsCspV3')
|
||||||
->willReturn(true);
|
->willReturn(true);
|
||||||
$token = $this->createMock(CsrfToken::class);
|
$token = $this->createMock(CsrfToken::class);
|
||||||
$token
|
$token
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace Test\Security\CSP;
|
||||||
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
|
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
|
||||||
use OC\Security\CSRF\CsrfToken;
|
use OC\Security\CSRF\CsrfToken;
|
||||||
use OC\Security\CSRF\CsrfTokenManager;
|
use OC\Security\CSRF\CsrfTokenManager;
|
||||||
|
use OCP\IRequest;
|
||||||
use Test\TestCase;
|
use Test\TestCase;
|
||||||
|
|
||||||
class ContentSecurityPolicyNonceManagerTest extends TestCase {
|
class ContentSecurityPolicyNonceManagerTest extends TestCase {
|
||||||
|
@ -35,7 +36,8 @@ class ContentSecurityPolicyNonceManagerTest extends TestCase {
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
|
$this->csrfTokenManager = $this->createMock(CsrfTokenManager::class);
|
||||||
$this->nonceManager = new ContentSecurityPolicyNonceManager(
|
$this->nonceManager = new ContentSecurityPolicyNonceManager(
|
||||||
$this->csrfTokenManager
|
$this->csrfTokenManager,
|
||||||
|
$this->createMock(IRequest::class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue