3333use Symfony \Component \DependencyInjection \ContainerInterface ;
3434use Symfony \Component \HttpFoundation \Cookie ;
3535use Symfony \Component \HttpFoundation \Request ;
36- use Symfony \Component \HttpFoundation \Response ;
3736
3837class CSRFTokenValidator implements SubscriberInterface
3938{
40- public const CSRF_SESSION_KEY = '__csrf_token- ' ;
39+ public const CSRF_KEY = '__csrf_token- ' ;
4140
4241 public const CSRF_TOKEN_ARGUMENT = '__csrf_token ' ;
4342
4443 public const CSRF_TOKEN_HEADER = 'X-CSRF-Token ' ;
4544
45+ private const CSRF_WAS_VALIDATED = 'isValidated ' ;
46+
4647 /**
4748 * @var ContainerInterface
4849 */
@@ -140,16 +141,13 @@ public function checkFrontendTokenValidation(Enlight_Event_EventArgs $args)
140141 /** @var Enlight_Controller_Action $controller */
141142 $ controller = $ args ->getSubject ();
142143 $ request = $ controller ->Request ();
143- $ response = $ controller ->Response ();
144144
145145 // do not check internal sub-requests or validated requests
146- if ($ request ->getAttribute ('_isSubrequest ' ) || $ request ->getAttribute (' isValidated ' )) {
146+ if ($ request ->getAttribute ('_isSubrequest ' ) || $ request ->getAttribute (self :: CSRF_WAS_VALIDATED )) {
147147 return ;
148148 }
149149
150150 if ($ request ->isGet () && !$ this ->isProtected ($ controller )) {
151- $ this ->updateCsrfTokenIfNotAvailable ($ request , $ response );
152-
153151 return ;
154152 }
155153
@@ -162,76 +160,40 @@ public function checkFrontendTokenValidation(Enlight_Event_EventArgs $args)
162160 return ;
163161 }
164162
165- if (!$ this ->checkRequest ($ request , $ response )) {
166- $ this ->regenerateToken ($ request , $ response );
163+ if (!$ this ->checkRequest ($ request )) {
167164 throw new CSRFTokenValidationException (sprintf ('The provided X-CSRF-Token for path "%s" is invalid. Please go back, reload the page and try again. ' , $ request ->getRequestUri ()));
168165 }
169166
170167 // mark request as validated to avoid double validation
171- $ request ->setAttribute (' isValidated ' , true );
168+ $ request ->setAttribute (self :: CSRF_WAS_VALIDATED , true );
172169 }
173170
174- public function regenerateToken ( Request $ request , Response $ response ): string
171+ public function clearExistingCookie ( ): void
175172 {
176173 $ shop = $ this ->contextService ->getShopContext ()->getShop ();
177174 $ name = $ this ->getCsrfName ();
178175
179- $ token = Random::getAlphanumericString (30 );
180- $ this ->container ->get ('session ' )->set ($ name , $ token );
181-
182- $ response ->headers ->clearCookie ($ name );
183-
184- /*
185- * Appending a '/' to the $basePath is not strictly necessary, but it is
186- * done to all cookie base paths in the
187- * `themes/Frontend/Bare/frontend/index/index.tpl` template. It's done
188- * here as well for compatibility reasons.
189- */
190- $ response ->headers ->setCookie (new Cookie (
176+ $ front = $ this ->container ->get ('front ' );
177+ $ response = $ front ->Response ();
178+ $ response ->headers ->clearCookie (
191179 $ name ,
192- $ token ,
193- 0 ,
194180 sprintf ('%s/ ' , $ shop ->getPath () ?: '' ),
195- null ,
181+ '' ,
196182 $ shop ->getSecure (),
197183 false
198- ));
199-
200- return $ token ;
201- }
202-
203- private function updateCsrfTokenIfNotAvailable (Request $ request , Response $ response ): void
204- {
205- $ name = $ this ->getCsrfName ();
206-
207- if ($ this ->container ->get ('session ' )->has ($ name )) {
208- return ;
209- }
210-
211- $ this ->regenerateToken ($ request , $ response );
212- }
213-
214- private function getCsrfName (): string
215- {
216- $ shop = $ this ->contextService ->getShopContext ()->getShop ();
217-
218- $ name = self ::CSRF_SESSION_KEY . $ shop ->getId ();
219-
220- if ($ shop ->getParentId () && $ this ->componentsConfig ->get ('shareSessionBetweenLanguageShops ' )) {
221- $ name = self ::CSRF_SESSION_KEY . $ shop ->getParentId ();
222- }
223-
224- return $ name ;
184+ );
225185 }
226186
227187 /**
228- * Check if the submitted CSRF token in cookie or header matches with the token stored in the session
188+ * Check if the submitted CSRF token matches with the token stored in the cookie or header
189+ *
190+ * @return bool
229191 */
230- private function checkRequest (Request $ request, Response $ response ): bool
192+ private function checkRequest (Request $ request)
231193 {
232194 $ name = $ this ->getCsrfName ();
233195
234- $ token = $ this -> container -> get ( ' session ' ) ->get ($ name );
196+ $ token = $ request -> cookies ->get ($ name );
235197
236198 if (!\is_string ($ token )) {
237199 return false ;
@@ -246,6 +208,19 @@ private function checkRequest(Request $request, Response $response): bool
246208 return hash_equals ($ token , $ requestToken );
247209 }
248210
211+ private function getCsrfName (): string
212+ {
213+ $ shop = $ this ->contextService ->getShopContext ()->getShop ();
214+
215+ $ name = self ::CSRF_KEY . $ shop ->getId ();
216+
217+ if ($ shop ->getParentId () && $ this ->componentsConfig ->get ('shareSessionBetweenLanguageShops ' )) {
218+ $ name = self ::CSRF_KEY . $ shop ->getParentId ();
219+ }
220+
221+ return $ name ;
222+ }
223+
249224 /**
250225 * Check if the controller has opted in for CSRF whitelisting and if the
251226 * called action is on the whitelist
0 commit comments