‪TYPO3CMS  11.5
SecureHtmlRenderingTest.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
21 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
22 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
23 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\AbstractInstruction;
24 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
25 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
26 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalResponse;
27 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
28 
29 class ‪SecureHtmlRenderingTest extends FunctionalTestCase
30 {
32 
33  private const ‪TYPE_EMPTY_PARSEFUNCTSPATH = 'empty-parseFuncTSPath';
34  protected const ‪LANGUAGE_PRESETS = [
35  'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8', 'iso' => 'en', 'hrefLang' => 'en-US', 'direction' => ''],
36  ];
37 
39  'SC_OPTIONS' => [
40  'Core/TypoScript/TemplateService' => [
41  'runThroughTemplatesPostProcessing' => [
42  'FunctionalTest' => \TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Hook\TypoScriptInstructionModifier::class . '->apply',
43  ],
44  ],
45  ],
46  ];
47 
48  protected ‪$coreExtensionsToLoad = ['fluid_styled_content'];
49 
50  protected function ‪setUp(): void
51  {
52  parent::setUp();
53 
55  'acme-com',
56  $this->‪buildSiteConfiguration(1000, 'https://acme.com/'),
57  [$this->‪buildDefaultLanguageConfiguration('EN', 'https://acme.us/')]
58  );
59 
60  $this->withDatabaseSnapshot(function () {
61  $this->‪setUpDatabase();
62  });
63  }
64 
65  protected function ‪setUpDatabase(): void
66  {
67  $backendUser = $this->setUpBackendUserFromFixture(1);
69 
70  $scenarioFile = __DIR__ . '/Fixtures/SecureHtmlScenario.yaml';
71  $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
72  $writer = DataHandlerWriter::withBackendUser($backendUser);
73  $writer->invokeFactory($factory);
74  static::failIfArrayIsNotEmpty(
75  $writer->getErrors()
76  );
77 
78  $this->setUpFrontendRootPage(
79  1000,
80  [
81  'constants' => ['EXT:fluid_styled_content/Configuration/TypoScript/constants.typoscript'],
82  'setup' => ['EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript'],
83  ],
84  [
85  'title' => 'ACME Root',
86  ]
87  );
88  }
89 
91  {
92  return [
93  '#01' => [
94  '01: <script>alert(1)</script>',
95  '<p>01: &lt;script&gt;alert(1)&lt;/script&gt;</p>',
96  ],
97  '#02' => [
98  '02: <unknown a="a" b="b">value</unknown>',
99  '<p>02: &lt;unknown a="a" b="b"&gt;value&lt;/unknown&gt;</p>',
100  ],
101  '#03' => [
102  '03: <img img="img" alt="alt" onerror="alert(1)">',
103  '<p>03: <img alt="alt"></p>',
104  ],
105  '#04' => [
106  '04: <img src="img" alt="alt" onerror="alert(1)">',
107  '<p>04: <img src="img" alt="alt"></p>',
108  ],
109  '#05' => [
110  '05: <img/src="img"/onerror="alert(1)">',
111  '<p>05: <img src="img"></p>',
112  ],
113  '#06' => [
114  '06: <strong>Given that x < y and y > z...</strong>',
115  '<p>06: <strong>Given that x y and y &gt; z...</strong></p>',
116  ],
117  '#07' => [
118  '07: <a href="t3://page?uid=1000" target="_blank" rel="noreferrer" class="button" role="button" onmouseover="alert(1)">TYPO3</a>',
119  '<p>07: <a href="/" target="_blank" rel="noreferrer" class="button" role="button">TYPO3</a></p>',
120  ],
121  ];
122  }
123 
130  public function ‪customParseFuncAvoidCrossSiteScripting(string $payload, string $expectation): void
131  {
132  $instructions = [
134  ];
135  $response = $this->‪invokeFrontendRendering(...$instructions);
136  self::assertSame($expectation, (string)$response->getBody());
137  }
138 
139  public static function ‪htmlViewHelperAvoidsCrossSiteScriptingDataProvider(): array
140  {
141  return [
142  '#01 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
144  '01: <script>alert(1)</script>',
145  '01: <script>alert(1)</script>',
146  ],
147  '#03 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
149  '03: <img img="img" alt="alt" onerror="alert(1)">',
150  '03: <img img="img" alt="alt" onerror="alert(1)">',
151  ],
152  '#07 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
154  '07: <a href="t3://page?uid=1000" target="_blank" rel="noreferrer" class="button" role="button" onmouseover="alert(1)">TYPO3</a>',
155  // expected, with empty parseFunc configuration internal link URN is not resolved
156  '07: <a href="t3://page?uid=1000" target="_blank" rel="noreferrer" class="button" role="button" onmouseover="alert(1)">TYPO3</a>',
157  ],
158  '#08 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
160  '08: <meta whatever="whatever">',
161  '08: <meta whatever="whatever">',
162  ],
163  '#09 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
165  '09: <sdfield onmouseover="alert(1)">',
166  '09: <sdfield onmouseover="alert(1)">',
167  ],
168  '#10 ' . self::TYPE_EMPTY_PARSEFUNCTSPATH => [
170  '10: <meta itemprop="type" content="voice">',
171  '10: <meta itemprop="type" content="voice">',
172  ],
173  ];
174  }
175 
183  public function ‪htmlViewHelperAvoidsCrossSiteScripting(string $type, string $payload, string $expectation): void
184  {
185  $instructions = [
186  $this->‪createFluidTemplateContentObject($type, $payload),
187  ];
188  $response = $this->‪invokeFrontendRendering(...$instructions);
189  self::assertSame($expectation, trim((string)$response->getBody(), "\n"));
190  }
191 
196  private function ‪invokeFrontendRendering(AbstractInstruction ...$instructions): InternalResponse
197  {
198  $sourcePageId = 1100;
199 
200  $request = (new InternalRequest('https://acme.us/'))
201  ->withPageId($sourcePageId)
202  ->withInstructions(
203  [
205  ]
206  );
207 
208  if (count($instructions) > 0) {
209  $request = $this->‪applyInstructions($request, ...$instructions);
210  }
211 
212  return $this->executeFrontendSubRequest($request);
213  }
214 
215  private function ‪createDefaultInstruction(): TypoScriptInstruction
216  {
217  return (new TypoScriptInstruction(TemplateService::class))
218  ->withTypoScript([
219  'config.' => [
220  'no_cache' => 1,
221  'debug' => 0,
222  'admPanel' => 0,
223  'disableAllHeaderCode' => 1,
224  'sendCacheHeaders' => 0,
225  ],
226  'page' => 'PAGE',
227  'page.' => [
228  'typeNum' => 0,
229  ],
230  ]);
231  }
232 
233  private function ‪createTextContentObjectWithCustomParseFuncInstruction(string $value): TypoScriptInstruction
234  {
235  // basically considered "insecure setup"
236  // + no explicit htmlSanitize
237  // + no HTMLparser + HTMLparser.htmlSpecialChars
238  return (new TypoScriptInstruction(TemplateService::class))
239  ->withTypoScript([
240  'page.' => [
241  '10' => 'TEXT',
242  '10.' => [
243  'value' => $value,
244  'parseFunc.' => [
245  'allowTags' => 'a,img,sdfield',
246  'tags.' => [
247  'a' => 'TEXT',
248  'a.' => [
249  'current' => 1,
250  'typolink' => [
251  'parameter.' => [
252  'data' => 'parameters:href',
253  ],
254  'title.' => [
255  'data' => 'parameters:title',
256  ],
257  'ATagParams.' => [
258  'data' => 'parameters:allParams',
259  ],
260  ],
261  ],
262  ],
263  'nonTypoTagStdWrap.' => [
264  'encapsLines.' => [
265  'nonWrappedTag' => 'p',
266  ],
267  ],
268  ],
269  ],
270  ],
271  ]);
272  }
273 
274  private function ‪createFluidTemplateContentObject(string $type, string $payload): TypoScriptInstruction
275  {
276  return (new TypoScriptInstruction(TemplateService::class))
277  ->withTypoScript([
278  'page.' => [
279  '10' => 'FLUIDTEMPLATE',
280  '10.' => [
281  'file' => 'EXT:fluid_styled_content/Tests/Functional/Rendering/Fixtures/FluidTemplate.html',
282  'variables.' => [
283  'type' => 'TEXT',
284  'type.' => [
285  'value' => $type,
286  ],
287  'payload' => 'TEXT',
288  'payload.' => [
289  'value' => $payload,
290  ],
291  ],
292  ],
293  ],
294  ]);
295  }
296 }
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\TYPE_EMPTY_PARSEFUNCTSPATH
‪const TYPE_EMPTY_PARSEFUNCTSPATH
Definition: SecureHtmlRenderingTest.php:32
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\customParseFuncAvoidCrossSiteScripting
‪customParseFuncAvoidCrossSiteScripting(string $payload, string $expectation)
Definition: SecureHtmlRenderingTest.php:129
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait
Definition: SiteBasedTestTrait.php:36
‪TYPO3
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:58
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\invokeFrontendRendering
‪InternalResponse invokeFrontendRendering(AbstractInstruction ... $instructions)
Definition: SecureHtmlRenderingTest.php:195
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\htmlViewHelperAvoidsCrossSiteScripting
‪htmlViewHelperAvoidsCrossSiteScripting(string $type, string $payload, string $expectation)
Definition: SecureHtmlRenderingTest.php:182
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildDefaultLanguageConfiguration
‪array buildDefaultLanguageConfiguration(string $identifier, string $base)
Definition: SiteBasedTestTrait.php:126
‪TYPO3\CMS\Core\Core\Bootstrap\initializeLanguageObject
‪static initializeLanguageObject()
Definition: Bootstrap.php:598
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\htmlViewHelperAvoidsCrossSiteScriptingDataProvider
‪static htmlViewHelperAvoidsCrossSiteScriptingDataProvider()
Definition: SecureHtmlRenderingTest.php:138
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering
Definition: SecureHtmlRenderingTest.php:16
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\$coreExtensionsToLoad
‪$coreExtensionsToLoad
Definition: SecureHtmlRenderingTest.php:47
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:46
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\applyInstructions
‪InternalRequest applyInstructions(InternalRequest $request, AbstractInstruction ... $instructions)
Definition: SiteBasedTestTrait.php:254
‪TYPO3\CMS\Core\Core\Bootstrap
Definition: Bootstrap.php:70
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪array buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:111
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\$configurationToUseInTestInstance
‪$configurationToUseInTestInstance
Definition: SecureHtmlRenderingTest.php:37
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\LANGUAGE_PRESETS
‪const LANGUAGE_PRESETS
Definition: SecureHtmlRenderingTest.php:33
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\setUpDatabase
‪setUpDatabase()
Definition: SecureHtmlRenderingTest.php:64
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\createFluidTemplateContentObject
‪createFluidTemplateContentObject(string $type, string $payload)
Definition: SecureHtmlRenderingTest.php:273
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\createTextContentObjectWithCustomParseFuncInstruction
‪createTextContentObjectWithCustomParseFuncInstruction(string $value)
Definition: SecureHtmlRenderingTest.php:232
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\createDefaultInstruction
‪createDefaultInstruction()
Definition: SecureHtmlRenderingTest.php:214
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest
Definition: SecureHtmlRenderingTest.php:30
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\setUp
‪setUp()
Definition: SecureHtmlRenderingTest.php:49
‪TYPO3\CMS\FluidStyledContent\Tests\FunctionalDeprecated\Rendering\SecureHtmlRenderingTest\customParseFuncAvoidsCrossSiteScriptingDataProvider
‪customParseFuncAvoidsCrossSiteScriptingDataProvider()
Definition: SecureHtmlRenderingTest.php:89