Prevent users from viewing or editing profiles of other users

I need to enhance the security of my application by restricting users from accessing profiles of other users.

route.js

router.get('/currentUser/:username', userAuth, (req, res) => {
  User.findOne({
    username: req.params.username
  }).then(user => {
    if (user) {
      return res.status(200).json(user);
    } else {
      return res.status(404).json({
        message: 'User not found'
      });
    }
  });
});

and in my userAuth.js

const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    jwt.verify(token, 'app_secret_token');
    next();
  } catch (error) {
    res.status(401).json({
      message: 'Authentication failed!'
    });
  }
};

If I log in as user test, my URL will be http://localhost:4200/currentuser/test. However, if I change the URL to another user like test2, it still loads the test2 profile even though I am logged in as test.

How can I prevent unauthorized access like this?

Answer №1

It is essential to verify that the user who is logged in has permission to access their own data.

To ensure this, you can cross-check the user information stored in the token with the requested page. To achieve this, encode the user ID within the JWT token. This measure guarantees that the parameter hasn't been tampered with as jwt.verify will fail if any unauthorized modifications are detected in the JWT token without possessing the secret key.

Include the necessary data in the JWT token when you sign it:

jwt.sign({
  userId: 'username'
}, 'secret', { expiresIn: '1h' });

If you store the same data as the serializeUser\deserializeUser function result, it should function correctly (the use of 'username' is just a suggestion).

You can utilize the callback from jwt.verify to extract the decoded token and access the required data

const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    jwt.verify(token, 'app_secret_token', (err, decoded) => {
      if (err) { throw err; }

      const currentUsername = decoded.userId; // <-- make sure this aligns with the encoded data in the jwt token

      // If the user making the request differs from the user in the token,
      // reject the request due to authentication failure
      if (req.originalUrl.includes('/currentUser/') &&
          !req.originalUrl.includes(`/currentUser/${currentUsername}`)) {
        throw new Error('access to other user data denied');
       }

       next();
    });

  } catch (error) {
    res.status(401).json({
      message: 'Authentication failed!'
    });
  }
};

Although combining this into two separate middlewares might be a feasible approach :-)

PS - as @anand-undavia mentioned, it might be more secure to ascertain the user's request based on the JWT token itself rather than solely relying on the 'url'. This way, each user would have exclusive access to their designated data, thereby eliminating potential issues entirely.

In essence, the user's details can be obtained using the aforementioned method (extracting it from the token), or through a req.user attribute if there is middleware in place that automatically adds it.

Answer №2

Assuming that the user profile page ID is mydomain?passedId=userId, you can simply add profile-guard to verify who can access or activate this page. In the CanActivate function, check if the passed ID matches the current user ID. If they match, then allow access by returning true. Otherwise, redirect the user to the previous page.

canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
let passedId: string = next.queryParams.passedId;
  let user = this.authService.GetUser();
  if (user.id == passedId)
    return true;
  else {
    this.router.navigate(['/home']); // Redirect to unauthorized page
    return false;
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhance your website with multiple interactive elements by incorporating several flashes through ExpressJS

When using request.flash to send flash messages to users, I encountered an issue. It seems that request.flash does not allow me to send multiple flash messages to a view at once. This is the code I tried: request.flash('danger', 'some flas ...

Obtaining the client's IP address using socket.io 2.0.3: a comprehensive guide

Currently, I am facing a challenge using socket.io v2.0.3 in my node.js server as I am unable to retrieve the client's IP address. Although there are several suggestions and techniques on platforms like stackoverflow, most of them are outdated and no ...

Ways to achieve a consistent output in Buffer.from compared to fs.readFile?

Currently, I am in the process of developing a feature for my slackbot that involves sending a post request containing binary data from an image to a ticketing system known as ServiceNow. Initially, I faced some challenges with obtaining the correct output ...

The functionality of my Javascript code is restricted to a single element within a Python embedded for loop in Django2

My Python for loop is iterating through these HTML template cards, each accompanied by JavaScript. However, I'm encountering an issue where the JavaScript only seems to work on the first element (specifically, it's meant to retrieve the seeked po ...

Ways to access a JavaScript object beyond the function scope

Using the code below, I am able to retrieve JSON data when an element is clicked. This data is then used to create a table, fill the cells with images, and append the table to a specific div. function LoadImagesByCategory() { $.getJSON("/Service/GetJs ...

The ajax function is malfunctioning when called from an external JavaScript file

I am having an issue with a Registration page that only has UserName and Password fields. When I click on the Submit button, I want to be able to submit the new User Details using an ajax call with jQuery. I have tried defining an Insert function on butt ...

Pausing a running function in React

Exploring Visual Sorting Algorithms In the process of creating a visual sorting algorithms tool for educational purposes, I have developed a function called sortArray() that handles the animation of the sorting process on arrays. The functionality is evid ...

Incorporating string input values into a function

I am currently working on a function that retrieves the value of an input upon clicking a button. My goal is to then have another event that will incorporate that value into a function when the button is clicked. var getInput = function() { $('#inpu ...

*NgFor toggle visibility of specific item

Here is a snippet of HTML code that I'm working with: <!-- Toggle show hide --> <ng-container *ngFor="let plateValue of plateValues; let i=index"> <button (click)="toggle(plateValue)">{{i}}. {{ btnText }}</button> ...

Can anyone recommend any offline editors for HTML, CSS, and JavaScript similar to JSFiddle, jsbin, or codepen?

Is there an alternative to JSFiddle.net that allows users to experiment with Javascript, HTML, and CSS offline in a similar way? ...

Exploring the differences between detecting the XMLHttpRequest object in JavaScript and using the try

When it comes to determining browser support for AJAX, I typically rely on object detection like this: if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else if (window.ActiveXObject) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } ...

Sending an XMLHttpRequest in PHP causes a blank array to be returned

> xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var jsondata = xmlhttp.responseText; console.log(xmlhttp.responseText); document.getElementById("jsondata").value = js ...

Transferring image asset URL to android using node.js API

I am trying to figure out how to send an image URL from a Node.js Express server to an Android device. The images are stored in /public/images, and I plan to use the link to display the image using the Glide library on Android. My issue is that I am unsure ...

While attempting to troubleshoot a program with mocha using the --debug-brk flag, it turns out that the debugging process actually

After setting up an open source project, I found that the mocha tests are running successfully. However, I am facing a challenge when trying to debug the functions being called by these tests. Every time I attempt to debug using 'mocha --debug-brk&apo ...

Encountering issues with Monaco Editor's autocomplete functionality in React

I'm facing an issue with implementing autocomplete in the Monaco Editor using a file called tf.d.ts that contains all the definitions in TypeScript. Despite several attempts, the autocomplete feature is not working as expected. import React, { useRef, ...

Utilizing a Static Image Path Prop in React JS: A Step-by-Step Guide

My Main Component import React from "react"; import TopModal from "./components/topModal"; // Passing productImage to the Child Component import productImage from "../../../../../../assets/images/juices.jpg"; import { makeS ...

What is preventing Protractor from detecting Angular on a site that has been automatically initialized with Angular?

Whenever I try to utilize browser.get() in my code, I encounter the following error: Error: Angular could not be found on the page http://localhost:5000/#/login debug=timing&saveLogs=true&displayAll=true : angular never provided resumeBootstrap A ...

Finding the perfect spot to CAPTURE an ERROR triggered during an EVAL operation

This snippet of code allows you to run JavaScript code while using a try/catch block to catch any errors that may occur. try { var result = eval(script); } catch (e) { // handle the error appropriately } However, if the variab ...

CSS - starting fresh with animations

I am facing an issue with a CSS animation that I created. Everything seems to be working correctly, but I need to complete it by setting the input type to reset the animation. Below is the CSS code snippet that should reset the animation: $('button& ...

Leveraging numerous identifiers in jQuery

I created a small jQuery script to check if the input box value is greater than 5, but I have two tags with IDs and only one of them seems to be working. <div id="register"> <form id="register"> <input id="first" type="text" /> <a ...