These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @title Token CSRF (Cross-site request forgery) |
||
4 | * @desc Protects against Cross-site request forgery attack. |
||
5 | * |
||
6 | * @author Pierre-Henry Soria <[email protected]> |
||
7 | * @copyright (c) 2012-2017, Pierre-Henry Soria. All Rights Reserved. |
||
8 | * @license GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory. |
||
9 | * @package PH7 / Framework / Security / CSRF |
||
10 | * @version 1.2 |
||
11 | */ |
||
12 | |||
13 | namespace PH7\Framework\Security\CSRF; |
||
14 | |||
15 | defined('PH7') or exit('Restricted access'); |
||
16 | |||
17 | use PH7\Framework\Session\Session; |
||
18 | use PH7\Framework\Navigation\Browser; |
||
19 | use PH7\Framework\Util\Various; |
||
20 | use PH7\Framework\Mvc\Model\DbConfig; |
||
21 | use PH7\Framework\Mvc\Request\Http; |
||
22 | use PH7\Framework\Ip\Ip; |
||
23 | use PH7\UserCore; |
||
24 | use PH7\AdminCore; |
||
25 | use PH7\AffiliateCore; |
||
26 | |||
27 | /** |
||
28 | * This class provides functions of numbers against the XSS (Cross-site scripting) vulnerability. |
||
29 | * PH Security Token (PHST) |
||
30 | */ |
||
31 | final class Token |
||
32 | { |
||
33 | /** |
||
34 | * @internal We have commented on "security_token_http_referer_*" because it causes bugs and it doesn't |
||
35 | * play a big role for safety because this variable can be changed by users (and the web browser). |
||
36 | */ |
||
37 | |||
38 | const VAR_NAME = 'pHST'; |
||
39 | |||
40 | /** @var Session */ |
||
41 | private $_oSession; |
||
42 | |||
43 | /** @var null|string */ |
||
44 | private $_sHttpReferer; |
||
45 | |||
46 | /** @var null|string */ |
||
47 | private $_sUserAgent; |
||
48 | |||
49 | public function __construct() |
||
50 | { |
||
51 | $this->_oSession = new Session; |
||
52 | |||
53 | $oBrowser = new Browser; |
||
54 | $this->_sHttpReferer = $oBrowser->getHttpReferer(); |
||
0 ignored issues
–
show
|
|||
55 | $this->_sUserAgent = $oBrowser->getUserAgent(); |
||
0 ignored issues
–
show
It seems like
$oBrowser->getUserAgent() can also be of type array . However, the property $_sUserAgent is declared as type null|string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
Loading history...
|
|||
56 | unset($oBrowser); |
||
57 | } |
||
58 | |||
59 | /** |
||
60 | * Generate a random token. |
||
61 | * |
||
62 | * @param string $sName |
||
63 | * |
||
64 | * @return string The Token generated random. |
||
65 | */ |
||
66 | public function generate($sName) |
||
67 | { |
||
68 | // If the token is still valid, it returns the correct token |
||
69 | if ($this->_oSession->exists('security_token_' . $sName)) { |
||
70 | return $this->_oSession->get('security_token_' . $sName); |
||
71 | } else { |
||
72 | $sToken = Various::genRnd($sName); |
||
73 | |||
74 | $aSessionData = [ |
||
75 | 'security_token_' . $sName => $sToken, |
||
76 | 'security_token_time_' . $sName => time(), |
||
77 | //'security_token_http_referer_' . $sName => $this->_sHttpReferer, |
||
78 | 'security_token_ip_' . $sName => Ip::get(), |
||
79 | 'security_token_http_user_agent_' . $sName => $this->_sUserAgent |
||
80 | ]; |
||
81 | |||
82 | $this->_oSession->set($aSessionData); |
||
83 | return $sToken; |
||
84 | } |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * @param string $sName Name of the Token. |
||
89 | * |
||
90 | * @param string $sInputToken The name of the token inserted in the hidden tag of the form. |
||
91 | * (e.g. for a from with method "post" and the field "<input type="hidden" name="my_token" />" the name of the token is "$_POST['my_token']" Default NULL |
||
92 | * |
||
93 | * @param integer $iTime Lifetime of token in seconds. Default NULL (value specified in the database settings). |
||
94 | * |
||
95 | * @return boolean Returns TRUE if the token is validated, FALSE otherwise. |
||
96 | */ |
||
97 | public function check($sName, $sInputToken = null, $iTime = null) |
||
98 | { |
||
99 | $iTime = (empty($iTime)) ? DbConfig::getSetting('securityTokenLifetime') : $iTime; |
||
100 | |||
101 | // The default tag name for the security token |
||
102 | $sInputToken = (empty($sInputToken)) ? (new Http)->post('security_token') : $sInputToken; |
||
103 | |||
104 | $aCheckSession = [ |
||
105 | 'security_token_' . $sName, |
||
106 | 'security_token_time_' . $sName, |
||
107 | //'security_token_http_referer_' . $sName, |
||
108 | 'security_token_ip_' . $sName, |
||
109 | 'security_token_http_user_agent_' . $sName |
||
110 | ]; |
||
111 | |||
112 | if ($this->_oSession->exists($aCheckSession) && !empty($sInputToken)) |
||
113 | if ($this->_oSession->get('security_token_' . $sName) === $sInputToken) |
||
114 | if ($this->_oSession->get('security_token_time_' . $sName) >= (time() - $iTime)) |
||
115 | //if ($this->_sHttpReferer === $this->_oSession->get('security_token_http_referer_' . $sName)) |
||
116 | if (Ip::get() === $this->_oSession->get('security_token_ip_' . $sName)) |
||
117 | if ($this->_sUserAgent === $this->_oSession->get('security_token_http_user_agent_' . $sName)) |
||
118 | { |
||
119 | // Delete the token and data sessions expired |
||
120 | $this->_oSession->remove($aCheckSession); |
||
121 | return true; |
||
122 | } |
||
123 | |||
124 | // Delete the token and data sessions expired |
||
125 | $this->_oSession->remove($aCheckSession); |
||
126 | return false; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * The Get Token parameter for the URL if someone is logged (User, Admin or Affiliate), nothing otherwise. |
||
131 | * |
||
132 | * @return string |
||
133 | */ |
||
134 | public function url() |
||
135 | { |
||
136 | return ($this->currentSess() !== true) ? '?' . static::VAR_NAME . '=' . $this->currentSess() : ''; |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Checks the URL Token. |
||
141 | * |
||
142 | * @return boolean |
||
143 | */ |
||
144 | public function checkUrl() |
||
145 | { |
||
146 | $oHttpRequest = new Http; |
||
147 | $bRet = ( ($this->currentSess() === true) || $oHttpRequest->currentUrl() === PH7_URL_ROOT || ($oHttpRequest->get(static::VAR_NAME) === $this->currentSess()) ); |
||
148 | unset($oHttpRequest); |
||
149 | |||
150 | return $bRet; |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Gets The Current Session Token. |
||
155 | * |
||
156 | * @return string|boolean The "token" if a user is logged or "true" if no user is logged. |
||
157 | */ |
||
158 | protected function currentSess() |
||
159 | { |
||
160 | if (UserCore::auth()) |
||
161 | $sToken = $this->_oSession->get('member_token'); |
||
162 | elseif (AdminCore::auth()) |
||
163 | $sToken = $this->_oSession->get('admin_token'); |
||
164 | elseif (AffiliateCore::auth()) |
||
165 | $sToken = $this->_oSession->get('affiliate_token'); |
||
166 | else $sToken = true; // If nobody is logged on, we did not need to do this test, so it returns true |
||
167 | |||
168 | return $sToken; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Clone is set to private to stop cloning. |
||
173 | */ |
||
174 | private function __clone() {} |
||
175 | } |
||
176 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.