Commit 3ff3ea91 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'F7529GuaranteeGetSipActionPlayedOnlyOnce' into 'master'

F7529 guarantee get sip action played only once

See merge request !153
parents 92b3fab7 61617f52
Pipeline #1980 passed with stages
in 2 minutes and 53 seconds
......@@ -1257,7 +1257,11 @@ The following `escape` & `action` types are available:
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| Token | Description |
+=======+==================================================================================================================================+
| m | `real_escape_string() <http://php.net/manual/en/mysqli.real-escape-string.php>`_ (m = mysql) |
| c | Config - the escape type configured in `configuration`_. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| C | Colon ':' will be escaped against \\:. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| d | Double ticks " will be escaped against \\". |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| l | LDAP search filter values: `ldap-escape() <http://php.net/manual/en/function.ldap-escape.php>`_ (LDAP_ESCAPE_FILTER). |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
......@@ -1265,21 +1269,19 @@ The following `escape` & `action` types are available:
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| s | Single ticks ' will be escaped against \\'. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| d | Double ticks " will be escaped against \\". |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| C | Colon ':' will be escaped against \\:. |
| S | Stop replace. If the replaced value contains nested variables, they won't be replaced. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| c | Config - the escape type configured in `configuration`_. |
| m | `real_escape_string() <http://php.net/manual/en/mysqli.real-escape-string.php>`_ (m = mysql) |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| p | Password hashing: depends on the hashing type in the Typo3 installation, includes salting if configured. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| '' | Nothing defined - the escape/action class type configured in `configuration`_. |
| w | wipe out current key/value pair from SIP store `variable-escape-wipe-key`_ |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| \- | No escaping. |
| X | Throw exception if variable is not found in the given store(s). Outputs `variable-type-message-violate`_ |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| S | Stop replace. If the replaced value contains nested variables, they won't be replaced. |
| '' | Nothing defined - the escape/action class type configured in `configuration`_. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| X | Throw exception if variable is not found in the given store(s). Outputs `variable-type-message-violate`_ |
| \- | No escaping. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
......@@ -1319,6 +1321,17 @@ Action
In special situation it might be useful to do a full stop on all current actions (no further procession). A custom
message can be defined via: `variable-type-message-violate`_.
.. _`variable-escape-wipe-key`:
* *wipe* - 'w': In special cases it might be useful to get a value via SIP only one time and after retrieving the value
it will be deleted in STORE SIP . Further access to the variable will return 'variable undefined'. At time of writing
only the STORE SIP supports the feature 'wipe'. This is useful to suppress any repeating events by using the browser history.
The following example will send a mail only the first when it is called with a given SIP::
10.sql = SELECT '...' AS _sendmail FROM Person AS p WHERE '{{action:S::w}}'='send' AND p.id={{pId:S}}
.. _`variable-default`:
Default
......
......@@ -147,6 +147,7 @@ const ERROR_MESSAGE_HTTP_STATUS = 'httpStatus'; // HTTP Status Code to report
// QFQ Error Codes
const ERROR_UNKNOW_SANITIZE_CLASS = 1001;
const ERROR_QUIT_QFQ_REGULAR = 1001;
const ERROR_WIPE_NOT_IMPLEMENTED_FOR_STORE = 1002;
const ERROR_CODE_SHOULD_NOT_HAPPEN = 1003;
const ERROR_SIP_MALFORMED = 1005;
const ERROR_SIP_INVALID = 1006;
......@@ -735,6 +736,7 @@ const TOKEN_ESCAPE_LDAP_DN = 'L';
const TOKEN_ESCAPE_MYSQL = 'm';
const TOKEN_ESCAPE_PASSWORD_T3FE = 'p';
const TOKEN_ESCAPE_NONE = '-';
const TOKEN_ESCAPE_WIPE = 'w';
const TOKEN_ESCAPE_STOP_REPLACE = 'S';
const TOKEN_ESCAPE_EXCEPTION = 'X';
......
......@@ -11,6 +11,7 @@ namespace qfq;
use qfq;
require_once(__DIR__ . '/../core/store/Store.php');
require_once(__DIR__ . '/../core/store/Sip.php');
require_once(__DIR__ . '/../core/database/Database.php');
require_once(__DIR__ . '/../core/typo3/Password.php');
require_once(__DIR__ . '/helper/Support.php');
......@@ -68,9 +69,9 @@ class Evaluate {
$this->startDelimiterLength = strlen($startDelimiter);
$this->endDelimiter = $endDelimiter;
$this->endDelimiterLength = strlen($endDelimiter);
$this->escapeTypeDefault = $this->store->getVar(F_ESCAPE_TYPE_DEFAULT, STORE_SYSTEM);
$this->escapeTypeDefault = $this->store::getVar(F_ESCAPE_TYPE_DEFAULT, STORE_SYSTEM);
if (empty($this->escapeTypeDefault) || $this->escapeTypeDefault == TOKEN_ESCAPE_CONFIG) {
$this->escapeTypeDefault = $this->store->getVar(SYSTEM_ESCAPE_TYPE_DEFAULT, STORE_SYSTEM);
$this->escapeTypeDefault = $this->store::getVar(SYSTEM_ESCAPE_TYPE_DEFAULT, STORE_SYSTEM);
}
}
......@@ -155,7 +156,7 @@ class Evaluate {
$posFirstClose = strpos($result, $this->endDelimiter);
// Variables like 'fillStoreVar' might contain SQL statements. Put them in store in case a DB exception is thrown.
$this->store->setVar(SYSTEM_SQL_RAW, $line, STORE_SYSTEM);
$this->store::setVar(SYSTEM_SQL_RAW, $line, STORE_SYSTEM);
while ($posFirstClose !== false) {
......@@ -236,7 +237,7 @@ class Evaluate {
$token = OnString::trimQuote(trim(implode(' ', $arrToken)));
if ($this->link === null) {
$this->link = new Link($this->store->getSipInstance(), $dbIndex);
$this->link = new Link($this->store::getSipInstance(), $dbIndex);
}
$foundInStore = TOKEN_FOUND_AS_COLUMN;
......@@ -261,7 +262,7 @@ class Evaluate {
}
if ($this->link === null) {
$this->link = new Link($this->store->getSipInstance(), $dbIndex);
$this->link = new Link($this->store::getSipInstance(), $dbIndex);
}
$foundInStore = TOKEN_FOUND_AS_COLUMN;
......@@ -269,7 +270,7 @@ class Evaluate {
$s = $this->link->renderLink('U:' . $token . '|s|r:8');
// Flag to add DND JS code later on.
$this->store->setVar(SYSTEM_DRAG_AND_DROP_JS, 'true', STORE_SYSTEM);
$this->store::setVar(SYSTEM_DRAG_AND_DROP_JS, 'true', STORE_SYSTEM);
// data-dnd-api="typo3conf/ext/qfq/qfq/api/dragAndDrop.php?s={{'U:form=<form name>[&paramX=<any value>]|s|r:8' AS _link}}"
return DND_DATA_DND_API . '="' . API_DIR . '/' . API_DRAG_AND_DROP_PHP . '?s=' . $s . '"';
......@@ -298,7 +299,7 @@ class Evaluate {
$token = trim($token);
$dbIndex = $this->dbIndex;
$flagThrowExceptionIfNotFound = false;
$flagWipe = false;
// Check if the $token starts with '[<int>]...' - yes: open the necessary database.
if (strlen($token) > 2 && $token[0] === '[') {
......@@ -360,7 +361,7 @@ class Evaluate {
$typeMessageViolate = ($arrToken[VAR_INDEX_MESSAGE] === null || $arrToken[VAR_INDEX_MESSAGE] === '') ? SANITIZE_TYPE_MESSAGE_VIOLATE_CLASS : $arrToken[VAR_INDEX_MESSAGE];
// search for value in stores
$value = $this->store->getVar($arrToken[VAR_INDEX_VALUE], $arrToken[VAR_INDEX_STORE], $arrToken[VAR_INDEX_SANATIZE], $foundInStore, $typeMessageViolate);
$value = $this->store::getVar($arrToken[VAR_INDEX_VALUE], $arrToken[VAR_INDEX_STORE], $arrToken[VAR_INDEX_SANATIZE], $foundInStore, $typeMessageViolate);
// escape ticks
if (is_string($value)) {
......@@ -400,6 +401,9 @@ class Evaluate {
case TOKEN_ESCAPE_EXCEPTION:
// empty values will be handled later.
break;
case TOKEN_ESCAPE_WIPE:
$flagWipe = true;
break;
default:
throw new UserFormException("Unknown escape qualifier: $escape", ERROR_UNKNOW_SANITIZE_CLASS);
break;
......@@ -418,6 +422,22 @@ class Evaluate {
$value = str_replace('\\:', ':', $arrToken[VAR_INDEX_DEFAULT]);
}
if ($flagWipe) {
switch ($foundInStore) {
case STORE_SIP:
$this->store::unsetVar($arrToken[VAR_INDEX_VALUE], STORE_SIP);
$sip = new Sip();
$sip->removeKeyFromSip($this->store::getVar(SIP_SIP, STORE_SIP), $arrToken[VAR_INDEX_VALUE]);
break;
case STORE_EMPTY:
case STORE_ZERO:
break;
default:
throw new UserReportException("Wipe not implemented for store $foundInStore", ERROR_WIPE_NOT_IMPLEMENTED_FOR_STORE);
}
}
return $value;
}
......
......@@ -23,8 +23,6 @@ class Sip {
private $phpUnit = false;
private $staticUniqId = false;
private $getParamL = '';
private $getParamType = '';
/**
* @param bool|false $phpUnit
......@@ -291,6 +289,41 @@ class Sip {
Session::set($sipParamStringNew, $sip);
}
/**
* Remove one key (incl value) from SIP. Do not change the SIP.
*
* set: sip['badcaffee1234']="r=123&action=start" >> sip['badcaffee1234']="r=123"
* unset: sip['r=123&action=start']
* set: sip("r=123")= 'badcaffee1234'
*
* @param string $s
* @param string $key
*/
public function removeKeyFromSip($s, $key) {
// Get old entry
$sipParamStringOld = Session::get($s);
$arr = explode('&', $sipParamStringOld);
// Find key and remove from array
foreach ($arr as $idx => $value) {
$tokenArr = explode('=', $value, 2);
if (($tokenArr[0] ?? '') == $key) {
unset($arr[$idx]);
}
}
$sipParamStringNew = implode('&', $arr);
// Remove old
Session::unsetItem($sipParamStringOld);
// Set new
Session::set($s, $sipParamStringNew);
Session::set($sipParamStringNew, $s);
}
/**
* Retrieve Params stored in $_SESSION[$s]
*
......@@ -305,7 +338,7 @@ class Sip {
# Check if parameter is manipulated
if (strlen($s) != SIP_TOKEN_LENGTH) {
Config::attackDetectedExitNow(array(), 'Invalid SIP token length: ' . strlen($s) . " _GET['s']=" . htmlentities($s) );
Config::attackDetectedExitNow(array(), 'Invalid SIP token length: ' . strlen($s) . " _GET['s']=" . htmlentities($s));
}
// Validate: Check if still the same fe_user is logged in.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment