3636use OC \AppFramework \Middleware \Security \Exceptions \StrictCookieMissingException ;
3737use OC \AppFramework \Utility \ControllerMethodReflector ;
3838use OC \Security \CSP \ContentSecurityPolicyManager ;
39+ use OC \Security \CSRF \CsrfTokenManager ;
3940use OCP \AppFramework \Http \ContentSecurityPolicy ;
4041use OCP \AppFramework \Http \EmptyContentSecurityPolicy ;
4142use OCP \AppFramework \Http \RedirectResponse ;
@@ -77,6 +78,8 @@ class SecurityMiddleware extends Middleware {
7778 private $ isAdminUser ;
7879 /** @var ContentSecurityPolicyManager */
7980 private $ contentSecurityPolicyManager ;
81+ /** @var CsrfTokenManager */
82+ private $ csrfTokenManager ;
8083
8184 /**
8285 * @param IRequest $request
@@ -88,6 +91,7 @@ class SecurityMiddleware extends Middleware {
8891 * @param bool $isLoggedIn
8992 * @param bool $isAdminUser
9093 * @param ContentSecurityPolicyManager $contentSecurityPolicyManager
94+ * @param CSRFTokenManager $csrfTokenManager
9195 */
9296 public function __construct (IRequest $ request ,
9397 ControllerMethodReflector $ reflector ,
@@ -97,7 +101,8 @@ public function __construct(IRequest $request,
97101 $ appName ,
98102 $ isLoggedIn ,
99103 $ isAdminUser ,
100- ContentSecurityPolicyManager $ contentSecurityPolicyManager ) {
104+ ContentSecurityPolicyManager $ contentSecurityPolicyManager ,
105+ CsrfTokenManager $ csrfTokenManager ) {
101106 $ this ->navigationManager = $ navigationManager ;
102107 $ this ->request = $ request ;
103108 $ this ->reflector = $ reflector ;
@@ -107,6 +112,7 @@ public function __construct(IRequest $request,
107112 $ this ->isLoggedIn = $ isLoggedIn ;
108113 $ this ->isAdminUser = $ isAdminUser ;
109114 $ this ->contentSecurityPolicyManager = $ contentSecurityPolicyManager ;
115+ $ this ->csrfTokenManager = $ csrfTokenManager ;
110116 }
111117
112118
@@ -171,6 +177,23 @@ public function beforeController($controller, $methodName) {
171177
172178 }
173179
180+ private function browserSupportsCspV3 () {
181+ $ browserWhitelist = [
182+ // Chrome 40+
183+ '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/ ' ,
184+ // Firefox 45+
185+ '/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/ ' ,
186+ // Safari 10+
187+ '/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/ ' ,
188+ ];
189+
190+ if ($ this ->request ->isUserAgent ($ browserWhitelist )) {
191+ return true ;
192+ }
193+
194+ return false ;
195+ }
196+
174197 /**
175198 * Performs the default CSP modifications that may be injected by other
176199 * applications
@@ -190,6 +213,10 @@ public function afterController($controller, $methodName, Response $response) {
190213 $ defaultPolicy = $ this ->contentSecurityPolicyManager ->getDefaultPolicy ();
191214 $ defaultPolicy = $ this ->contentSecurityPolicyManager ->mergePolicies ($ defaultPolicy , $ policy );
192215
216+ if ($ this ->browserSupportsCspV3 ()) {
217+ $ defaultPolicy ->useJsNonce ($ this ->csrfTokenManager ->getToken ()->getEncryptedValue ());
218+ }
219+
193220 $ response ->setContentSecurityPolicy ($ defaultPolicy );
194221
195222 return $ response ;
0 commit comments