Secure and controlled access to user files
import play.api.mvc._
import play.api.libs.json._
class UserController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
def getUserData(userId: String) = Action { implicit request: Request[AnyContent] =>
val user = User.find(userId)
user match {
case Some(u) => Ok(Json.toJson(u))
case None => NotFound
}
}
}
The
getUserData
function in the
UserController
class is vulnerable to Insecure Direct Object References (IDOR) vulnerability. This function takes a
userId
as a parameter, retrieves the user information from the database, and returns it as a JSON object.
The issue here is that there is no authorization check to verify if the user requesting the data is allowed to access it. This means that if an attacker knows or guesses the
userId
of another user, they can access or manipulate their data. This is because the
userId
is directly used to fetch the user data from the database without any additional access control checks.
The lack of proper access control checks can lead to unauthorized information disclosure, data tampering, and other security issues, making the system vulnerable to IDOR attacks.
This vulnerability can be exploited by an attacker by simply sending a GET request to the
getUserData
endpoint with the
userId
of the user whose data they want to access or manipulate.
import play.api.mvc._
import play.api.libs.json._
class UserController @Inject()(cc: ControllerComponents, authAction: AuthenticatedAction) extends AbstractController(cc) {
def getUserData(userId: String) = authAction { implicit request: Request[AnyContent] =>
val loggedInUser = request.user
if(loggedInUser.id == userId) {
val user = User.find(userId)
user match {
case Some(u) => Ok(Json.toJson(u))
case None => NotFound
}
} else {
Unauthorized
}
}
}
The updated code now includes an
authAction
which is an instance of
AuthenticatedAction
. This is a custom action builder that checks if a user is authenticated before the action is executed. If the user is not authenticated, it will return an Unauthorized result.
In the
getUserData
method, we first retrieve the logged-in user from the request. This user is set in the
AuthenticatedAction
after successful authentication.
Next, we check if the logged-in user's id matches the
userId
parameter. If it does, we proceed to find the user and return the user data. If it doesn't, we return an Unauthorized result. This ensures that users can only access their own data.
This approach effectively mitigates the insecure direct object reference vulnerability by implementing proper authentication and authorization checks. It ensures that only authenticated and authorized users can access the
getUserData
endpoint.