1 file.test public FileUploadSvgTestCase::testSVGFileUploadValidation()

Test SVG upload validation.

File

core/modules/file/tests/file.test, line 3040
Tests for file.module.

Class

FileUploadSvgTestCase
Tests validation of SVG uploads.

Code

public function testSVGFileUploadValidation() {
  $default_content = '<rect width="400" height="400" fill="#93a7ac"/>';
  $default_open_tag = '<svg width="400" height="400" version="1.1" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">';
  // cspell:disable-next-line
  $a_tag_svg_href_content = '%3Csvg+xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22+onload%3D%22alert%281%29%22%3E%3C%2Fsvg%3E';

  $samples = array(
    'valid' => array(
      'contents' => $default_open_tag . $default_content . '</svg>',
      'message' => 'was uploaded.',
    ),
    'no_dimensions' => array(
      'contents' => '<svg version="1.1" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">' . $default_content . '</svg>',
      'message' => 'was uploaded.',
    ),
    'no_namespace_script' => array(
      'contents' => '<svg><script>alert(1)</script>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Invalid SVG namespace.',
    ),
    'invalid_namespace' => array(
      'contents' => $default_open_tag . '<g xmlns="invalid ns"/>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Invalid SVG file.',
    ),
    'broken' => array(
      'contents' => $default_open_tag . '<g>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Invalid SVG file.',
    ),
    'not_svg' => array(
      'contents' => '<xml><foobar/></xml>',
      'message' => 'could not be uploaded. Invalid SVG namespace.',
    ),
    'onevent' => array(
      'contents' => $default_open_tag . '<rect width="400" height="400" onload="alert(1)" fill="#93a7ac"/></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'iframe' => array(
      'contents' => $default_open_tag . $default_content . '<foreignObject x="20" y="20" width="220" height="220"><iframe src="https://example.org/" width="220" height="220"></iframe></foreignObject></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'script' => array(
      'contents' => $default_open_tag . $default_content . '<script>alert(1)</script></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xlink_script' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a xlink:href="javascript:alert(1)">test</a>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'link_data' => array(
      'contents' => $default_open_tag . $default_content . '<a href="data:image/svg+xml,' . $a_tag_svg_href_content . '"></a></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'link_safe' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a href="https://example.com/?a=1&amp;b=2"><text>test</text></a><a xlink:href="#test">test</a>' . $default_content . '</svg>',
      'message' => 'was uploaded.',
    ),
    'cdata_style' => array(
      'contents' => $default_open_tag . '<style><![CDATA[ rect { fill: #93a7ac; } ]]></style>' . $default_content . '</svg>',
      'message' => 'was uploaded.',
    ),
    'embedded_image' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image xlink:href="data:image/png;base64,iVBORw0KGgo=" width="1" height="1"/></svg>',
      'message' => 'was uploaded.',
    ),
    'link_whitespace_script' => array(
      'contents' => $default_open_tag . $default_content . '<a href="jav&#x09;ascript:alert(1)"><text>test</text></a></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xlink_nested_namespace_script' => array(
      'contents' => $default_open_tag . $default_content . '<a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="javascript:alert(1)"><text>test</text></a></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xlink_prefix_script' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:foo="http://www.w3.org/1999/xlink"><a foo:href="javascript:alert(1)"><text>test</text></a>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'encoded_comment_script' => array(
      'contents' => $default_open_tag . $default_content . '<text>&lt;!--</text><script>alert(1)</script><text>--&gt;</text></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'animate_script' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><a id="test" xlink:href="#"><text>test</text></a><animate xlink:href="#test" attributeName="href" values="javascript:alert(1)" begin="0s"/>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'animate_child_script' => array(
      'contents' => $default_open_tag . '<a><animate attributeName="href" dur="10s" begin="0s" fill="freeze" values="javascript:alert(1)"/>' . $default_content . '</a></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'set_script' => array(
      'contents' => $default_open_tag . '<a><set attributeName="href" begin="0s" to="javascript:alert(1)"/>' . $default_content . '</a></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xhtml_namespace_script' => array(
      'contents' => '<?xml version="1.0"?>' . $default_open_tag . '<script xmlns="http://www.w3.org/1999/xhtml">alert(1)</script>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'animate_transform' => array(
      'contents' => $default_open_tag . $default_content . '<animateTransform attributeName="transform" type="rotate" from="0" to="360"/></svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'comments_metadata' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><!-- Generator: Test --><title>Test</title><desc>A test image</desc><metadata><rdf:RDF><rdf:Description><dc:title><rdf:Alt><rdf:li>Test</rdf:li></rdf:Alt></dc:title></rdf:Description></rdf:RDF></metadata>' . $default_content . '</svg>',
      'message' => 'was uploaded.',
    ),
    'processing_instruction' => array(
      'contents' => $default_open_tag . '<?x ><img src onerror=alert(1)><?x?>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'abrupt_comment' => array(
      'contents' => $default_open_tag . '<!--><img src=x onerror=alert(1)>-->' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'html_breakout' => array(
      'contents' => $default_open_tag . '<p/><style><![CDATA[</style><img src=x onerror=alert(1)>]]></style>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'desc_element' => array(
      'contents' => $default_open_tag . '<desc><style><![CDATA[</style><img src=x onerror=alert(1)>]]></style></desc>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'doctype_breakout' => array(
      'contents' => '<!DOCTYPE svg SYSTEM "><img src=x onerror=alert(1)>">' . $default_open_tag . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'title_cdata' => array(
      'contents' => $default_open_tag . '<title><![CDATA[</title><script>alert(1)</script>]]></title>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xml_events' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" id="test"><x xmlns="http://www.w3.org/2001/xml-events" event="load" observer="test" handler="#test"/>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'xinclude' => array(
      'contents' => '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xi="http://www.w3.org/2001/XInclude"><text><xi:include href="/etc/passwd" parse="text"/></text>' . $default_content . '</svg>',
      'message' => 'could not be uploaded. Dangerous content found.',
    ),
    'entity_script' => array(
      'contents' => '<!DOCTYPE svg [<!ENTITY a "javascript:">]>' . $default_open_tag . '<a href="&a;alert(1)"><text>test</text></a></svg>',
      'message' => 'could not be uploaded. Invalid SVG file.',
    ),
  );

  foreach ($samples as $sample => $settings) {
    $filename = $sample . '.svg';
    $filepath = $this->createSvgFile($settings + array('filepath' => $filename));

    // Upload an SVG file.
    $edit = array();
    $edit['files[upload][]'] = backdrop_realpath($filepath);
    $this->backdropPost('file/add', $edit, t('Next'));

    // Check that the file exists in the database.
    $fid = $this->getLastFileId();
    $file = file_load($fid);
    $this->assertTrue($file, t('SVG file found in database.'));

    // Check that the SVG file has been validated.
    $this->assertRaw(t('%name ' . $settings['message'], array('%name' => $filename)), t('File validated.'));
  }

}