I have a security question regarding using camunda through REST-API.
I would like to have variables validation when using any endpoint that can change task/process instance variables.
For example, when I use the endpoint to complete a task, I would like to validate the variables sent by the complete request.
I also need to make sure that on the complete task request, only some fields are taken into account.
Imagine I have a “Select assignee” task:
1 - I want to make sure that on the complete request for this specific task, only the assignee variable will be changed/added to the process instance.
2 - I want to make sure that the assignee is in the following collection: [‘person1’, ‘person2’].
@psilva you can use listeners on the tasks to preform the validation before the task is execute (Execution Listener: Start). How are you using the engine? Java delegates, scripting, embedded, shared?
Hello @StephenOTT, I am using Angular only with ajax requests to the engine-rest that is provided by camunda.
I thought of Listeners to validate the data and that might work for what I need, thanks!
Still, it doesn’t solve the problem I also reffered.
In the complete request body, I can send the variables I want to change in the process, even if in that step it shouldn’t be possible to change it.
For example, if I have a variable “risk” in the process, anyone with access to the task can make a request that changes that value, even though it is a calculated value. Is there anyway to prevent this behaviour?
I thought that it would be possible to describe which variables would be changeable in a specific task.
EDIT: By complete request, I mean the rest api endpoint request that allows the completion of a task (post-complete).
Yes thats a problem i have encountered. See the link above with the Generic Form validator code. In that code you could write a small script that checks the submission for which data is allowed to be submitted. I am just about to release a update to the code that will enable multiple script files to be used. So should be easy for you to write a small validator script per Submission Form, and use shared scripts across all setups
Add execution listeners that throw a error (thus causing a rollback) when some data changed, but it it will likely be problematic to capture the changes
Add a form validator such as the links above (except the links above are for a “generic” solution that lets you run your validator through scripts
Add some sort of global submission listener that tracks the attempted changes.
So with the first option it will be hard to see which variables changed, is that right?
With the second option I tried form fields, but that doesn’t prevent variables that are not there to be changed.
The third option seems promising, but I lack the experience in camunda to try that yet.
Maybe the first option is the right one for my specific case.
I am trying to understand how camunda developers handle this security issue.
In my experience, it seems like it will be problematic to detect the changes (for #1)
Can you explain your issue with the second option? You should be able to define all logic. What is your specific logic story/scenario. Will provide you with a example. You dont need to use the generic script. You can just add your own validator as per: https://docs.camunda.org/manual/7.8/user-guide/task-forms/#form-field-validation. The Generic JS version is so you can upload your validations along side your HTML angular forms as part of a single package during the deployment.
The third option i see as having the same issue as the first option.
Yes, with form fields I can specify the validation for all fields, for example, if I call POST /task/{id}/complete with the following data:
{
…“variables”: {
… …“decision”: {“type”: “String”, “value”: “accept”},
… …“risk”: {“type”: “String”, “value”: “low”}
…}
}
I can validate that decision is a value required and can make other validations. But I cannot prevent risk to be changed (and that’s a calculated value).
If an user has experience in rest, he can easily make this request and change variables that he wasn’t supposed to.
What I want in this case is to prevent any variables beside decision to be added or changed in the customer decision task.
But I cannot prevent risk to be changed (and that’s a calculated value).
Yes you can prevent that change:
When the submission occurs, in the script you define that “risk” cannot be part of the submission. If the field is found you throw an error; or you just completely ignore the risk variable.
With the Form validator usage you are actually using: https://docs.camunda.org/manual/7.8/reference/rest/task/post-submit-form/ and not using the /complete. The task is only “completed” is the form validator returns “true” because the submission data was “Valid” / aka: the risk field was not attempted to be modified.
@psilva here is a working example of “Banned Fields”
load('classpath:validationResult.js')
load('classpath:validate.min.js')
var JSONObject = Java.type('org.camunda.bpm.engine.impl.util.json.JSONObject')
var jsonSubmission = JSON.parse(new JSONObject(submissionValues).toString())
// Validate.js Constraints
function getConstraints() {
var constraints = {
age: {
presence: true,
numericality: {
onlyInteger: true,
greaterThan: 18,
lessThanOrEqualTo: 125,
}
}
};
return constraints
}
// List of fields that are not allowed to be changed
function bannedFields(){
// could also be loaded from another location (like a yaml or json file)
return [
"risk",
"owner",
"master_field",
"current_state",
"flagged",
"priority"
]
}
// Check if the submission has any of the banned fields
function checkForBannedFields(submission, bannedFields) {
// Loop through list of banned fields (nashorn loop)
for each (var field in bannedFields){
var hasBannedField = validate.contains(submission, field)
// if a banned field was found then return true:
if (hasBannedField == true) {
return true
}
}
// If no banned fields were found:
return false
}
// if there is a banned field:
if (checkForBannedFields(jsonSubmission, bannedFields())){
validationResult(false, {
"detail": "VALIDATE.JS",
"message": 'Submission contains a banned field: ' + JSON.stringify(bannedFields())
}
)
// If no banned fields were found:
} else {
// If no banned fields then continue:
// Run Validations against Validate.js
var validation = validate(jsonSubmission, getConstraints())
if (validation === undefined) {
validationResult(true)
} else {
validationResult(false, {
"detail": "VALIDATE.JS",
"message": JSON.stringify(validation)
}
)
}
}
when the user task is submitted you will get a response such as:
{
"type": "RestException",
"message": "Cannot submit task form df4fe4ec-4336-11e8-b611-0242ac130002: Invalid value submitted for form field 'banned-fields': validation of validator(io.digitalstate.camunda.JsFormValidation) failed."
}
and the console will output:
Caused by: org.camunda.bpm.engine.impl.form.validator.FormFieldValidationException: Submission contains a banned field: ["risk","owner","master_field","current_state","flagged","priority"]