Skip to main content

Lack of protection against deletion

Need

Implementation of safeguards to prevent accidental deletion of critical objects

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework

Description

Non compliant code

import play.api.mvc._

object HomeController extends Controller {
def delete(id: String) = Action { implicit request =>
val item = Item.find(id)
item match {
case Some(i) => {
i.delete()
Ok("Item deleted.")
}
case None => NotFound("Item not found.")
}
}
}

The above Scala code snippet is an example of a Play framework controller that handles deletion of an item. The delete method takes an id as a parameter and attempts to find an item with that id. If the item is found, it is deleted and a success message is returned. If the item is not found, a NotFound error is returned.

This code is vulnerable because there is no protection against accidental deletion of critical items. Any user who knows the id of an item can delete it, whether they are supposed to have that ability or not. Additionally, there is no confirmation step before deletion, so a user could accidentally delete an item without any way to recover it. This could lead to loss of critical data.

Steps

  • Implement authentication and authorization mechanisms to ensure that only authorized users can delete critical objects.
  • Use a confirmation dialog or a two-step deletion process to prevent accidental deletions.
  • Implement access control lists (ACLs) or role-based access control (RBAC) to restrict deletion permissions to specific users or roles.
  • Implement a soft delete mechanism instead of a hard delete, where deleted objects are marked as deleted but not physically removed from the system.
  • Implement audit logging to track deletion actions and identify any suspicious or unauthorized deletions.

Compliant code

import play.api.mvc._
import play.api.libs.json._

case class DeleteRequest(confirm: Boolean)

object DeleteRequest {
implicit val format = Json.format[DeleteRequest]
}

object HomeController extends Controller {
def delete(id: String) = Action(parse.json) { implicit request =>
val item = Item.find(id)
item match {
case Some(i) => {
val deleteRequest = request.body.validate[DeleteRequest]
deleteRequest.fold(
errors => {
BadRequest(Json.obj("status" ->"KO", "message" -> JsError.toJson(errors)))
},
deleteRequest => {
if (deleteRequest.confirm) {
i.delete()
Ok("Item deleted.")
} else {
BadRequest("Confirmation required to delete item.")
}
}
)
}
case None => NotFound("Item not found.")
}
}
}

The updated code now requires a confirmation flag to be sent in the request body when deleting an item. This is done by creating a DeleteRequest case class with a confirm Boolean field. The confirm field is then checked before the item is deleted. If confirm is true, the item is deleted. If confirm is false or not provided, a "Confirmation required to delete item." message is returned.

This change helps to prevent accidental deletions by requiring an explicit confirmation for each delete action. However, it does not implement authentication, authorization, access control, soft delete, or audit logging. These additional measures should be implemented as appropriate for your application to further protect against accidental or unauthorized deletions.

References