diff --git a/src/DDTrace/Integrations/Filesystem/FilesystemIntegration.php b/src/DDTrace/Integrations/Filesystem/FilesystemIntegration.php index 528cc894c2..2f3365f0a3 100644 --- a/src/DDTrace/Integrations/Filesystem/FilesystemIntegration.php +++ b/src/DDTrace/Integrations/Filesystem/FilesystemIntegration.php @@ -51,20 +51,21 @@ public function init(): int private static function preHook($variant) { return static function (HookData $hook) use ($variant) { - if (count($hook->args) == 0 || !is_string($hook->args[0])) { - return; - } + if (count($hook->args) == 0 || !is_string($hook->args[0])) { + return; + } - $protocol = []; - if ( - preg_match('/^[a-z]+\:\/\//', $hook->args[0], $protocol) && - isset($protocol[0]) && - $protocol[0] !== 'file') - { - return; - } + $protocol = []; + $uri_parsed = preg_match('/^([a-z]+)\:\/\//', $hook->args[0], $protocol); + $protocol = isset($protocol[1]) ? $protocol[1]: ""; - \datadog\appsec\push_address("server.io.fs.file", $hook->args[0], true); + if (empty($protocol) || $protocol === 'file') { + \datadog\appsec\push_address("server.io.fs.file", $hook->args[0], true); + } + + if (in_array($variant, ['file_get_contents', 'fopen']) && (empty($protocol) || $protocol === 'http')) { + \datadog\appsec\push_address("server.io.net.url", $hook->args[0], true); + } }; } diff --git a/tests/Integrations/Filesystem/FilesystemTest.php b/tests/Integrations/Filesystem/FilesystemTest.php index ed7cbdcb96..bf84f6386a 100644 --- a/tests/Integrations/Filesystem/FilesystemTest.php +++ b/tests/Integrations/Filesystem/FilesystemTest.php @@ -15,14 +15,23 @@ protected static function getAppIndexScript() return __DIR__ . '/index.php'; } - protected function assertEvent(string $value, $traces) + protected static function getEnvs() + { + return array_merge(parent::getEnvs(), [ + 'DD_APPSEC_RASP_ENABLED' => true + ]); + } + + protected function assertEvent(string $value, $traces, $also_ssrf = false) { $events = AppsecStatus::getInstance()->getEvents(); - $this->assertEquals(1, count($events)); + $this->assertEquals($also_ssrf ? 2 : 1, count($events)); $this->assertEquals($value, $events[0]["server.io.fs.file"]); + if ($also_ssrf) { + $this->assertEquals($value, $events[1]["server.io.net.url"]); + } $this->assertEquals('push_address', $events[0]['eventName']); $this->assertTrue($events[0]['rasp']); - $this->assertGreaterThanOrEqual(0.0, $traces[0][0]['metrics']['_dd.appsec.rasp.duration_ext']); } public function testFileGetContents() @@ -32,7 +41,33 @@ public function testFileGetContents() TestCase::assertSame('OK', $response); }); - $this->assertEvent('./index.php', $traces); + $this->assertEvent('./index.php', $traces, true); + } + + public function testFileProtocol() + { + $file = __DIR__ . '/index.php'; + $traces = $this->tracesFromWebRequest(function () use ($file) { + $response = $this->call(GetSpec::create('Root', '/?function=fopen&path=file://'.$file)); + TestCase::assertSame('OK', $response); + }); + + $this->assertEvent('file://'. $file, $traces); + } + + public function testHttpProtocol() + { + $file = 'http://example.com'; + $traces = $this->tracesFromWebRequest(function () use ($file) { + $response = $this->call(GetSpec::create('Root', '/?function=fopen&path='.$file)); + TestCase::assertSame('OK', $response); + }); + + $events = AppsecStatus::getInstance()->getEvents(); + $this->assertEquals(1, count($events)); + $this->assertEquals($file, $events[0]["server.io.net.url"]); + $this->assertEquals('push_address', $events[0]['eventName']); + $this->assertTrue($events[0]['rasp']); } public function testFilePutContents() @@ -50,7 +85,7 @@ public function testFopen() $response = $this->call(GetSpec::create('Root', '/?function=fopen&path=./index.php')); TestCase::assertSame('OK', $response); }); - $this->assertEvent('./index.php', $traces); + $this->assertEvent('./index.php', $traces, true); } public function testReadFile()