Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/Engines/NodeJs.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
2 changes: 1 addition & 1 deletion src/Engines/Python.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
2 changes: 1 addition & 1 deletion src/Engines/Python3.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
67 changes: 67 additions & 0 deletions tests/Security/ScriptTokenEntropyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace DreamFactory\Core\Script\Tests\Security;

use PHPUnit\Framework\TestCase;

/**
* Verifies that script engine token generation uses cryptographically secure
* random_bytes() instead of the predictable uniqid().
*
* uniqid() is microtime-based (~20 bits of entropy), allowing token prediction.
* random_bytes(32) provides 256 bits of entropy.
*/
class ScriptTokenEntropyTest extends TestCase
{
/**
* @dataProvider engineClassProvider
*/
public function testEngineUsesRandomBytesNotUniqid(string $className): void
{
$reflection = new \ReflectionClass($className);
$source = file_get_contents($reflection->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],
];
}
}