PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/controller/class-webauthn.php +47 -14 6.2.0 → 6.3.0 View file →
@@ -7,8 +7,9 @@
7 7
8 8 namespace WP_Defender\Controller;
9 9
10 10 use Error;
11 +use WP_User;
11 12 use Exception;
12 13 use WP_DEFENDER_VENDOR\Webauthn\Server;
13 14 use WP_Defender\Controller;
14 15 use WP_Defender\Behavior\WPMUDEV;
@@ -246,8 +247,9 @@
246 247 $posted_data = defender_get_data_from_request( null, 'p' );
247 248 if ( '' === $posted_data['data'] || '' === $posted_data['client_id'] ) {
248 249 throw new Exception( esc_html__( 'Missing field(s).', 'defender-security' ) );
249 250 }
251 + $client_id = sanitize_text_field( $posted_data['client_id'] );
250 252
251 253 $psr17_factory = new Psr17Factory();
252 254 $creator = new ServerRequestCreator(
253 255 $psr17_factory,
@@ -269,9 +271,8 @@
269 271 null
270 272 );
271 273
272 274 $response_data = base64_decode( sanitize_text_field( $posted_data['data'] ), true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
273 - $client_id = sanitize_text_field( $posted_data['client_id'] );
274 275 $pub_key_cco = $this->get_trans_val( 'pub_key_cco', $client_id );
275 276 $pub_key_cco = PublicKeyCredentialCreationOptions::createFromString( base64_decode( $pub_key_cco, true ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
276 277
277 278 $public_key_credential_source = $server->loadAndCheckAttestationResponse(
@@ -304,12 +305,16 @@
304 305 );
305 306 }
306 307 wp_send_json_success( $response );
307 308 } catch ( Error $error ) {
308 - $this->delete_trans( 'pub_key_cco', $client_id );
309 + if ( null !== $client_id ) {
310 + $this->delete_trans( 'pub_key_cco', $client_id );
311 + }
309 312 wp_send_json_error( $error->getMessage() );
310 313 } catch ( Exception $exception ) {
311 - $this->delete_trans( 'pub_key_cco', $client_id );
314 + if ( null !== $client_id ) {
315 + $this->delete_trans( 'pub_key_cco', $client_id );
316 + }
312 317 wp_send_json_error( $exception->getMessage() );
313 318 }
314 319 }
315 320
@@ -496,14 +501,15 @@
496 501
497 502 /**
498 503 * Verify response.
499 504 *
500 - * @param bool $will_return Either return array or echo json.
505 + * @param bool $will_return Either return array or echo json.
506 + * @param WP_User|null $expected_user The expected user.
501 507 *
502 508 * @return array|void
503 509 * @throws Exception If something goes wrong.
504 510 */
505 - public function verify_response( bool $will_return = false ) {
511 + public function verify_response( bool $will_return = false, ?WP_User $expected_user = null ) {
506 512 $client_id = null;
507 513 try {
508 514 if ( ! $this->verify_nonce( 'wpdef_webauthn', 'post' ) ) {
509 515 throw new Exception( esc_html__( 'Bad nonce.', 'defender-security' ) );
@@ -517,23 +523,44 @@
517 523 || '' === $posted_data['client_id']
518 524 ) {
519 525 throw new Exception( esc_html__( 'Missing field(s).', 'defender-security' ) );
520 526 }
527 + $client_id = sanitize_text_field( $posted_data['client_id'] );
528 + // Check expected user.
529 + if ( $expected_user instanceof WP_User ) {
530 + $user = $expected_user;
531 + } else {
532 + $user = wp_get_current_user();
533 + }
521 534
522 - $user_entity = false;
535 + // Establish a trusted scope BEFORE any access to the repository —
536 + // both before our own pre-check and before internal library calls
537 + // inside loadAndCheckAssertionResponse().
538 + $this->service->set_expected_user_id( $user->ID );
523 539 $response_data = base64_decode( $posted_data['data'], true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
524 - $username = sanitize_text_field( $posted_data['username'] );
525 - $client_id = sanitize_text_field( $posted_data['client_id'] );
526 - $pub_key_cro = PublicKeyCredentialRequestOptions::createFromString( base64_decode( $this->get_trans_val( 'pub_key_cro', $client_id ), true ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
527 - $user = get_user_by( 'login', $username );
540 + if ( false === $response_data ) {
541 + throw new Exception( esc_html__( 'Invalid response data.', 'defender-security' ) );
542 + }
528 543
529 - if ( is_object( $user ) ) {
530 - $user_entity = $this->get_user_entity( $user->ID );
544 + $decoded_response = json_decode( $response_data, true );
545 + if ( ! is_array( $decoded_response ) || ! isset( $decoded_response['rawId'] ) || ! is_string( $decoded_response['rawId'] ) || '' === $decoded_response['rawId'] ) {
546 + throw new Exception( esc_html__( 'Invalid assertion payload.', 'defender-security' ) );
531 547 }
532 548
549 + $credential_id = $this->base64url_decode( $decoded_response['rawId'] );
550 + if ( false === $credential_id || '' === $credential_id ) {
551 + throw new Exception( esc_html__( 'Invalid credential id.', 'defender-security' ) );
552 + }
553 + $credential = $this->service->findOneByCredentialId( $credential_id );
554 + if ( ! $credential ) {
555 + throw new Exception( esc_html__( 'Invalid user.', 'defender-security' ) );
556 + }
557 +
558 + $user_entity = $this->get_user_entity( $user->ID );
533 559 if ( false === $user_entity ) {
534 560 throw new Exception( esc_html__( 'User does not exist.', 'defender-security' ) );
535 561 }
562 + $pub_key_cro = PublicKeyCredentialRequestOptions::createFromString( base64_decode( $this->get_trans_val( 'pub_key_cro', $client_id ), true ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
536 563
537 564 $psr17_factory = new Psr17Factory();
538 565 $creator = new ServerRequestCreator(
539 566 $psr17_factory,
@@ -562,14 +589,18 @@
562 589 $server_request
563 590 );
564 591
565 592 $this->delete_trans( 'pub_key_cro', $client_id );
593 + // Reset the area just in case.
594 + $this->service->set_expected_user_id( null );
566 595
567 596 $data = esc_html__( 'Authenticator verified successfully.', 'defender-security' );
568 597
569 598 return defender_maybe_echo_json( $data, true, $will_return );
570 599 } catch ( Error $error ) {
571 - $this->delete_trans( 'pub_key_cro', $client_id );
600 + if ( null !== $client_id ) {
601 + $this->delete_trans( 'pub_key_cro', $client_id );
602 + }
572 603
573 604 return defender_maybe_echo_json( $error->getMessage(), false, $will_return );
574 605 } catch ( Exception $exception ) {
575 606 $data = array( 'message' => $exception->getMessage() );
@@ -583,9 +614,11 @@
583 614
584 615 $this->service->addUserHandleMatchFailed( $user, $decoded_response );
585 616 }
586 617
587 - $this->delete_trans( 'pub_key_cro', $client_id );
618 + if ( null !== $client_id ) {
619 + $this->delete_trans( 'pub_key_cro', $client_id );
620 + }
588 621
589 622 return defender_maybe_echo_json( $data, false, $will_return );
590 623 }
591 624 }