Issues (21)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

helper/session_helper.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
*
4
* 2FA extension for the phpBB Forum Software package.
5
*
6
* @copyright (c) 2015 Paul Sohier
7
* @license GNU General Public License, version 2 (GPL-2.0)
8
*
9
*/
10
11
namespace paul999\tfa\helper;
12
13
use paul999\tfa\exceptions\module_exception;
14
use paul999\tfa\modules\module_interface;
15
use phpbb\auth\auth;
16
use phpbb\config\config;
17
use phpbb\controller\helper;
18
use phpbb\db\driver\driver_interface;
19
use phpbb\di\service_collection;
20
use phpbb\template\template;
21
use phpbb\user;
22
23
/**
24
 * helper method which is used to detect if a user needs to use 2FA
25
 */
26
class session_helper implements session_helper_interface
27
{
28
	/**
29
	 * @var driver_interface
30
	 */
31
	private $db;
32
33
	/**
34
	 * @var config
35
	 */
36
	private $config;
37
38
	/**
39
	 * @var user
40
	 */
41
	private $user;
42
43
	/**
44
	 * @var array
45
	 */
46
	private $modules;
47
48
	private $module_data = [];
49
50
	/**
51
	 * @var string
52
	 */
53
	private $registration_table;
54
55
	/**
56
	 * @var string
57
	 */
58
	private $user_table;
59
60
	/**
61
	 * @var array
62
	 */
63
	private $user_array = [];
64
65
	/**
66
	 * @var \phpbb\template\template
67
	 */
68
	private $template;
69
70
	/**
71
	 * @var \phpbb\controller\helper
72
	 */
73
	private $controller_helper;
74
75
	/**
76
	 * Constructor
77
	 *
78
	 * @access public
79
	 *
80
	 * @param driver_interface         $db
81
	 * @param config                   $config
82
	 * @param user                     $user
83
	 * @param service_collection       $modules
84
	 * @param \phpbb\template\template $template
85
	 * @param \phpbb\controller\helper $controller_helper
86
	 * @param string                   $registration_table
87
	 * @param string                   $user_table
88
	 */
89 View Code Duplication
	public function __construct(driver_interface $db, config $config, user $user, service_collection $modules, template $template, helper $controller_helper, $registration_table, $user_table)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
	{
91
		$this->db					= $db;
92
		$this->user					= $user;
93
		$this->config				= $config;
94
		$this->template 			= $template;
95
		$this->controller_helper 	= $controller_helper;
96
		$this->registration_table	= $registration_table;
97
		$this->user_table			= $user_table;
98
		$this->module_data			= $modules;
0 ignored issues
show
Documentation Bug introduced by
It seems like $modules of type object<phpbb\di\service_collection> is incompatible with the declared type array of property $module_data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
99
	}
100
101
	/**
102
	 * Register the tagged modules if they are enabled.
103
	 */
104
	private function validate_modules()
105
	{
106
		/**
107
		 * @var module_interface $module
108
		 */
109
		foreach ($this->module_data as $module)
110
		{
111
			if ($module instanceof module_interface)
112
			{
113
				// Only add them if they are actually a module_interface.
114
				$priority = $module->get_priority();
115
				if (isset($this->modules[$module->get_priority()]))
116
				{
117
					throw new module_exception(400, 'TFA_DOUBLE_PRIORITY', array($priority, get_class($module), get_class($this->modules[$priority])));
118
				}
119
				if ($module->is_enabled())
120
				{
121
					$this->modules[$priority] = $module;
122
				}
123
			}
124
		}
125
	}
126
127
	/**
128
	 * @param $requested_module
129
	 * @return null|module_interface
130
	 */
131
	public function find_module($requested_module)
132
	{
133
		/**
134
		 * @var module_interface $module
135
		 */
136
		foreach ($this->get_modules() as $module)
137
		{
138
			if ($module->get_name() == $requested_module)
139
			{
140
				return $module;
141
			}
142
		}
143
		return null;
144
	}
145
146
	/**
147
	 * @return array
148
	 */
149
	public function get_modules()
150
	{
151
		if (empty($this->modules))
152
		{
153
			$this->validate_modules();
154
		}
155
		return $this->modules;
156
	}
157
158
	/**
159
	 * @param int $user_id
160
	 * @param bool $admin
161
	 * @param array $userdata
162
	 * @return bool
163
	 */
164
	public function is_tfa_required($user_id, $admin = false, $userdata = array())
165
	{
166
		if (sizeof($this->get_modules()) == 0)
167
		{
168
			return false;
169
		}
170
		switch ($this->config['tfa_mode'])
171
		{
172
			case session_helper_interface::MODE_DISABLED:
173
				return false;
174
175
			case session_helper_interface::MODE_NOT_REQUIRED:
176
				return $this->is_tfa_registered($user_id);
177
178
			case session_helper_interface::MODE_REQUIRED_FOR_ACP_LOGIN:
179
			case session_helper_interface::MODE_REQUIRED_FOR_ADMIN:
180
				return $this->do_permission_check($user_id, $userdata, 'a_');
181
182
			case session_helper_interface::MODE_REQUIRED_FOR_MODERATOR:
183
				return $this->do_permission_check($user_id, $userdata, array('m_', 'a_'));
184
185
			case session_helper_interface::MODE_REQUIRED:
186
				return true;
187
188
			default:
189
				return false;
190
		}
191
	}
192
193
	/**
194
	 * Check if the user has two factor authentication added to his account.
195
	 *
196
	 * @param int $user_id
197
	 * @return bool
198
	 */
199
	public function is_tfa_registered($user_id)
200
	{
201
		if (isset($this->user_array[$user_id]))
202
		{
203
			return $this->user_array[$user_id];
204
		}
205
206
		$this->user_array[$user_id] = false; // Preset to false.
207
208
		/**
209
		 * @var int $priority
210
		 * @var module_interface $module
211
		 */
212
		foreach ($this->get_modules() as $priority => $module)
213
		{
214
			$this->user_array[$user_id] = $this->user_array[$user_id] || $module->is_usable($user_id);
215
		}
216
		return $this->user_array[$user_id];
217
	}
218
219
	/**
220
	 * Check if the user has any key registred, even if the module is not available.
221
	 *
222
	 * @param int $user_id
223
	 * @return bool
224
	 */
225
	public function is_tfa_key_registred($user_id)
226
	{
227
		/**
228
		 * @var int $priority
229
		 * @var module_interface $module
230
		 */
231
		foreach ($this->get_modules() as $priority => $module)
232
		{
233
			if ($module->key_registered($user_id))
234
			{
235
				return true;
236
			}
237
		}
238
		return false;
239
	}
240
241
242
	/**
243
	 * @param int $user_id
244
	 * @param bool $admin
245
	 * @param bool $auto_login
246
	 * @param bool $viewonline
247
	 * @param string $redirect
248
	 * @param bool $secure
249
	 * @throws \Exception
250
	 */
251
	public function generate_page($user_id, $admin, $auto_login, $viewonline, $redirect, $secure = false)
252
	{
253
		$this->user->add_lang_ext('paul999/tfa', 'common');
254
		$modules = $this->get_modules();
255
256
		/**
257
		 * @var module_interface $row
258
		 */
259
		foreach ($modules as $row)
260
		{
261
			if ($row->is_usable($user_id))
262
			{
263
				$this->template->assign_block_vars('tfa_options', array_merge(array(
264
					'ID'	=> $row->get_name(),
265
					'NAME'	=> $this->user->lang($row->get_translatable_name()),
266
					'U_SUBMIT_AUTH'	=> $this->controller_helper->route('paul999_tfa_read_controller_submit', array(
267
						'user_id'		=> (int) $user_id,
268
						'admin'			=> (int) $admin,
269
						'auto_login'	=> (int) $auto_login,
270
						'viewonline'	=> (int) $viewonline,
271
						'class'			=> $row->get_name(),
272
					)),
273
					'S_HIDDEN_FIELDS' => build_hidden_fields(['sid' => $this->user->session_id]),
274
				), $row->login_start($user_id)));
275
			}
276
		}
277
278
		add_form_key('tfa_login_page');
279
280
		$random = sha1(random_bytes(32));
281
282
		$sql_ary = array(
283
			'tfa_random' 	=> $random,
284
			'tfa_uid'		=> $user_id,
285
		);
286
		$sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . "
287
			WHERE
288
				session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "' AND
289
				session_user_id = " . (int) $this->user->data['user_id'];
290
		$this->db->sql_query($sql);
291
292
		$this->template->assign_vars(array(
293
			'REDIRECT'		=> $redirect,
294
			'RANDOM'		=> $random,
295
			'RELOGIN_NOTE'	=> $secure,
296
		));
297
298
		page_header('TFA_KEY_REQUIRED');
299
300
		$this->template->set_filenames(array(
301
			'body' => '@paul999_tfa/authenticate_main.html'
302
		));
303
		page_footer(false); // Do not include cron on this page!
304
	}
305
306
	/**
307
	 * Return the userdata for a specific user.
308
	 *
309
	 * @param int $user_id
310
	 * @param array $userdata
311
	 * @return array
312
	 */
313
	private function user_data($user_id, $userdata = array())
314
	{
315
		if (empty($userdata))
316
		{
317
			$sql = 'SELECT * FROM ' . $this->user_table . ' WHERE user_id = ' . (int) $user_id;
318
			$result = $this->db->sql_query($sql);
319
			$userdata = $this->db->sql_fetchrow($result);
320
			$this->db->sql_freeresult($result);
321
		}
322
		return $userdata;
323
	}
324
325
	/**
326
	 * @param int $user_id
327
	 * @param array $userdata
328
	 * @param string|array $permission
329
	 * @return bool
330
	 */
331
	private function do_permission_check($user_id, $userdata, $permission)
332
	{
333
		if ($this->is_tfa_registered($user_id))
334
		{
335
			return true;
336
		}
337
		$userdata = $this->user_data($user_id, $userdata);
338
		$auth = new auth();
339
		$auth->acl($userdata);
340
341
		if (!is_array($permission))
342
		{
343
			$permission = array($permission);
344
		}
345
		foreach ($permission as $perm)
346
		{
347
			if ($auth->acl_get($perm))
348
			{
349
				return true;
350
			}
351
		}
352
		return false;
353
	}
354
}
355