Fix broken foreign key links

Fixes: #14270 - Middle-click on foreign key link broken
Fixes: #14363 - Broken relational links in tables
Pull-request: #15325

Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
William Desportes 2019-06-22 11:39:58 +02:00
commit d2caddf5e9
No known key found for this signature in database
GPG Key ID: 90A0EF1B8251A889
7 changed files with 152 additions and 7 deletions

View File

@ -1289,4 +1289,32 @@ class Core
self::fatalError(__('possible exploit'));
}
}
/**
* Sign the sql query using hmac using the session token
*
* @param string $sqlQuery The sql query
* @return void
*/
public static function signSqlQuery($sqlQuery)
{
/** @var array $cfg */
global $cfg;
return hash_hmac('sha256', $sqlQuery, $_SESSION[' HMAC_secret '] . $cfg['blowfish_secret']);
}
/**
* Check that the sql query has a valid hmac signature
*
* @param string $sqlQuery The sql query
* @return void
*/
public static function checkSqlQuerySignature($sqlQuery, $signature)
{
/** @var array $cfg */
global $cfg;
$hmac = hash_hmac('sha256', $sqlQuery, $_SESSION[' HMAC_secret '] . $cfg['blowfish_secret']);
return hash_equals($hmac, $signature);
}
}

View File

@ -5313,16 +5313,19 @@ class Results
$title = htmlspecialchars($data);
}
$sqlQuery = 'SELECT * FROM '
. Util::backquote($map[$meta->name][3]) . '.'
. Util::backquote($map[$meta->name][0])
. ' WHERE '
. Util::backquote($map[$meta->name][1])
. $where_comparison;
$_url_params = array(
'db' => $map[$meta->name][3],
'table' => $map[$meta->name][0],
'pos' => '0',
'sql_query' => 'SELECT * FROM '
. Util::backquote($map[$meta->name][3]) . '.'
. Util::backquote($map[$meta->name][0])
. ' WHERE '
. Util::backquote($map[$meta->name][1])
. $where_comparison,
'sql_signature' => Core::signSqlQuery($sqlQuery),
'sql_query' => $sqlQuery,
);
if ($transformation_plugin != $default_function) {

View File

@ -214,6 +214,7 @@ class AuthenticationSignon extends AuthenticationPlugin
/* Restore our token */
if (!empty($pma_token)) {
$_SESSION[' PMA_token '] = $pma_token;
$_SESSION[' HMAC_secret '] = Util::generateRandom(16);
}
/**

View File

@ -29,6 +29,7 @@ class Session
private static function generateToken()
{
$_SESSION[' PMA_token '] = Util::generateRandom(16);
$_SESSION[' HMAC_secret '] = Util::generateRandom(16);
/**
* Check if token is properly generated (the generation can fail, for example

View File

@ -1760,7 +1760,8 @@ class Util
$tag_params_strings = array();
if (($url_length > $GLOBALS['cfg']['LinkLengthLimit'])
|| ! $in_suhosin_limits
|| strpos($url, 'sql_query=') !== false
// Has as sql_query without a signature
|| ( strpos($url, 'sql_query=') !== false && strpos($url, 'sql_signature=') === false)
|| strpos($url, 'view[as]=') !== false
) {
$parts = explode('?', $url, 2);

View File

@ -13,6 +13,7 @@ use PhpMyAdmin\Response;
use PhpMyAdmin\Sql;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use PhpMyAdmin\Core;
/**
* Gets some core libraries
@ -71,6 +72,10 @@ if (isset($_POST['bkm_fields']['bkm_sql_query'])) {
$sql_query = $_POST['bkm_fields']['bkm_sql_query'];
} elseif (isset($_POST['sql_query'])) {
$sql_query = $_POST['sql_query'];
} elseif (isset($_GET['sql_query']) && isset($_GET['sql_signature'])) {
if (Core::checkSqlQuerySignature($_GET['sql_query'], $_GET['sql_signature'])) {
$sql_query = $_GET['sql_query'];
}
}
// This one is just to fill $db

View File

@ -1121,4 +1121,110 @@ class CoreTest extends PmaTestCase
$this->assertGreaterThan(0, mb_strpos($printed, $warn));
}
/**
* Test for Core::signSqlQuery
*
* @return void
*/
function testSignSqlQuery()
{
$_SESSION[' HMAC_secret '] = hash('sha1', 'test');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$signature = Core::signSqlQuery($sqlQuery);
$hmac = '33371e8680a640dc05944a2a24e6e630d3e9e3dba24464135f2fb954c3a4ffe2';
$this->assertSame($hmac, $signature, 'The signature must match the computed one');
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignature()
{
$_SESSION[' HMAC_secret '] = hash('sha1', 'test');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = '33371e8680a640dc05944a2a24e6e630d3e9e3dba24464135f2fb954c3a4ffe2';
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignatureFails()
{
$_SESSION[' HMAC_secret '] = hash('sha1', '132654987gguieunofz');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = '33371e8680a640dc05944a2a24e6e630d3e9e3dba24464135f2fb954c3a4ffe2';
$this->assertFalse(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignatureFailsBadHash()
{
$_SESSION[' HMAC_secret '] = hash('sha1', 'test');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = '3333333380a640dc05944a2a24e6e630d3e9e3dba24464135f2fb954c3eeeeee';
$this->assertFalse(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignatureFailsNoSession()
{
$_SESSION[' HMAC_secret '] = 'empty';
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = '3333333380a640dc05944a2a24e6e630d3e9e3dba24464135f2fb954c3eeeeee';
$this->assertFalse(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignatureFailsFromAnotherSession()
{
$_SESSION[' HMAC_secret '] = hash('sha1', 'firstSession');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = Core::signSqlQuery($sqlQuery);
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
$_SESSION[' HMAC_secret '] = hash('sha1', 'secondSession');
// Try to use the token (hmac) from the previous session
$this->assertFalse(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
/**
* Test for Core::checkSqlQuerySignature
*
* @return void
*/
function testCheckSqlQuerySignatureFailsBlowfishSecretChanged()
{
$GLOBALS['cfg']['blowfish_secret'] = '';
$_SESSION[' HMAC_secret '] = hash('sha1', 'firstSession');
$sqlQuery = 'SELECT * FROM `test`.`db` WHERE 1;';
$hmac = Core::signSqlQuery($sqlQuery);
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
$GLOBALS['cfg']['blowfish_secret'] = '32154987zd';
// Try to use the previous HMAC signature
$this->assertFalse(Core::checkSqlQuerySignature($sqlQuery, $hmac));
$GLOBALS['cfg']['blowfish_secret'] = '32154987zd';
// Generate the HMAC signature to check that it works
$hmac = Core::signSqlQuery($sqlQuery);
// Must work now, (good secret and blowfish_secret)
$this->assertTrue(Core::checkSqlQuerySignature($sqlQuery, $hmac));
}
}