0

When we install WordPress with Softaculous, a Login button appears and we log in to the site without entering the username and password we pressed.

We have a site where we sell digital subscriptions. We manage subscriptions for various websites here. Now we need to integrate a site made with WordPress here.

When our customer receives a site subscription, we plan to create a user for the WordPress site with the code below.

add_action('rest_api_init', 'wp_rest_user_endpoints');
/**
* Register a new user
*
* @param WP_REST_Request $request Full details about the request.
* @return array $args.
**/
function wp_rest_user_endpoints($request) {
   /**
   * Handle Register User request.
   */
   register_rest_route('wp/v2', 'users/register', array(
       'methods' => 'POST',
       'callback' => 'wc_rest_user_endpoint_handler',
   ));
}

function wc_rest_user_endpoint_handler($request = null) {
   $response = array();
   $parameters = $request->get_json_params();
   $username = sanitize_text_field($parameters['username']);
   $email = sanitize_text_field($parameters['email']);
   $password = sanitize_text_field($parameters['password']);
   $error = new WP_Error();
   if (empty($username)) {
      $error->add(400, __("Username field 'username' is required.", 'wp-rest-user'), array('status' => 400));
      return $error;
   }
   if (empty($email)) {
      $error->add(401, __("Email field 'email' is required.", 'wp-rest-user'), array('status' => 400));
      return $error;
   }
   if (empty($password)) {
      $error->add(404, __("Password field 'password' is required.", 'wp-rest-user'), array('status' => 400));
      return $error;
   }
   $user_id = username_exists($username);
   if (!$user_id && email_exists($email) == false) {
      $user_id = wp_create_user($username, $password, $email);
      if (!is_wp_error($user_id)) {
         $user = get_user_by('id', $user_id);
         $user->set_role('subscriber');
         $response['code'] = 200;
         $response['message'] = __("User '" . $username . "' Registration was Successful", "wp-rest-user");
      } else {
         return $user_id;
      }
   } else {
      $error->add(406, __("Email already exists, please try 'Reset Password'", 'wp-rest-user'), array('status' => 400));
      return $error;
   }
   return new WP_REST_Response($response, 123);
}

Then, we want to put a Login button on our site, as I mentioned above in the Softaculous structure, and direct it to the WordPress website as a member login.

Q1. How can we do this login event? Can we login via API or do we need something different? I'm asking because I've seen ways to log in with a cookie.

We also put a member login form on the WordPress website. This form triggers an API that checks whether the membership we have written on our site is active or not.

Q2. When it gets Ok result from API, it will return to WordPress site and log in. How can we make this turn?

