Skip to content

Commit 05af36e

Browse files
committed
appsec/laravel: be more defensive
Just doing isset($user['username']) is not safe is $user doesn't implement ArrayAccess. php > class A {} php > $a = new A; php > var_dump(isset($a['x'])); PHP Warning: Uncaught Error: Cannot use object of type A as array in php shell code:1 Stack trace: thrown in php shell code on line 1
1 parent 0c35caf commit 05af36e

File tree

2 files changed

+70
-22
lines changed

2 files changed

+70
-22
lines changed

appsec/src/extension/php_helpers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const zend_array *nonnull dd_get_superglob_or_equiv(
6464
if (equiv) {
6565
ret = zend_hash_str_find(equiv, name, name_len);
6666
} else {
67-
ret = dd_php_get_autoglobal(track, ZEND_STRL("_GET"));
67+
ret = dd_php_get_autoglobal(track, name, name_len);
6868
}
6969

7070
if (!ret || Z_TYPE_P(ret) != IS_ARRAY) {

src/DDTrace/Integrations/Laravel/LaravelIntegration.php

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -367,27 +367,38 @@ static function ($This, $scope, $args, $loginSuccess) {
367367
static function ($This, $scope, $args) {
368368
$authClass = 'Illuminate\Contracts\Auth\Authenticatable';
369369
if (
370-
!function_exists('\datadog\appsec\track_user_login_success_event_automated') ||
370+
!function_exists('datadog\appsec\track_user_login_success_event_automated') ||
371371
!isset($args[1]) ||
372372
!$args[1] ||
373373
!($args[1] instanceof $authClass)
374374
) {
375375
return;
376376
}
377377

378+
$user = $args[1];
378379
$metadata = [];
379380

380-
if (isset($args[1]['name'])) {
381-
$metadata['name'] = $args[1]['name'];
382-
}
383-
384-
if (isset($args[1]['email'])) {
385-
$metadata['email'] = $args[1]['email'];
381+
if (\method_exists($user, '__isset') && \method_exists($user, '__get')) {
382+
// Model methods have table columns as properties
383+
if (isset($user->name)) {
384+
$metadata['name'] = $user->name;
385+
}
386+
if (isset($user->email)) {
387+
$metadata['email'] = $user->email;
388+
}
389+
} elseif ($user instanceof \ArrayAccess) {
390+
// Model also implements ArrayAccess
391+
if (isset($user['name'])) {
392+
$metadata['name'] = $user['name'];
393+
}
394+
if (isset($user['email'])) {
395+
$metadata['email'] = $user['email'];
396+
}
386397
}
387398

388399
\datadog\appsec\track_user_login_success_event_automated(
389-
self::getLoginFromArgs($args[1]),
390-
\method_exists($args[1], 'getAuthIdentifier') ? $args[1]->getAuthIdentifier() : '',
400+
self::getLoginFromArgs($user),
401+
self::getAuthIdentifier($user),
391402
$metadata
392403
);
393404
}
@@ -420,7 +431,7 @@ static function ($This, $scope, $args) {
420431

421432
\datadog\appsec\track_user_login_success_event_automated(
422433
self::getLoginFromArgs($args[0]),
423-
\method_exists($args[0], 'getAuthIdentifier') ? $args[0]->getAuthIdentifier() : '',
434+
self::getAuthIdentifier($args[0]),
424435
$metadata
425436
);
426437
}
@@ -454,13 +465,14 @@ static function ($This, $scope, $args, $user) {
454465
if (
455466
!isset($user) ||
456467
!$user ||
457-
!($user instanceof $authClass) ||
458-
!\method_exists($user, 'getAuthIdentifier')
468+
!($user instanceof $authClass)
459469
) {
460470
return;
461471
}
462472

463-
\datadog\appsec\track_authenticated_user_event_automated($user->getAuthIdentifier());
473+
\datadog\appsec\track_authenticated_user_event_automated(
474+
self::getAuthIdentifier($user)
475+
);
464476
}
465477
);
466478

@@ -478,13 +490,14 @@ static function ($This, $scope, $args) {
478490
if (
479491
!isset($args[1]) ||
480492
!$args[1] ||
481-
!($args[1] instanceof $authClass) ||
482-
!\method_exists($args[1], 'getAuthIdentifier')
493+
!($args[1] instanceof $authClass)
483494
) {
484495
return;
485496
}
486497

487-
\datadog\appsec\track_authenticated_user_event_automated($args[1]->getAuthIdentifier());
498+
\datadog\appsec\track_authenticated_user_event_automated(
499+
self::getAuthIdentifier($args[1])
500+
);
488501
}
489502
);
490503

@@ -505,7 +518,7 @@ static function ($This, $scope, $args) {
505518

506519
\datadog\appsec\track_user_signup_event_automated(
507520
self::getLoginFromArgs($args[0]),
508-
\method_exists($args[0], 'getAuthIdentifier') ? $args[0]->getAuthIdentifier() : '',
521+
self::getAuthIdentifier($args[0]),
509522
[]
510523
);
511524
}
@@ -588,16 +601,51 @@ public static function getServiceName()
588601
*/
589602
public static function getLoginFromArgs($args)
590603
{
591-
if (isset($args['email'])) {
592-
return $args['email'];
604+
if (\is_array($args) || $args instanceof \ArrayAccess) {
605+
if (isset($args['email'])) {
606+
return $args['email'];
607+
}
608+
if (isset($args['username'])) {
609+
return $args['username'];
610+
}
611+
}
612+
613+
if (!\is_object($args)) {
614+
return null;
615+
}
616+
617+
if (isset($args->email)) {
618+
return $args->email;
593619
}
594-
if (isset($args['username'])) {
595-
return $args['username'];
620+
621+
if (isset($args->username)) {
622+
return $args->username;
623+
}
624+
625+
$clazz = 'Illuminate\Auth\Passwords\CanResetPassword';
626+
if ($args instanceof $clazz) {
627+
return $args->getEmailForPasswordReset();
596628
}
597629

598630
return null;
599631
}
600632

633+
public static function getAuthIdentifier($user)
634+
{
635+
if (!\is_object($user) || !\method_exists($user, "getAuthIdentifier")) {
636+
return '';
637+
}
638+
639+
$identifier = $user->getAuthIdentifier();
640+
if (\is_string($identifier)) {
641+
return $identifier;
642+
}
643+
if (\is_int($identifier)) {
644+
return (string)$identifier;
645+
}
646+
return ''; // could be an aggregate key?
647+
}
648+
601649
/**
602650
* Tells whether a span is a lumen request.
603651
*

0 commit comments

Comments
 (0)