From d6e548f2403bfe1704952ac37f12ad782cc36300 Mon Sep 17 00:00:00 2001 From: thekevinm Date: Fri, 23 Jan 2026 00:11:24 +0000 Subject: [PATCH 1/2] Add Overview section with platform description Added standard overview describing DreamFactory as a secure, self-hosted enterprise data access platform for enterprise apps and on-prem LLMs. Co-Authored-By: Claude Opus 4.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac58d1f..2014820 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Overview -DreamFactory(™) Script is a package built on top of the DreamFactory core, and as such retains the requirements of the [df-core](https://github.com/dreamfactorysoftware/df-core). +DreamFactory is a secure, self-hosted enterprise data access platform that provides governed API access to any data source, connecting enterprise applications and on-prem LLMs with role-based access and identity passthrough. ## Documentation From aa4d7cc8168b779d93a945d44551ce2b1a04348d Mon Sep 17 00:00:00 2001 From: nicdavidson Date: Fri, 10 Apr 2026 10:45:03 -0600 Subject: [PATCH 2/2] Security: replace uniqid() with random_bytes(32) for script auth tokens uniqid() is microtime-based with ~20 bits of entropy, making script tokens predictable. Replace with bin2hex(random_bytes(32)) for 256-bit cryptographically secure tokens in all three script engines. Add regression tests verifying source code uses random_bytes. --- src/Engines/NodeJs.php | 2 +- src/Engines/Python.php | 2 +- src/Engines/Python3.php | 2 +- tests/Security/ScriptTokenEntropyTest.php | 67 +++++++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 tests/Security/ScriptTokenEntropyTest.php diff --git a/src/Engines/NodeJs.php b/src/Engines/NodeJs.php index 32721a7..1f31252 100644 --- a/src/Engines/NodeJs.php +++ b/src/Engines/NodeJs.php @@ -67,7 +67,7 @@ protected function enrobeScript($script, array &$data = [], array $platform = [] if ((!empty($https) && ('off' != $https)) || (443 == Arr::get($_SERVER, 'SERVER_PORT'))) { $protocol = "https"; } - $token = uniqid(); + $token = bin2hex(random_bytes(32)); $apiKey = Arr::get($platform, 'session.api_key'); $sessionToken = Arr::get($platform, 'session.session_token'); $tokenCache = [ diff --git a/src/Engines/Python.php b/src/Engines/Python.php index 87bb8a5..acc495c 100644 --- a/src/Engines/Python.php +++ b/src/Engines/Python.php @@ -72,7 +72,7 @@ protected function enrobeScript($script, array &$data = [], array $platform = [] if ((!empty($https) && ('off' != $https)) || (443 == Arr::get($_SERVER, 'SERVER_PORT'))) { $protocol = 'https'; } - $token = uniqid(); + $token = bin2hex(random_bytes(32)); $apiKey = Arr::get($platform, 'session.api_key'); $sessionToken = Arr::get($platform, 'session.session_token'); $tokenCache = [ diff --git a/src/Engines/Python3.php b/src/Engines/Python3.php index 11f211b..af3d650 100644 --- a/src/Engines/Python3.php +++ b/src/Engines/Python3.php @@ -73,7 +73,7 @@ protected function enrobeScript($script, array &$data = [], array $platform = [] if ((!empty($https) && ('off' != $https)) || (443 == Arr::get($_SERVER, 'SERVER_PORT'))) { $protocol = 'https'; } - $token = uniqid(); + $token = bin2hex(random_bytes(32)); $tokenCache = [ 'app_id' => Arr::get($platform, 'session.app.id'), 'user_id' => Arr::get($platform, 'session.user.id') diff --git a/tests/Security/ScriptTokenEntropyTest.php b/tests/Security/ScriptTokenEntropyTest.php new file mode 100644 index 0000000..34560b5 --- /dev/null +++ b/tests/Security/ScriptTokenEntropyTest.php @@ -0,0 +1,67 @@ +getFileName()); + + $this->assertStringNotContainsString( + 'uniqid()', + $source, + "$className must not use uniqid() for token generation (insufficient entropy)" + ); + + $this->assertStringContainsString( + 'random_bytes', + $source, + "$className must use random_bytes() for cryptographically secure token generation" + ); + } + + /** + * Verify the token format: bin2hex(random_bytes(32)) produces a 64-char hex string. + */ + public function testTokenFormat(): void + { + $token = bin2hex(random_bytes(32)); + $this->assertEquals(64, strlen($token), 'Token should be 64 hex characters (256 bits)'); + $this->assertMatchesRegularExpression('/^[0-9a-f]{64}$/', $token); + } + + /** + * Verify uniqueness across 100 tokens (basic sanity check). + */ + public function testTokenUniqueness(): void + { + $tokens = []; + for ($i = 0; $i < 100; $i++) { + $tokens[] = bin2hex(random_bytes(32)); + } + $this->assertCount(100, array_unique($tokens), 'All 100 tokens should be unique'); + } + + public static function engineClassProvider(): array + { + return [ + 'NodeJs' => [\DreamFactory\Core\Script\Engines\NodeJs::class], + 'Python' => [\DreamFactory\Core\Script\Engines\Python::class], + 'Python3' => [\DreamFactory\Core\Script\Engines\Python3::class], + ]; + } +}