5
  • we have a 1 question per question policy but I notice there is nothing protecting your registration endpoint from bulk user registration attacks, nothing to enforce minimum password security rules, and no email validation or verification ( assuming it's even an email ). I could download a list of users and sign them up without them knowing in bulk using a script in 5 minutes or spam your users table with thousands of junk users.
    – Tom J Nowell
    Mar 8 at 14:14
  • Membership will be done entirely through our own panel. We generate a random username and use the e-mail address he subscribed to. In the same way, we create the password from the panel and direct it that way. We don't make easy passwords anyway. Anyone who wants to become a member of us already has to pay money. Since it will only be processed between two servers, wouldn't it be safe if we make the access of the api's based on ip?
    – sakarya
    Mar 8 at 15:06
  • that's fine within a system, but this is a singular endpoint that I can hit and bypass your entire membership system for malicious purposes, and no IP restrictions are not the solution, they mitigate the problem slightly, but the whole point of security measures is that you don't trust the input by default. The request has to prove to you that it's valid and you can't assume the values are safe to process, or that the request came from your own code and your own servers.
    – Tom J Nowell
    Mar 8 at 16:15
  • If you believe this endpoint is ok because requests only ever come from another site/server that you own, then don't just trust that, enforce it by making the request require authentication and using application passwords. Then check the values anyway because that server might have been compromised or someone might have intercepted/stolen the credentials or figured out how to bypass them
    – Tom J Nowell
    Mar 8 at 16:16
  • other than registration, this plugin may be helpful for login/logout github.com/humanmade/rest-sessions
    – Tom J Nowell
    Mar 8 at 16:41

1 Answer 1

0

Q1. How can we do this login event? Can we login via API or do we need something different? I'm asking because I've seen ways to log in with a cookie.

The WP REST API provides no session management functionality. There is no way to login, register, or logout via the REST API.

If it did, the registration endpoint in your question would be unnecessary.

Plugins might exist that provide session management, but doing this will require 100% custom code.

If it helps, this is the automatic API discovery process for the REST API that reveals the authentication methods it exposes:

https://developer.wordpress.org/rest-api/using-the-rest-api/discovery/#authentication-discovery

You may find with 3rd party authentication plugins that the ability to login via the API and create new authentication sessions purely via the API might be possible.

Q2. When it gets Ok result from API, it will return to WordPress site and log in. How can we make this turn?

You would need to create an entirely new endpoint to do this. Software such as Softaculous has an advantage the REST API does not because it can reach behind the scenes and do things directly to the database, run PHP scripts directly with priviledged access, or WP CLI commands such as wp user create etc and do things that can't normally be done.

A common method on enterprise hosting is to do this via a WP CLI command using internal mechanisms that aren't reachable via a browser or the open web, such as queued tasks or internal proprietary cron jobs. Others use custom REST API endpoints that create temporary users and then set up credentials and custom filters to bypass what the site normally does ( you would not want to do this as it has major security implications and is not scalable, these systems are built with a lone hosting support/maintenance agent in mind, not for regular use ).

These usually create temporary back doors that self-close, with mechanisms that rely on temporary tokens etc


Note that if we ignore all of this, the code in the question is insecure:

  • there is no rate limiting
  • it does not check if a user already exists
    • but it does return the error object, allowing an attacker to fire of repeated requests for usernames to see which ones generate user already exists errors
    • this also works for emails!!
  • although emails are sanitised, there is nothing checking that they are emails, and the endpoint will happily accept "I'm not an email" and pass it to $email
  • the endpoint bypasses the validation/verification step to confirm the user does indeed own that email. Anybody can sign up with anybody's email, I could sign up with your email! And there's nothing anybody could do about it. This has major legal and regulatory consequences, you should consult a lawyer with expertise in this area before continuing.
  • There are no protections for password strength and integrity in the API, this endpoint bypasses those entirely. . would be a valid password.
    • it may even be possible to use a blank password which would make it impossible for the user to login

I suspect you've used this answer on Stack Overflow to create the endpoint, which has its own issues, but then removed half of the protections it uses such as username_exits etc:

https://stackoverflow.com/a/50105811/57482

10
  • Yes. I got the code for becoming a member from the link you specified. The user has to make a payment when registering on our site. E-mail addresses are checked on our site. We have the necessary precautions on our side. After you become a member of us, we plan to add it to the wordpress site as a member with the e-mail address used when signing up with us via the path in this code. We will not open a membership on the WordPress site.
    – sakarya
    Mar 8 at 15:17
  • While logging in, checks will be made on our site via the API we wrote. Is his membership still active, is there such a user, etc. In our system, we want to get the username and password information we created for the WordPress site and enable it to log in to the WordPress site.
    – sakarya
    Mar 8 at 15:17
  • Women could just as easily be potential members! But wether you have a system with manual checks or not, this endpoint is unauthenticated and exposed to the world, the point is I could bypass your entire system and make calls directly to yoursite.com/wp-json/wp/v2/register. Even if you are checking the users that get created I could still perform attacks such as resource exhaustion
    – Tom J Nowell
    Mar 8 at 16:21
  • curl -X POST -d 'username=test&email=test&password=test' http://example.com/wp-json/wp/v2/register will bypass your entire membership system and create a user named test from a command line without even visiting your site
    – Tom J Nowell
    Mar 8 at 16:21
  • and this copy pasted into a terminal would create 50000 users i=0; while [ $i -lt 50000 ]; do ((i++)); curl -X POST -d "username=test${i}&email=test${i}@example.com&password=test" http://example.com/wp-json/wp/v2/register; done
    – Tom J Nowell
    Mar 8 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.