Protection against hidden field manipulation
import play.api.mvc._
object Application extends Controller {
def save = Action { implicit request =>
val form = request.body.asFormUrlEncoded
val hiddenField = form.get("hiddenField").headOption
hiddenField match {
case Some(value) => Ok("Hidden field value: " + value)
case None => BadRequest("Missing hidden field")
}
}
}
In the above code, we have a simple Play Framework controller named
Application
. This controller has a single action named
save
. This action is vulnerable to hidden fields manipulation.
The
save
action retrieves form data from the request and attempts to extract a value for a hidden field named
"hiddenField"
. If the field is found, the value of the field is returned in the response. If the field is not found, a
BadRequest
response is returned.
The vulnerability lies in the fact that the value of the
"hiddenField"
is trusted without any validation. An attacker can manipulate the value of the hidden field before the form is submitted. Since the application blindly trusts the value of the hidden field, this can lead to undesired behaviors.
For example, if the hidden field is used to store the ID of a database record, an attacker could change the ID before submitting the form, causing the action to operate on a different record than intended.
To mitigate this vulnerability, the application should not trust user input, even if it is from a hidden field. The application should validate all input and ensure it is in an expected format and within expected bounds. The application should also ensure that the user has the necessary permissions to perform the action they are attempting.
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
object Application extends Controller {
case class Data(hiddenField: Option[String])
val form = Form(
mapping(
"hiddenField" -> optional(text)
)(Data.apply)(Data.unapply)
)
def save = Action { implicit request =>
form.bindFromRequest.fold(
formWithErrors => BadRequest("Invalid request"),
data => data.hiddenField match {
case Some(value) => Ok("Hidden field value: " + value)
case None => BadRequest("Missing hidden field")
}
)
}
}
The original code was vulnerable to hidden fields manipulation. This vulnerability could allow an attacker to modify fields that are invisible to the regular user and cause undesired behaviors in the application.
The fixed code uses Play Framework's form handling to bind the request data to a case class. This provides a layer of abstraction between the raw request data and the application logic, which can help to prevent manipulation of hidden fields.
The
Form
object is defined with a mapping that specifies the expected structure of the request data. In this case, it expects an optional
hiddenField
parameter. The
Form
object is then used to bind the request data to an instance of the
Data
case class.
The
bindFromRequest
method is used to bind the request data to the form. If the binding is successful, the form data is passed to the success function, which checks the value of the
hiddenField
parameter and responds accordingly. If the binding fails (for example, if the request data does not match the expected structure), the failure function is called, which responds with a "Invalid request" error.
This approach provides several layers of protection against hidden fields manipulation:
- It validates the structure of the request data, ensuring that it matches the expected structure.
- It sanitizes the request data by binding it to a case class, which can help to prevent injection attacks.
- It provides a clear separation between the raw request data and the application logic, which can make it harder for an attacker to manipulate hidden fields.
In addition to these measures, it's also recommended to implement proper access controls and authorization mechanisms, use server-side session management, and regularly update and patch the Play framework and its dependencies.